1 /* $Id: dlpi.c,v 1.2 2002-01-17 06:13:02 srittau Exp $
8 #include <sys/stream.h>
10 #include <sys/modctl.h>
11 #include <sys/cmn_err.h>
13 #include <sys/socket.h>
14 #include <sys/sockio.h>
16 #include <sys/ethernet.h>
17 #include <sys/byteorder.h>
18 #include <sys/sunddi.h>
22 #include <netatalk/phase2.h>
23 #include <netatalk/at.h>
28 u_char at_multicastaddr[ ETHERADDRL ] = {
29 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
31 u_char at_org_code[ 3 ] = {
34 u_char aarp_org_code[ 3 ] = {
39 dlpi_open( queue_t *q, dev_t *dev, int oflag, int sflag, cred_t *cred )
41 struct atif_data *aid;
44 if (( err = drv_priv( cred )) != 0 ) {
47 if (( aid = if_alloc( q )) == NULL ) {
50 q->q_ptr = (void *)aid;
57 dlpi_close( queue_t *q, int oflag, cred_t *cred )
59 struct atif_data *aid = (struct atif_data *)q->q_ptr;
67 dl_bind_req( queue_t *q, ulong sap )
69 union DL_primitives *dl;
72 if (( m = allocb( DL_BIND_REQ_SIZE, BPRI_HI )) == NULL ) {
75 m->b_wptr = m->b_rptr + DL_BIND_REQ_SIZE;
76 m->b_datap->db_type = M_PROTO;
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 */
90 dl_attach_req( queue_t *q, ulong ppa )
92 union DL_primitives *dl;
95 if (( m = allocb( DL_ATTACH_REQ_SIZE, BPRI_HI )) == NULL ) {
98 m->b_wptr = m->b_rptr + DL_ATTACH_REQ_SIZE;
99 m->b_datap->db_type = M_PROTO;
101 dl = (union DL_primitives *)m->b_rptr;
102 dl->dl_primitive = DL_ATTACH_REQ;
103 dl->attach_req.dl_ppa = ppa;
109 dl_enabmulti_req( queue_t *q, caddr_t addr )
111 union DL_primitives *dl;
114 if (( m = allocb( DL_ENABMULTI_REQ_SIZE + ETHERADDRL, BPRI_HI )) == NULL ) {
117 m->b_wptr = m->b_rptr + DL_ENABMULTI_REQ_SIZE;
118 m->b_datap->db_type = M_PROTO;
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;
131 dl_unitdata_req( queue_t *q, mblk_t *m0, ushort type, caddr_t addr )
133 union DL_primitives *dl;
138 /* len = msgdsize( m0 ) + sizeof( struct llc ); */
140 if (( m1 = allocb( sizeof( struct llc ), BPRI_HI )) == NULL ) {
141 cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 1\n" );
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;
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 ));
155 cmn_err( CE_NOTE, "dl_unitdate_req type %X\n", type );
158 llc->llc_ether_type = htons( type );
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" );
166 m->b_wptr = m->b_rptr + DL_UNITDATA_REQ_SIZE;
167 m->b_datap->db_type = M_PROTO;
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;
175 bcopy(addr, m->b_wptr, ETHERADDRL );
176 m->b_wptr += ETHERADDRL;
178 bcopy( &len, m->b_wptr, sizeof( ushort ));
179 m->b_wptr += sizeof( ushort );
185 dlpi_rput( queue_t *q, mblk_t *m )
187 struct atif_data *aid = (struct atif_data *)q->q_ptr;
188 union DL_primitives *dl;
192 switch ( m->b_datap->db_type ) {
199 if ( m->b_wptr - m->b_rptr < sizeof( dl->dl_primitive )) {
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 )) {
208 if (( m0 = unlinkb( m )) == NULL ) {
211 if ( m0->b_wptr - m0->b_rptr < sizeof( struct llc )) {
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 ) {
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 ));
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 ));
239 if ( m->b_wptr - m->b_rptr < sizeof( DL_OK_ACK_SIZE )) {
242 switch ( dl->ok_ack.dl_correct_primitive ) {
244 if ( aid->aid_state != DL_ATTACH_PENDING ) {
245 cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach state %d\n",
249 if ( aid->aid_c.c_type != IF_UNITSEL ) {
250 cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach context %x\n",
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" );
262 if_name( aid, WR(q)->q_next->q_qinfo->qi_minfo->mi_idname,
263 aid->aid_c.c_u.u_unit.uu_ppa );
265 aid->aid_state = DL_BIND_PENDING;
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?
275 dl_bind_req( WR( q ), 0 );
277 dl_bind_req( WR( q ), ETHERMTU );
281 case DL_ENABMULTI_REQ :
282 if ( aid->aid_c.c_type != SIOCADDMULTI ) {
284 "dlpi_rput DL_OK_ACK enabmulti context %x\n",
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;
297 cmn_err( CE_CONT, "!dlpi_rput DL_OK_ACK unhandled %d\n",
298 dl->ok_ack.dl_correct_primitive );
304 if ( m->b_wptr - m->b_rptr < sizeof( DL_BIND_ACK_SIZE )) {
307 if ( aid->aid_state != DL_BIND_PENDING ) {
310 if ( aid->aid_c.c_type != IF_UNITSEL ) {
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;
323 if ( m->b_wptr - m->b_rptr < sizeof( DL_ERROR_ACK_SIZE )) {
327 switch ( aid->aid_c.c_type ) {
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 );
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 );
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;
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 );
351 cmn_err( CE_NOTE, "dlpi_rput M_PCPROTO 0x%x\n", dl->dl_primitive );
357 cmn_err( CE_NOTE, "dlpi_rput 0x%X\n", m->b_datap->db_type );
366 dlpi_wput( queue_t *q, mblk_t *m )
368 struct atif_data *aid = (struct atif_data *)RD(q)->q_ptr;
372 switch ( m->b_datap->db_type ) {
374 if ( m->b_wptr - m->b_rptr < sizeof( struct iocblk )) {
378 ioc = (struct iocblk *)m->b_rptr;
379 switch ( ioc->ioc_cmd ) {
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 );
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 );
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 );
396 if ( aid->aid_c.c_type != 0 ) {
397 cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL context %x\n",
399 ioc_error_ack( q, m, EINVAL );
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 );
414 cmn_err( CE_NOTE, "dlpi_wput M_IOCTL 0x%X\n", ioc->ioc_cmd );
421 cmn_err( CE_NOTE, "dlpi_wput 0x%X\n", m->b_datap->db_type );
429 static struct module_info dlpi_info = {
438 static struct qinit dlpi_rinit = {
439 dlpi_rput, /* qi_putp */
441 dlpi_open, /* qi_qopen */
442 dlpi_close, /* qi_qclose */
444 &dlpi_info, /* qi_minfo */
448 static struct qinit dlpi_winit = {
449 dlpi_wput, /* qi_putp */
452 NULL, /* qi_qclose */
454 &dlpi_info, /* qi_minfo */
458 static struct streamtab dlpi_stream = {
465 static struct fmodsw dlpi_fmodsw = {
468 D_NEW | D_MP | D_MTPERMOD
472 * DDP Streams module. This module is pushed on DLPI drivers by atalkd.
474 struct modlstrmod dlpi_lstrmod = {
476 "DDP Streams module",