]> arthur.barton.de Git - netatalk.git/blob - sys/solaris/dlpi.c
Remove bdb env on exit
[netatalk.git] / sys / solaris / dlpi.c
1 /* $Id: dlpi.c,v 1.2 2002-01-17 06:13:02 srittau Exp $
2  */
3
4 #include <config.h>
5
6 #include <sys/types.h>
7 #include <sys/kmem.h>
8 #include <sys/stream.h>
9 #include <sys/conf.h>
10 #include <sys/modctl.h>
11 #include <sys/cmn_err.h>
12 #include <sys/ddi.h>
13 #include <sys/socket.h>
14 #include <sys/sockio.h>
15 #include <sys/dlpi.h>
16 #include <sys/ethernet.h>
17 #include <sys/byteorder.h>
18 #include <sys/sunddi.h>
19 #include <net/if.h>
20 #include <errno.h>
21
22 #include <netatalk/phase2.h>
23 #include <netatalk/at.h>
24
25 #include "ioc.h"
26 #include "if.h"
27
28 u_char  at_multicastaddr[ ETHERADDRL ] = {
29     0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
30 };
31 u_char  at_org_code[ 3 ] = {
32     0x08, 0x00, 0x07,
33 };
34 u_char  aarp_org_code[ 3 ] = {
35     0x00, 0x00, 0x00,
36 };
37
38     static int
39 dlpi_open( queue_t *q, dev_t *dev, int oflag, int sflag, cred_t *cred )
40 {
41     struct atif_data    *aid;
42     int                 err = 0;
43
44     if (( err = drv_priv( cred )) != 0 ) {
45         return( err );
46     }
47     if (( aid = if_alloc( q )) == NULL ) {
48         return( ENOMEM );
49     }
50     q->q_ptr = (void *)aid;
51
52     qprocson( q );
53     return( err );
54 }
55
56     static int
57 dlpi_close( queue_t *q, int oflag, cred_t *cred )
58 {
59     struct atif_data    *aid = (struct atif_data *)q->q_ptr;
60
61     qprocsoff( q );
62     if_free( aid );
63     return( 0 );
64 }
65
66     static int
67 dl_bind_req( queue_t *q, ulong sap )
68 {
69     union DL_primitives *dl;
70     mblk_t              *m;
71
72     if (( m = allocb( DL_BIND_REQ_SIZE, BPRI_HI )) == NULL ) {
73         return( ENOMEM );
74     }
75     m->b_wptr = m->b_rptr + DL_BIND_REQ_SIZE;
76     m->b_datap->db_type = M_PROTO;
77
78     dl = (union DL_primitives *)m->b_rptr;
79     dl->dl_primitive = DL_BIND_REQ;
80     dl->bind_req.dl_sap = sap;
81     dl->bind_req.dl_max_conind = 0;
82     dl->bind_req.dl_service_mode = DL_CLDLS;
83     dl->bind_req.dl_conn_mgmt = 0;
84     dl->bind_req.dl_xidtest_flg = 0;    /* XXX */
85     putnext( q, m );
86     return( 0 );
87 }
88
89     static int
90 dl_attach_req( queue_t *q, ulong ppa )
91 {
92     union DL_primitives *dl;
93     mblk_t              *m;
94
95     if (( m = allocb( DL_ATTACH_REQ_SIZE, BPRI_HI )) == NULL ) {
96         return( ENOMEM );
97     }
98     m->b_wptr = m->b_rptr + DL_ATTACH_REQ_SIZE;
99     m->b_datap->db_type = M_PROTO;
100
101     dl = (union DL_primitives *)m->b_rptr;
102     dl->dl_primitive = DL_ATTACH_REQ;
103     dl->attach_req.dl_ppa = ppa;
104     putnext( q, m );
105     return( 0 );
106 }
107
108     int
109 dl_enabmulti_req( queue_t *q, caddr_t addr )
110 {
111     union DL_primitives *dl;
112     mblk_t              *m;
113
114     if (( m = allocb( DL_ENABMULTI_REQ_SIZE + ETHERADDRL, BPRI_HI )) == NULL ) {
115         return( ENOMEM );
116     }
117     m->b_wptr = m->b_rptr + DL_ENABMULTI_REQ_SIZE;
118     m->b_datap->db_type = M_PROTO;
119
120     dl = (union DL_primitives *)m->b_rptr;
121     dl->dl_primitive = DL_ENABMULTI_REQ;
122     dl->enabmulti_req.dl_addr_length = ETHERADDRL;
123     dl->enabmulti_req.dl_addr_offset = m->b_wptr - m->b_rptr;
124     bcopy( addr, m->b_wptr, ETHERADDRL );
125     m->b_wptr += ETHERADDRL;
126     putnext( q, m );
127     return( 0 );
128 }
129
130     int
131 dl_unitdata_req( queue_t *q, mblk_t *m0, ushort type, caddr_t addr )
132 {
133     union DL_primitives *dl;
134     struct llc          *llc;
135     mblk_t              *m1, *m;
136     ushort              len;
137
138     /* len = msgdsize( m0 ) + sizeof( struct llc ); */
139
140     if (( m1 = allocb( sizeof( struct llc ), BPRI_HI )) == NULL ) {
141         cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 1\n" );
142         return( ENOMEM );
143     }
144     m1->b_wptr = m1->b_rptr + sizeof( struct llc );
145     m1->b_datap->db_type = M_DATA;
146     llc = (struct llc *)m1->b_rptr;
147
148     llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
149     llc->llc_control = LLC_UI;
150     if ( type == ETHERTYPE_AARP ) {
151         bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
152     } else if ( type == ETHERTYPE_AT ) {
153         bcopy( at_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
154     } else {
155         cmn_err( CE_NOTE, "dl_unitdate_req type %X\n", type );
156         return( EINVAL );
157     }
158     llc->llc_ether_type = htons( type );
159     linkb( m1, m0 );
160
161     if (( m = allocb( DL_UNITDATA_REQ_SIZE + ETHERADDRL + sizeof( ushort ),
162                       BPRI_HI )) == NULL ) {
163         cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 2\n" );
164         return( ENOMEM );
165     }
166     m->b_wptr = m->b_rptr + DL_UNITDATA_REQ_SIZE;
167     m->b_datap->db_type = M_PROTO;
168     linkb( m, m1 );
169
170     dl = (union DL_primitives *)m->b_rptr;
171     dl->dl_primitive = DL_UNITDATA_REQ;
172     dl->unitdata_req.dl_dest_addr_length = ETHERADDRL + sizeof ( ushort );
173     dl->unitdata_req.dl_dest_addr_offset = m->b_wptr - m->b_rptr;
174
175     bcopy(addr, m->b_wptr, ETHERADDRL );
176     m->b_wptr += ETHERADDRL;
177     len = 0;
178     bcopy( &len, m->b_wptr, sizeof( ushort ));
179     m->b_wptr += sizeof( ushort );
180     putnext( q, m );
181     return( 0 );
182 }
183
184     static int
185 dlpi_rput( queue_t *q, mblk_t *m )
186 {
187     struct atif_data    *aid = (struct atif_data *)q->q_ptr;
188     union DL_primitives *dl;
189     mblk_t              *m0;
190     struct llc          *llc;
191
192     switch ( m->b_datap->db_type ) {
193     case M_IOCNAK :
194         putnext( q, m );
195         return( 0 );
196
197     case M_PCPROTO :
198     case M_PROTO :
199         if ( m->b_wptr - m->b_rptr < sizeof( dl->dl_primitive )) {
200             break;
201         }
202         dl = (union DL_primitives *)m->b_rptr;
203         switch ( dl->dl_primitive ) {
204         case DL_UNITDATA_IND :
205             if ( m->b_wptr - m->b_rptr < sizeof( DL_UNITDATA_IND_SIZE )) {
206                 break;
207             }
208             if (( m0 = unlinkb( m )) == NULL ) {
209                 break;
210             }
211             if ( m0->b_wptr - m0->b_rptr < sizeof( struct llc )) {
212                 freemsg( m0 );
213                 break;
214             }
215             llc = (struct llc *)m0->b_rptr;
216             if ( llc->llc_dsap != LLC_SNAP_LSAP ||
217                     llc->llc_ssap != LLC_SNAP_LSAP ||
218                     llc->llc_control != LLC_UI ) {
219                 freemsg( m0 );
220                 break;
221             }
222
223             if ( bcmp( llc->llc_org_code, at_org_code,
224                     sizeof( at_org_code )) == 0 &&
225                     ntohs( llc->llc_ether_type ) == ETHERTYPE_AT ) {
226                 adjmsg( m0, sizeof( struct llc ));
227                 ddp_rput( aid, m0 );
228             } else if ( bcmp( llc->llc_org_code, aarp_org_code,
229                     sizeof( aarp_org_code )) == 0 &&
230                     ntohs( llc->llc_ether_type ) == ETHERTYPE_AARP ) {
231                 adjmsg( m0, sizeof( struct llc ));
232                 aarp_rput( q, m0 );
233             } else {
234                 freemsg( m0 );
235             }
236             break;
237
238         case DL_OK_ACK :
239             if ( m->b_wptr - m->b_rptr < sizeof( DL_OK_ACK_SIZE )) {
240                 break;
241             }
242             switch ( dl->ok_ack.dl_correct_primitive ) {
243             case DL_ATTACH_REQ :
244                 if ( aid->aid_state != DL_ATTACH_PENDING ) {
245                     cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach state %d\n",
246                             aid->aid_state );
247                     break;
248                 }
249                 if ( aid->aid_c.c_type != IF_UNITSEL ) {
250                     cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach context %x\n",
251                             aid->aid_c.c_type );
252                     break;
253                 }
254
255                 if ( WR(q)->q_next == NULL || WR(q)->q_next->q_qinfo == NULL ||
256                         WR(q)->q_next->q_qinfo->qi_minfo == NULL ||
257                         WR(q)->q_next->q_qinfo->qi_minfo->mi_idname == NULL ) {
258                     cmn_err( CE_NOTE, "dlpi_rput can't get interface name\n" );
259                     break;
260                 }
261
262                 if_name( aid, WR(q)->q_next->q_qinfo->qi_minfo->mi_idname,
263                         aid->aid_c.c_u.u_unit.uu_ppa );
264
265                 aid->aid_state = DL_BIND_PENDING;
266
267 #ifdef i386
268                 /*
269                  * As of Solaris 7 (nice name), the i386 arch needs to be
270                  * bound as 0 to receive 802 frames.  However, in the same
271                  * OS, Sparcs must be bound as ETHERMTU (or at least not 0)
272                  * to receive the same frames.  A bug?  In the Solaris 7
273                  * (nice name) kernel?
274                  */
275                 dl_bind_req( WR( q ), 0 );
276 #else /* i386 */
277                 dl_bind_req( WR( q ), ETHERMTU );
278 #endif /* i386 */
279                 break;
280
281             case DL_ENABMULTI_REQ :
282                 if ( aid->aid_c.c_type != SIOCADDMULTI ) {
283                     cmn_err( CE_NOTE,
284                             "dlpi_rput DL_OK_ACK enabmulti context %x\n",
285                             aid->aid_c.c_type );
286                     break;
287                 }
288
289                 ioc_ok_ack( aid->aid_c.c_u.u_multi.um_q,
290                         aid->aid_c.c_u.u_multi.um_m, 0 );
291                 aid->aid_c.c_type = 0;
292                 aid->aid_c.c_u.u_multi.um_q = NULL;
293                 aid->aid_c.c_u.u_multi.um_m = 0;
294                 break;
295
296             default :
297                 cmn_err( CE_CONT, "!dlpi_rput DL_OK_ACK unhandled %d\n",
298                         dl->ok_ack.dl_correct_primitive );
299                 break;
300             }
301             break;
302
303         case DL_BIND_ACK :
304             if ( m->b_wptr - m->b_rptr < sizeof( DL_BIND_ACK_SIZE )) {
305                 break;
306             }
307             if ( aid->aid_state != DL_BIND_PENDING ) {
308                 break;
309             }
310             if ( aid->aid_c.c_type != IF_UNITSEL ) {
311                 break;
312             }
313             bcopy( m->b_rptr + dl->bind_ack.dl_addr_offset, aid->aid_hwaddr, 
314                     dl->bind_ack.dl_addr_length );
315             aid->aid_state = DL_IDLE;
316             ioc_ok_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, 0 );
317             aid->aid_c.c_type = 0;
318             aid->aid_c.c_u.u_unit.uu_m = NULL;
319             aid->aid_c.c_u.u_unit.uu_ppa = 0;
320             break;
321
322         case DL_ERROR_ACK :
323             if ( m->b_wptr - m->b_rptr < sizeof( DL_ERROR_ACK_SIZE )) {
324                 break;
325             }
326
327             switch ( aid->aid_c.c_type ) {
328             case IF_UNITSEL :
329                 if ( dl->error_ack.dl_errno == DL_SYSERR ) {
330                     ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m,
331                             dl->error_ack.dl_unix_errno );
332                 } else {
333                     cmn_err( CE_CONT, "dlpi_rput DL_ERROR_ACK 0x%x\n",
334                             dl->error_ack.dl_errno );
335                     ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, EINVAL );
336                 }
337                 aid->aid_c.c_type = 0;
338                 aid->aid_c.c_u.u_unit.uu_m = NULL;
339                 aid->aid_c.c_u.u_unit.uu_ppa = 0;
340                 break;
341
342             default :
343                 cmn_err( CE_NOTE, "dlpi_rput DL_ERROR_ACK unhandled %d %d %d\n",
344                         dl->error_ack.dl_error_primitive,
345                         dl->error_ack.dl_errno, dl->error_ack.dl_unix_errno );
346                 break;
347             }
348             break;
349
350         default :
351             cmn_err( CE_NOTE, "dlpi_rput M_PCPROTO 0x%x\n", dl->dl_primitive );
352             break;
353         }
354         break;
355
356     default :
357         cmn_err( CE_NOTE, "dlpi_rput 0x%X\n", m->b_datap->db_type );
358         break;
359     }
360
361     freemsg( m );
362     return( 0 );
363 }
364
365     static int
366 dlpi_wput( queue_t *q, mblk_t *m )
367 {
368     struct atif_data            *aid = (struct atif_data *)RD(q)->q_ptr;
369     struct iocblk               *ioc;
370     int                         rc;
371
372     switch ( m->b_datap->db_type ) {
373     case M_IOCTL :
374         if ( m->b_wptr - m->b_rptr < sizeof( struct iocblk )) {
375             freemsg( m );
376             break;
377         }
378         ioc = (struct iocblk *)m->b_rptr;
379         switch ( ioc->ioc_cmd ) {
380         case IF_UNITSEL :
381             if ( ioc->ioc_count != TRANSPARENT ) {
382                 cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL non-TRANSPARENT\n" );
383                 ioc_error_ack( q, m, EINVAL );
384                 break;
385             }
386             if ( m->b_cont == NULL ) {
387                 cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL no arg\n" );
388                 ioc_error_ack( q, m, EINVAL );
389                 break;
390             }
391             if ( aid->aid_state != DL_UNATTACHED ) {
392                 cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL already attached\n" );
393                 ioc_error_ack( q, m, EINVAL );
394                 break;
395             }
396             if ( aid->aid_c.c_type != 0 ) {
397                 cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL context %x\n",
398                         aid->aid_c.c_type );
399                 ioc_error_ack( q, m, EINVAL );
400                 break;
401             }
402
403             aid->aid_state = DL_ATTACH_PENDING;
404             aid->aid_c.c_type = IF_UNITSEL;
405             aid->aid_c.c_u.u_unit.uu_m = m;
406             aid->aid_c.c_u.u_unit.uu_ppa = *(ulong *)m->b_cont->b_rptr;
407             if (( rc = dl_attach_req( q, aid->aid_c.c_u.u_unit.uu_ppa )) < 0 ) {
408                 ioc_error_ack( q, m, rc );
409                 break;
410             }
411             break;
412
413         default :
414             cmn_err( CE_NOTE, "dlpi_wput M_IOCTL 0x%X\n", ioc->ioc_cmd );
415             putnext( q, m );
416             break;
417         }
418         break;
419
420     default :
421         cmn_err( CE_NOTE, "dlpi_wput 0x%X\n", m->b_datap->db_type );
422         freemsg( m );
423         break;
424     }
425
426     return( 0 );
427 }
428
429 static struct module_info       dlpi_info = {
430     0,
431     "ddp",
432     0,
433     1500,
434     3000,
435     64
436 };
437
438 static struct qinit             dlpi_rinit = {
439     dlpi_rput,          /* qi_putp */
440     NULL,               /* qi_srvp */
441     dlpi_open,          /* qi_qopen */
442     dlpi_close,         /* qi_qclose */
443     NULL,
444     &dlpi_info,         /* qi_minfo */
445     NULL,
446 };
447
448 static struct qinit             dlpi_winit = {
449     dlpi_wput,          /* qi_putp */
450     NULL,               /* qi_srvp */
451     NULL,               /* qi_qopen */
452     NULL,               /* qi_qclose */
453     NULL,
454     &dlpi_info,         /* qi_minfo */
455     NULL,
456 };
457
458 static struct streamtab         dlpi_stream = {
459     &dlpi_rinit,
460     &dlpi_winit,
461     NULL,
462     NULL
463 };
464
465 static struct fmodsw            dlpi_fmodsw = {
466     "ddp",
467     &dlpi_stream,
468     D_NEW | D_MP | D_MTPERMOD
469 };
470
471 /*
472  * DDP Streams module.  This module is pushed on DLPI drivers by atalkd.
473  */
474 struct modlstrmod               dlpi_lstrmod = {
475     &mod_strmodops,
476     "DDP Streams module",
477     &dlpi_fmodsw,
478 };