3 #endif /* HAVE_CONFIG_H */
7 #include <sys/stream.h>
8 #include <sys/devops.h>
9 #include <sys/modctl.h>
12 #include <sys/sockio.h>
13 #include <sys/socket.h>
14 #include <sys/tihdr.h>
15 #include <sys/tiuser.h>
16 #include <sys/timod.h>
17 #include <sys/sunddi.h>
18 #include <sys/ethernet.h>
20 #include <net/route.h>
23 #include <netatalk/endian.h>
24 #include <netatalk/at.h>
25 #include <netatalk/ddp.h>
33 tpi_getinfo( dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp )
36 return( DDI_FAILURE );
39 /* Solaris 10 removed DDI_IDENTIFIED and replaced "identify" with "nulldev" */
42 tpi_identify( dev_info_t *dip )
46 /* don't use strcmp under Solaris 9, problem loading kernel module */
47 tmp = ddi_get_name( dip );
48 if ((tmp[0]== 'd') && (tmp[1]=='d') && (tmp[2]=='p') && tmp[3]==0) {
49 return( DDI_IDENTIFIED );
51 return( DDI_NOT_IDENTIFIED );
54 #endif /* DDI_IDENTIFIED */
57 tpi_attach( dev_info_t *dip, ddi_attach_cmd_t cmd )
61 if ( cmd != DDI_ATTACH ) {
62 return( DDI_FAILURE );
65 if (( rc = ddi_create_minor_node( dip, "ddp", S_IFCHR, 0, DDI_PSEUDO,
66 CLONE_DEV )) != DDI_SUCCESS ) {
73 tpi_detach( dev_info_t *dip, ddi_detach_cmd_t cmd )
75 if ( cmd != DDI_DETACH ) {
76 return( DDI_FAILURE );
79 ddi_remove_minor_node( dip, "ddp" );
81 return( DDI_SUCCESS );
85 tpi_open( queue_t *q, dev_t *dev, int oflag, int sflag, cred_t *cred )
87 static minor_t minor = 1;
89 if ( sflag != CLONEOPEN ) {
92 if (( q->q_ptr = (void *)sock_alloc( q )) == NULL ) {
96 *dev = makedevice( getmajor( *dev ), minor++ );
102 tpi_close( queue_t *q, int oflag, cred_t *cred )
104 struct sock_data *sd = (struct sock_data *)q->q_ptr;
112 tpi_rput( queue_t *q, mblk_t *m )
114 cmn_err( CE_NOTE, "tpi_rput dp_type = 0x%X\n", m->b_datap->db_type );
120 t_bind_ack( queue_t *q, struct sockaddr_at *sat )
123 struct T_bind_ack *t;
125 if (( m = allocb( sizeof( struct T_bind_ack ) +
126 sizeof( struct sockaddr_at ), BPRI_HI )) == NULL ) {
129 m->b_wptr = m->b_rptr + sizeof( struct T_bind_ack );
130 m->b_datap->db_type = M_PCPROTO;
132 t = (struct T_bind_ack *)m->b_rptr;
133 t->PRIM_type = T_BIND_ACK;
134 t->ADDR_length = sizeof( struct sockaddr_at );
135 t->ADDR_offset = m->b_wptr - m->b_rptr;
136 t->CONIND_number = 0;
138 bcopy( (caddr_t)sat, m->b_wptr, sizeof( struct sockaddr_at ));
139 m->b_wptr += sizeof( struct sockaddr_at );
146 t_ok_ack( queue_t *q, long prim )
152 if (( m = allocb( sizeof( struct T_ok_ack ), BPRI_HI )) == NULL ) {
155 m->b_wptr = m->b_rptr + sizeof( struct T_ok_ack );
156 m->b_datap->db_type = M_PCPROTO;
158 t = (struct T_ok_ack *)m->b_rptr;
159 t->PRIM_type = T_OK_ACK;
160 t->CORRECT_prim = prim;
166 t_error_ack( queue_t *q, long prim, long terror, long uerror )
169 struct T_error_ack *t;
172 if (( m = allocb( sizeof( struct T_error_ack ), BPRI_HI )) == NULL ) {
175 m->b_wptr = m->b_rptr + sizeof( struct T_error_ack );
176 m->b_datap->db_type = M_PCPROTO;
178 t = (struct T_error_ack *)m->b_rptr;
179 t->PRIM_type = T_ERROR_ACK;
180 t->ERROR_prim = prim;
181 t->TLI_error = terror;
182 t->UNIX_error = uerror;
188 t_info_ack( queue_t *q, long state )
191 struct T_info_ack *t;
194 if (( m = allocb( sizeof( struct T_info_ack ), BPRI_HI )) == NULL ) {
197 m->b_wptr = m->b_rptr + sizeof( struct T_info_ack );
198 m->b_datap->db_type = M_PCPROTO;
200 t = (struct T_info_ack *)m->b_rptr;
201 t->PRIM_type = T_INFO_ACK;
206 t->ADDR_size = sizeof( struct sockaddr_at );
209 t->SERV_type = T_CLTS;
210 t->CURRENT_state = state;
211 t->PROVIDER_flag = 0;
217 t_unitdata_ind( queue_t *q, mblk_t *m0, struct sockaddr_at *sat )
220 struct T_unitdata_ind *t;
222 if (( m = allocb( sizeof( struct T_unitdata_ind ) +
223 sizeof( struct sockaddr_at ), BPRI_HI )) == NULL ) {
226 m->b_wptr = m->b_rptr + sizeof( struct T_unitdata_ind );
227 m->b_datap->db_type = M_PROTO;
229 t = (struct T_unitdata_ind *)m->b_rptr;
230 t->PRIM_type = T_UNITDATA_IND;
231 t->SRC_length = sizeof( struct sockaddr_at );
232 t->SRC_offset = m->b_wptr - m->b_rptr;
233 bcopy( (caddr_t)sat, m->b_wptr, sizeof( struct sockaddr_at ));
234 m->b_wptr += sizeof( struct sockaddr_at );
250 tpi_wput( queue_t *q, mblk_t *m )
252 struct sock_data *sd = (struct sock_data *)RD(q)->q_ptr;
253 union T_primitives *tl;
256 struct ioc_state *is;
259 struct sockaddr_at sat;
265 switch ( m->b_datap->db_type ) {
268 if ( m->b_wptr - m->b_rptr < sizeof( tl->type )) {
272 tl = (union T_primitives *)m->b_rptr;
273 switch ( tl->type ) {
275 t_info_ack( q, sd->sd_state );
280 if ( m->b_wptr - m->b_rptr < sizeof( struct T_unbind_req )) {
284 if ( sd->sd_state != TS_IDLE ) {
285 t_error_ack( q, T_BIND_REQ, TOUTSTATE, 0 );
289 bzero( (caddr_t)&sd->sd_sat, sizeof( struct sockaddr_at ));
290 sd->sd_state = TS_UNBND;
291 t_ok_ack( q, T_UNBIND_REQ );
295 if ( m->b_wptr - m->b_rptr < sizeof( struct T_bind_req )) {
299 if ( sd->sd_state != TS_UNBND ) {
300 t_error_ack( q, T_BIND_REQ, TOUTSTATE, 0 );
305 if ( tl->bind_req.ADDR_length == 0 ) {
306 bzero( (caddr_t)&sat, sizeof( struct sockaddr_at ));
307 sat.sat_family = AF_APPLETALK;
309 if ( tl->bind_req.ADDR_length != sizeof( struct sockaddr ) ||
310 m->b_wptr - m->b_rptr <
311 tl->bind_req.ADDR_offset + tl->bind_req.ADDR_length ) {
312 cmn_err( CE_CONT, "tpi_wput T_BIND_REQ wierd\n" );
316 sat = *(struct sockaddr_at *)(m->b_rptr +
317 tl->bind_req.ADDR_offset );
320 if (( err = sock_bind( sd, &sat )) != 0 ) {
321 t_error_ack( q, T_BIND_REQ, TSYSERR, err );
323 /* seems like we must return the requested address */
324 t_bind_ack( q, &sat );
329 case T_UNITDATA_REQ :
330 if ( m->b_wptr - m->b_rptr < sizeof( struct T_unitdata_req )) {
334 if ( sd->sd_state != TS_IDLE ) {
335 cmn_err( CE_NOTE, "tpi_wput unitdata on unbound socket\n" );
336 t_error_ack( q, T_UNITDATA_REQ, TOUTSTATE, 0 );
340 if ( tl->unitdata_req.DEST_length != sizeof( struct sockaddr )) {
341 cmn_err( CE_NOTE, "tpi_wput T_UNITDATA_REQ %d\n",
342 tl->unitdata_req.DEST_length );
349 * Sometimes, the socket layer gives us crap... Sound like a bug?
351 if ( m->b_rptr + tl->unitdata_req.DEST_offset +
352 tl->unitdata_req.DEST_length > m->b_wptr ) {
353 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 );
359 sat = *(struct sockaddr_at *)(m->b_rptr +
360 tl->unitdata_req.DEST_offset );
361 if ( sat.sat_family != AF_APPLETALK ) {
362 cmn_err( CE_CONT, "tpi_wput non-AppleTalk\n" );
367 if ( m->b_wptr - m->b_rptr < sizeof( struct ddpehdr )) {
368 cmn_err( CE_CONT, "tpi_wput m too short\n" );
372 m->b_wptr = m->b_rptr + sizeof( struct ddpehdr );
373 m->b_datap->db_type = M_DATA;
374 deh = (struct ddpehdr *)m->b_rptr;
377 deh->deh_len = msgdsize( m );
379 deh->deh_dnet = sat.sat_addr.s_net;
380 deh->deh_dnode = sat.sat_addr.s_node;
381 deh->deh_dport = sat.sat_port;
383 deh->deh_snet = sd->sd_sat.sat_addr.s_net;
384 deh->deh_snode = sd->sd_sat.sat_addr.s_node;
385 deh->deh_sport = sd->sd_sat.sat_port;
387 deh->deh_sum = 0; /* XXX */
388 deh->deh_bytes = htonl( deh->deh_bytes );
389 return( if_route( if_withaddr( &sd->sd_sat ), m, &sat ));
392 /* cmn_err( CE_NOTE, "tpi_wput M_PCPROTO 0x%X\n", tl->type ); */
393 t_error_ack( q, tl->type, TNOTSUPPORT, 0 );
400 if ( m->b_wptr - m->b_rptr < sizeof( struct iocblk )) {
404 ioc = (struct iocblk *)m->b_rptr;
405 if ( ioc->ioc_count != TRANSPARENT ) {
406 cmn_err( CE_CONT, "tpi_wput non-TRANSPARENT %X\n", ioc->ioc_cmd );
407 ioc_error_ack( q, m, EINVAL );
410 if ( m->b_cont == NULL ) {
411 cmn_err( CE_CONT, "tpi_wput M_IOCTL no arg\n" );
412 ioc_error_ack( q, m, EINVAL );
416 /* de-allocated after M_IOCDATA processing */
417 if (( m0 = allocb( sizeof( struct ioc_state ), BPRI_HI )) == NULL ) {
418 cmn_err( CE_CONT, "tpi_wput m0 no mem\n" );
419 ioc_error_ack( q, m, EINVAL );
422 m0->b_wptr = m->b_rptr + sizeof( struct ioc_state );
423 is = (struct ioc_state *)m0->b_rptr;
425 switch ( ioc->ioc_cmd ) {
428 if (( err = drv_priv( ioc->ioc_cr )) != 0 ) {
429 ioc_error_ack( q, m, err );
432 is->is_state = M_COPYIN;
433 is->is_addr = *(caddr_t *)m->b_cont->b_rptr;
434 ioc_copyin( q, m, m0, is->is_addr, sizeof( struct rtentry ));
439 if (( err = drv_priv( ioc->ioc_cr )) != 0 ) {
440 ioc_error_ack( q, m, err );
445 is->is_state = M_COPYIN;
446 is->is_addr = *(caddr_t *)m->b_cont->b_rptr;
447 ioc_copyin( q, m, m0, is->is_addr, sizeof( struct ifreq ));
451 is->is_state = M_COPYIN;
452 is->is_addr = *(caddr_t *)m->b_cont->b_rptr;
453 ioc_copyin( q, m, m0, is->is_addr, sizeof( struct netbuf ));
457 ioc_error_ack( q, m, EINVAL );
463 if ( m->b_wptr - m->b_rptr < sizeof( struct copyresp )) {
467 cp = (struct copyresp *)m->b_rptr;
468 if ( cp->cp_rval != 0 ) {
469 cmn_err( CE_CONT, "tpi_wput IOCDATA failed %s\n", cp->cp_rval );
474 if (( m0 = cp->cp_private ) == NULL ) {
475 cmn_err( CE_CONT, "tpi_wput IOCDATA no state\n" );
476 ioc_error_ack( q, m, EINVAL );
479 if ( m0->b_wptr - m0->b_rptr < sizeof( struct ioc_state )) {
480 cmn_err( CE_CONT, "tpi_wput IOCDATA private too short\n" );
481 ioc_error_ack( q, m, EINVAL );
484 is = (struct ioc_state *)m0->b_rptr;
486 switch ( cp->cp_cmd ) {
488 switch ( is->is_state ) {
490 if ( m->b_cont == NULL ) {
491 cmn_err( CE_CONT, "tpi_wput TI_GETMYNAME COPYIN no arg\n" );
492 ioc_error_ack( q, m, EINVAL );
495 nb = *(struct netbuf *)m->b_cont->b_rptr;
496 nb.len = sizeof( struct sockaddr_at );
497 /* copy out netbuf */
498 is->is_state = M_COPYOUT;
500 ioc_copyout( q, m, m0, (caddr_t)&nb, is->is_addr,
501 sizeof( struct netbuf ));
502 is->is_addr = nb.buf;
506 switch ( is->is_count ) {
508 /* copy out address to nb.buf */
509 is->is_state = M_COPYOUT;
511 ioc_copyout( q, m, m0, (caddr_t)&sd->sd_sat, is->is_addr,
512 sizeof( struct sockaddr_at ));
516 ioc_ok_ack( q, m, 0 );
520 cmn_err( CE_NOTE, "tpi_wput TI_GETMYNAME count %d\n",
522 ioc_error_ack( q, m, EINVAL );
528 cmn_err( CE_NOTE, "tpi_wput TI_GETMYNAME state %d\n",
530 ioc_error_ack( q, m, EINVAL );
535 case SIOCADDRT : /* manipulate routing table */
537 if (( err = drv_priv( cp->cp_cr )) != 0 ) {
538 ioc_error_ack( q, m, err );
541 if ( is->is_state != M_COPYIN ) {
542 cmn_err( CE_CONT, "tpi_wput SIOC(ADD|DEL)RT bad state\n" );
547 rt = *(struct rtentry *)m->b_cont->b_rptr;
549 if ( cp->cp_cmd == SIOCADDRT ) {
550 err = rt_add( (struct sockaddr_at *)&rt.rt_dst,
551 (struct sockaddr_at *)&rt.rt_gateway, rt.rt_flags );
552 } else if ( cp->cp_cmd == SIOCDELRT ) {
553 err = rt_del( (struct sockaddr_at *)&rt.rt_dst,
554 (struct sockaddr_at *)&rt.rt_gateway, rt.rt_flags );
556 cmn_err( CE_CONT, "tpi_wput SIOC(ADD|DEL)RT bad cmd\n" );
561 ioc_error_ack( q, m, err );
563 ioc_ok_ack( q, m, 0 );
568 * These both require lower messages to be sent.
572 if (( err = drv_priv( cp->cp_cr )) != 0 ) {
573 ioc_error_ack( q, m, err );
576 if ( is->is_state != M_COPYIN ) {
577 cmn_err( CE_CONT, "tpi_wput SIOCSIFADDR bad state\n" );
582 ifr = *(struct ifreq *)m->b_cont->b_rptr;
584 /* initiate command, pass q and m (current context to be saved */
585 if ( cp->cp_cmd == SIOCSIFADDR ) {
586 err = if_setaddr( q, m, ifr.ifr_name,
587 (struct sockaddr_at *)&ifr.ifr_addr );
589 err = if_addmulti( q, m, ifr.ifr_name, &ifr.ifr_addr );
592 ioc_error_ack( q, m, err );
597 case SIOCGIFADDR : /* get interface address */
598 switch ( is->is_state ) {
600 /* ack the original ioctl */
601 ioc_ok_ack( q, m, 0 );
605 if ( m->b_cont == NULL ) {
606 cmn_err( CE_CONT, "tpi_wput SIOCGIFADDR COPYIN no arg\n" );
607 ioc_error_ack( q, m, EINVAL );
612 ifr = *(struct ifreq *)m->b_cont->b_rptr;
613 if (( err = if_getaddr( ifr.ifr_name,
614 (struct sockaddr_at *)&ifr.ifr_addr )) != 0 ) {
615 ioc_error_ack( q, m, err );
617 is->is_state = M_COPYOUT;
618 ioc_copyout( q, m, m0, (caddr_t)&ifr, is->is_addr,
619 sizeof( struct ifreq ));
620 return( 0 ); /* avoid freemsg( m0 ) below */
623 cmn_err( CE_CONT, "tpi_wput SIOCGIFADDR bad state\n" );
630 cmn_err( CE_NOTE, "tpi_wput M_IOCDATA 0x%X\n", cp->cp_cmd );
631 ioc_error_ack( q, m, EINVAL );
638 cmn_err( CE_NOTE, "!tpi_wput dp_type = 0x%X\n", m->b_datap->db_type );
646 static struct module_info tpi_info = {
655 static struct qinit tpi_rinit = {
656 tpi_rput, /* qi_putp */
658 tpi_open, /* qi_qopen */
659 tpi_close, /* qi_qclose */
661 &tpi_info, /* qi_minfo */
665 static struct qinit tpi_winit = {
666 tpi_wput, /* qi_putp */
675 static struct streamtab tpi_stream = {
682 static struct cb_ops tpi_cbops = {
683 nulldev, /* cb_open */
684 nulldev, /* cb_close */
697 D_NEW | D_MP | D_MTPERMOD, /* cb_flag */
699 nodev, /* cb_aread */
700 nodev, /* cb_awrite */
703 static struct dev_ops tpi_devops = {
707 #ifdef DDI_IDENTIFIED
717 (struct bus_ops *)NULL,
722 * DDP Streams device. This device is opened by socket().
724 struct modldrv tpi_ldrv = {
726 "DDP Streams device",