4 #include <sys/stream.h>
5 #include <sys/devops.h>
6 #include <sys/modctl.h>
9 #include <sys/sockio.h>
10 #include <sys/socket.h>
11 #include <sys/tihdr.h>
12 #include <sys/tiuser.h>
13 #include <sys/timod.h>
14 #include <sys/sunddi.h>
15 #include <sys/ethernet.h>
17 #include <net/route.h>
20 #include <netatalk/endian.h>
21 #include <netatalk/at.h>
22 #include <netatalk/ddp.h>
30 tpi_getinfo( dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp )
33 return( DDI_FAILURE );
37 tpi_identify( dev_info_t *dip )
39 if ( strcmp( ddi_get_name( dip ), "ddp" ) == 0 ) {
40 return( DDI_IDENTIFIED );
42 return( DDI_NOT_IDENTIFIED );
47 tpi_attach( dev_info_t *dip, ddi_attach_cmd_t cmd )
51 if ( cmd != DDI_ATTACH ) {
52 return( DDI_FAILURE );
55 if (( rc = ddi_create_minor_node( dip, "ddp", S_IFCHR, 0, DDI_PSEUDO,
56 CLONE_DEV )) != DDI_SUCCESS ) {
63 tpi_detach( dev_info_t *dip, ddi_detach_cmd_t cmd )
65 if ( cmd != DDI_DETACH ) {
66 return( DDI_FAILURE );
69 ddi_remove_minor_node( dip, "ddp" );
71 return( DDI_SUCCESS );
75 tpi_open( queue_t *q, dev_t *dev, int oflag, int sflag, cred_t *cred )
77 static minor_t minor = 1;
79 if ( sflag != CLONEOPEN ) {
82 if (( q->q_ptr = (void *)sock_alloc( q )) == NULL ) {
86 *dev = makedevice( getmajor( *dev ), minor++ );
92 tpi_close( queue_t *q, int oflag, cred_t *cred )
94 struct sock_data *sd = (struct sock_data *)q->q_ptr;
102 tpi_rput( queue_t *q, mblk_t *m )
104 cmn_err( CE_NOTE, "tpi_rput dp_type = 0x%X\n", m->b_datap->db_type );
110 t_bind_ack( queue_t *q, struct sockaddr_at *sat )
113 struct T_bind_ack *t;
115 if (( m = allocb( sizeof( struct T_bind_ack ) +
116 sizeof( struct sockaddr_at ), BPRI_HI )) == NULL ) {
119 m->b_wptr = m->b_rptr + sizeof( struct T_bind_ack );
120 m->b_datap->db_type = M_PCPROTO;
122 t = (struct T_bind_ack *)m->b_rptr;
123 t->PRIM_type = T_BIND_ACK;
124 t->ADDR_length = sizeof( struct sockaddr_at );
125 t->ADDR_offset = m->b_wptr - m->b_rptr;
126 t->CONIND_number = 0;
128 bcopy( (caddr_t)sat, m->b_wptr, sizeof( struct sockaddr_at ));
129 m->b_wptr += sizeof( struct sockaddr_at );
136 t_ok_ack( queue_t *q, long prim )
142 if (( m = allocb( sizeof( struct T_ok_ack ), BPRI_HI )) == NULL ) {
145 m->b_wptr = m->b_rptr + sizeof( struct T_ok_ack );
146 m->b_datap->db_type = M_PCPROTO;
148 t = (struct T_ok_ack *)m->b_rptr;
149 t->PRIM_type = T_OK_ACK;
150 t->CORRECT_prim = prim;
156 t_error_ack( queue_t *q, long prim, long terror, long uerror )
159 struct T_error_ack *t;
162 if (( m = allocb( sizeof( struct T_error_ack ), BPRI_HI )) == NULL ) {
165 m->b_wptr = m->b_rptr + sizeof( struct T_error_ack );
166 m->b_datap->db_type = M_PCPROTO;
168 t = (struct T_error_ack *)m->b_rptr;
169 t->PRIM_type = T_ERROR_ACK;
170 t->ERROR_prim = prim;
171 t->TLI_error = terror;
172 t->UNIX_error = uerror;
178 t_info_ack( queue_t *q, long state )
181 struct T_info_ack *t;
184 if (( m = allocb( sizeof( struct T_info_ack ), BPRI_HI )) == NULL ) {
187 m->b_wptr = m->b_rptr + sizeof( struct T_info_ack );
188 m->b_datap->db_type = M_PCPROTO;
190 t = (struct T_info_ack *)m->b_rptr;
191 t->PRIM_type = T_INFO_ACK;
196 t->ADDR_size = sizeof( struct sockaddr_at );
199 t->SERV_type = T_CLTS;
200 t->CURRENT_state = state;
201 t->PROVIDER_flag = 0;
207 t_unitdata_ind( queue_t *q, mblk_t *m0, struct sockaddr_at *sat )
210 struct T_unitdata_ind *t;
212 if (( m = allocb( sizeof( struct T_unitdata_ind ) +
213 sizeof( struct sockaddr_at ), BPRI_HI )) == NULL ) {
216 m->b_wptr = m->b_rptr + sizeof( struct T_unitdata_ind );
217 m->b_datap->db_type = M_PROTO;
219 t = (struct T_unitdata_ind *)m->b_rptr;
220 t->PRIM_type = T_UNITDATA_IND;
221 t->SRC_length = sizeof( struct sockaddr_at );
222 t->SRC_offset = m->b_wptr - m->b_rptr;
223 bcopy( (caddr_t)sat, m->b_wptr, sizeof( struct sockaddr_at ));
224 m->b_wptr += sizeof( struct sockaddr_at );
240 tpi_wput( queue_t *q, mblk_t *m )
242 struct sock_data *sd = (struct sock_data *)RD(q)->q_ptr;
243 union T_primitives *tl;
246 struct ioc_state *is;
249 struct sockaddr_at sat;
255 switch ( m->b_datap->db_type ) {
258 if ( m->b_wptr - m->b_rptr < sizeof( tl->type )) {
262 tl = (union T_primitives *)m->b_rptr;
263 switch ( tl->type ) {
265 t_info_ack( q, sd->sd_state );
270 if ( m->b_wptr - m->b_rptr < sizeof( struct T_unbind_req )) {
274 if ( sd->sd_state != TS_IDLE ) {
275 t_error_ack( q, T_BIND_REQ, TOUTSTATE, 0 );
279 bzero( (caddr_t)&sd->sd_sat, sizeof( struct sockaddr_at ));
280 sd->sd_state = TS_UNBND;
281 t_ok_ack( q, T_UNBIND_REQ );
285 if ( m->b_wptr - m->b_rptr < sizeof( struct T_bind_req )) {
289 if ( sd->sd_state != TS_UNBND ) {
290 t_error_ack( q, T_BIND_REQ, TOUTSTATE, 0 );
295 if ( tl->bind_req.ADDR_length == 0 ) {
296 bzero( (caddr_t)&sat, sizeof( struct sockaddr_at ));
297 sat.sat_family = AF_APPLETALK;
299 if ( tl->bind_req.ADDR_length != sizeof( struct sockaddr ) ||
300 m->b_wptr - m->b_rptr <
301 tl->bind_req.ADDR_offset + tl->bind_req.ADDR_length ) {
302 cmn_err( CE_CONT, "tpi_wput T_BIND_REQ wierd\n" );
306 sat = *(struct sockaddr_at *)(m->b_rptr +
307 tl->bind_req.ADDR_offset );
310 if (( err = sock_bind( sd, &sat )) != 0 ) {
311 t_error_ack( q, T_BIND_REQ, TSYSERR, err );
313 /* seems like we must return the requested address */
314 t_bind_ack( q, &sat );
319 case T_UNITDATA_REQ :
320 if ( m->b_wptr - m->b_rptr < sizeof( struct T_unitdata_req )) {
324 if ( sd->sd_state != TS_IDLE ) {
325 cmn_err( CE_NOTE, "tpi_wput unitdata on unbound socket\n" );
326 t_error_ack( q, T_UNITDATA_REQ, TOUTSTATE, 0 );
330 if ( tl->unitdata_req.DEST_length != sizeof( struct sockaddr )) {
331 cmn_err( CE_NOTE, "tpi_wput T_UNITDATA_REQ %d\n",
332 tl->unitdata_req.DEST_length );
339 * Sometimes, the socket layer gives us crap... Sound like a bug?
341 if ( m->b_rptr + tl->unitdata_req.DEST_offset +
342 tl->unitdata_req.DEST_length > m->b_wptr ) {
343 cmn_err( CE_CONT, "tpi_wput T_UNITDATA_REQ mblk size %X %X\n", m->b_rptr + tl->unitdata_req.DEST_offset + tl->unitdata_req.DEST_length, m->b_wptr );
349 sat = *(struct sockaddr_at *)(m->b_rptr +
350 tl->unitdata_req.DEST_offset );
351 if ( sat.sat_family != AF_APPLETALK ) {
352 cmn_err( CE_CONT, "tpi_wput non-AppleTalk\n" );
357 if ( m->b_wptr - m->b_rptr < sizeof( struct ddpehdr )) {
358 cmn_err( CE_CONT, "tpi_wput m too short\n" );
362 m->b_wptr = m->b_rptr + sizeof( struct ddpehdr );
363 m->b_datap->db_type = M_DATA;
364 deh = (struct ddpehdr *)m->b_rptr;
367 deh->deh_len = msgdsize( m );
369 deh->deh_dnet = sat.sat_addr.s_net;
370 deh->deh_dnode = sat.sat_addr.s_node;
371 deh->deh_dport = sat.sat_port;
373 deh->deh_snet = sd->sd_sat.sat_addr.s_net;
374 deh->deh_snode = sd->sd_sat.sat_addr.s_node;
375 deh->deh_sport = sd->sd_sat.sat_port;
377 deh->deh_sum = 0; /* XXX */
378 deh->deh_bytes = htonl( deh->deh_bytes );
379 return( if_route( if_withaddr( &sd->sd_sat ), m, &sat ));
382 /* cmn_err( CE_NOTE, "tpi_wput M_PCPROTO 0x%X\n", tl->type ); */
383 t_error_ack( q, tl->type, TNOTSUPPORT, 0 );
390 if ( m->b_wptr - m->b_rptr < sizeof( struct iocblk )) {
394 ioc = (struct iocblk *)m->b_rptr;
395 if ( ioc->ioc_count != TRANSPARENT ) {
396 cmn_err( CE_CONT, "tpi_wput non-TRANSPARENT %X\n", ioc->ioc_cmd );
397 ioc_error_ack( q, m, EINVAL );
400 if ( m->b_cont == NULL ) {
401 cmn_err( CE_CONT, "tpi_wput M_IOCTL no arg\n" );
402 ioc_error_ack( q, m, EINVAL );
406 /* de-allocated after M_IOCDATA processing */
407 if (( m0 = allocb( sizeof( struct ioc_state ), BPRI_HI )) == NULL ) {
408 cmn_err( CE_CONT, "tpi_wput m0 no mem\n" );
409 ioc_error_ack( q, m, EINVAL );
412 m0->b_wptr = m->b_rptr + sizeof( struct ioc_state );
413 is = (struct ioc_state *)m0->b_rptr;
415 switch ( ioc->ioc_cmd ) {
418 if (( err = drv_priv( ioc->ioc_cr )) != 0 ) {
419 ioc_error_ack( q, m, err );
422 is->is_state = M_COPYIN;
423 is->is_addr = *(caddr_t *)m->b_cont->b_rptr;
424 ioc_copyin( q, m, m0, is->is_addr, sizeof( struct rtentry ));
429 if (( err = drv_priv( ioc->ioc_cr )) != 0 ) {
430 ioc_error_ack( q, m, err );
435 is->is_state = M_COPYIN;
436 is->is_addr = *(caddr_t *)m->b_cont->b_rptr;
437 ioc_copyin( q, m, m0, is->is_addr, sizeof( struct ifreq ));
441 is->is_state = M_COPYIN;
442 is->is_addr = *(caddr_t *)m->b_cont->b_rptr;
443 ioc_copyin( q, m, m0, is->is_addr, sizeof( struct netbuf ));
447 ioc_error_ack( q, m, EINVAL );
453 if ( m->b_wptr - m->b_rptr < sizeof( struct copyresp )) {
457 cp = (struct copyresp *)m->b_rptr;
458 if ( cp->cp_rval != 0 ) {
459 cmn_err( CE_CONT, "tpi_wput IOCDATA failed %d\n", cp->cp_rval );
464 if (( m0 = cp->cp_private ) == NULL ) {
465 cmn_err( CE_CONT, "tpi_wput IOCDATA no state\n" );
466 ioc_error_ack( q, m, EINVAL );
469 if ( m0->b_wptr - m0->b_rptr < sizeof( struct ioc_state )) {
470 cmn_err( CE_CONT, "tpi_wput IOCDATA private too short\n" );
471 ioc_error_ack( q, m, EINVAL );
474 is = (struct ioc_state *)m0->b_rptr;
476 switch ( cp->cp_cmd ) {
478 switch ( is->is_state ) {
480 if ( m->b_cont == NULL ) {
481 cmn_err( CE_CONT, "tpi_wput TI_GETMYNAME COPYIN no arg\n" );
482 ioc_error_ack( q, m, EINVAL );
485 nb = *(struct netbuf *)m->b_cont->b_rptr;
486 nb.len = sizeof( struct sockaddr_at );
487 /* copy out netbuf */
488 is->is_state = M_COPYOUT;
490 ioc_copyout( q, m, m0, (caddr_t)&nb, is->is_addr,
491 sizeof( struct netbuf ));
492 is->is_addr = nb.buf;
496 switch ( is->is_count ) {
498 /* copy out address to nb.buf */
499 is->is_state = M_COPYOUT;
501 ioc_copyout( q, m, m0, (caddr_t)&sd->sd_sat, is->is_addr,
502 sizeof( struct sockaddr_at ));
506 ioc_ok_ack( q, m, 0 );
510 cmn_err( CE_NOTE, "tpi_wput TI_GETMYNAME count %d\n",
512 ioc_error_ack( q, m, EINVAL );
518 cmn_err( CE_NOTE, "tpi_wput TI_GETMYNAME state %d\n",
520 ioc_error_ack( q, m, EINVAL );
525 case SIOCADDRT : /* manipulate routing table */
527 if (( err = drv_priv( cp->cp_cr )) != 0 ) {
528 ioc_error_ack( q, m, err );
531 if ( is->is_state != M_COPYIN ) {
532 cmn_err( CE_CONT, "tpi_wput SIOC(ADD|DEL)RT bad state\n" );
537 rt = *(struct rtentry *)m->b_cont->b_rptr;
539 if ( cp->cp_cmd == SIOCADDRT ) {
540 err = rt_add( (struct sockaddr_at *)&rt.rt_dst,
541 (struct sockaddr_at *)&rt.rt_gateway, rt.rt_flags );
542 } else if ( cp->cp_cmd == SIOCDELRT ) {
543 err = rt_del( (struct sockaddr_at *)&rt.rt_dst,
544 (struct sockaddr_at *)&rt.rt_gateway, rt.rt_flags );
546 cmn_err( CE_CONT, "tpi_wput SIOC(ADD|DEL)RT bad cmd\n" );
551 ioc_error_ack( q, m, err );
553 ioc_ok_ack( q, m, 0 );
558 * These both require lower messages to be sent.
562 if (( err = drv_priv( cp->cp_cr )) != 0 ) {
563 ioc_error_ack( q, m, err );
566 if ( is->is_state != M_COPYIN ) {
567 cmn_err( CE_CONT, "tpi_wput SIOCSIFADDR bad state\n" );
572 ifr = *(struct ifreq *)m->b_cont->b_rptr;
574 /* initiate command, pass q and m (current context to be saved */
575 if ( cp->cp_cmd == SIOCSIFADDR ) {
576 err = if_setaddr( q, m, ifr.ifr_name,
577 (struct sockaddr_at *)&ifr.ifr_addr );
579 err = if_addmulti( q, m, ifr.ifr_name, &ifr.ifr_addr );
582 ioc_error_ack( q, m, err );
587 case SIOCGIFADDR : /* get interface address */
588 switch ( is->is_state ) {
590 /* ack the original ioctl */
591 ioc_ok_ack( q, m, 0 );
595 if ( m->b_cont == NULL ) {
596 cmn_err( CE_CONT, "tpi_wput SIOCGIFADDR COPYIN no arg\n" );
597 ioc_error_ack( q, m, EINVAL );
602 ifr = *(struct ifreq *)m->b_cont->b_rptr;
603 if (( err = if_getaddr( ifr.ifr_name,
604 (struct sockaddr_at *)&ifr.ifr_addr )) != 0 ) {
605 ioc_error_ack( q, m, err );
607 is->is_state = M_COPYOUT;
608 ioc_copyout( q, m, m0, (caddr_t)&ifr, is->is_addr,
609 sizeof( struct ifreq ));
610 return( 0 ); /* avoid freemsg( m0 ) below */
613 cmn_err( CE_CONT, "tpi_wput SIOCGIFADDR bad state\n" );
620 cmn_err( CE_NOTE, "tpi_wput M_IOCDATA 0x%X\n", cp->cp_cmd );
621 ioc_error_ack( q, m, EINVAL );
628 cmn_err( CE_NOTE, "!tpi_wput dp_type = 0x%X\n", m->b_datap->db_type );
636 static struct module_info tpi_info = {
645 static struct qinit tpi_rinit = {
646 tpi_rput, /* qi_putp */
648 tpi_open, /* qi_qopen */
649 tpi_close, /* qi_qclose */
651 &tpi_info, /* qi_minfo */
655 static struct qinit tpi_winit = {
656 tpi_wput, /* qi_putp */
665 static struct streamtab tpi_stream = {
672 static struct cb_ops tpi_cbops = {
673 nulldev, /* cb_open */
674 nulldev, /* cb_close */
687 D_NEW | D_MP | D_MTPERMOD, /* cb_flag */
689 nodev, /* cb_aread */
690 nodev, /* cb_awrite */
693 static struct dev_ops tpi_devops = {
703 (struct bus_ops *)NULL,
708 * DDP Streams device. This device is opened by socket().
710 struct modldrv tpi_ldrv = {
712 "DDP Streams device",