+++ /dev/null
-/* $Id: dlpi.c,v 1.2 2002-01-17 06:13:02 srittau Exp $
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/kmem.h>
-#include <sys/stream.h>
-#include <sys/conf.h>
-#include <sys/modctl.h>
-#include <sys/cmn_err.h>
-#include <sys/ddi.h>
-#include <sys/socket.h>
-#include <sys/sockio.h>
-#include <sys/dlpi.h>
-#include <sys/ethernet.h>
-#include <sys/byteorder.h>
-#include <sys/sunddi.h>
-#include <net/if.h>
-#include <errno.h>
-
-#include <netatalk/phase2.h>
-#include <netatalk/at.h>
-
-#include "ioc.h"
-#include "if.h"
-
-u_char at_multicastaddr[ ETHERADDRL ] = {
- 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
-};
-u_char at_org_code[ 3 ] = {
- 0x08, 0x00, 0x07,
-};
-u_char aarp_org_code[ 3 ] = {
- 0x00, 0x00, 0x00,
-};
-
- static int
-dlpi_open( queue_t *q, dev_t *dev, int oflag, int sflag, cred_t *cred )
-{
- struct atif_data *aid;
- int err = 0;
-
- if (( err = drv_priv( cred )) != 0 ) {
- return( err );
- }
- if (( aid = if_alloc( q )) == NULL ) {
- return( ENOMEM );
- }
- q->q_ptr = (void *)aid;
-
- qprocson( q );
- return( err );
-}
-
- static int
-dlpi_close( queue_t *q, int oflag, cred_t *cred )
-{
- struct atif_data *aid = (struct atif_data *)q->q_ptr;
-
- qprocsoff( q );
- if_free( aid );
- return( 0 );
-}
-
- static int
-dl_bind_req( queue_t *q, ulong sap )
-{
- union DL_primitives *dl;
- mblk_t *m;
-
- if (( m = allocb( DL_BIND_REQ_SIZE, BPRI_HI )) == NULL ) {
- return( ENOMEM );
- }
- m->b_wptr = m->b_rptr + DL_BIND_REQ_SIZE;
- m->b_datap->db_type = M_PROTO;
-
- dl = (union DL_primitives *)m->b_rptr;
- dl->dl_primitive = DL_BIND_REQ;
- dl->bind_req.dl_sap = sap;
- dl->bind_req.dl_max_conind = 0;
- dl->bind_req.dl_service_mode = DL_CLDLS;
- dl->bind_req.dl_conn_mgmt = 0;
- dl->bind_req.dl_xidtest_flg = 0; /* XXX */
- putnext( q, m );
- return( 0 );
-}
-
- static int
-dl_attach_req( queue_t *q, ulong ppa )
-{
- union DL_primitives *dl;
- mblk_t *m;
-
- if (( m = allocb( DL_ATTACH_REQ_SIZE, BPRI_HI )) == NULL ) {
- return( ENOMEM );
- }
- m->b_wptr = m->b_rptr + DL_ATTACH_REQ_SIZE;
- m->b_datap->db_type = M_PROTO;
-
- dl = (union DL_primitives *)m->b_rptr;
- dl->dl_primitive = DL_ATTACH_REQ;
- dl->attach_req.dl_ppa = ppa;
- putnext( q, m );
- return( 0 );
-}
-
- int
-dl_enabmulti_req( queue_t *q, caddr_t addr )
-{
- union DL_primitives *dl;
- mblk_t *m;
-
- if (( m = allocb( DL_ENABMULTI_REQ_SIZE + ETHERADDRL, BPRI_HI )) == NULL ) {
- return( ENOMEM );
- }
- m->b_wptr = m->b_rptr + DL_ENABMULTI_REQ_SIZE;
- m->b_datap->db_type = M_PROTO;
-
- dl = (union DL_primitives *)m->b_rptr;
- dl->dl_primitive = DL_ENABMULTI_REQ;
- dl->enabmulti_req.dl_addr_length = ETHERADDRL;
- dl->enabmulti_req.dl_addr_offset = m->b_wptr - m->b_rptr;
- bcopy( addr, m->b_wptr, ETHERADDRL );
- m->b_wptr += ETHERADDRL;
- putnext( q, m );
- return( 0 );
-}
-
- int
-dl_unitdata_req( queue_t *q, mblk_t *m0, ushort type, caddr_t addr )
-{
- union DL_primitives *dl;
- struct llc *llc;
- mblk_t *m1, *m;
- ushort len;
-
- /* len = msgdsize( m0 ) + sizeof( struct llc ); */
-
- if (( m1 = allocb( sizeof( struct llc ), BPRI_HI )) == NULL ) {
- cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 1\n" );
- return( ENOMEM );
- }
- m1->b_wptr = m1->b_rptr + sizeof( struct llc );
- m1->b_datap->db_type = M_DATA;
- llc = (struct llc *)m1->b_rptr;
-
- llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
- llc->llc_control = LLC_UI;
- if ( type == ETHERTYPE_AARP ) {
- bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
- } else if ( type == ETHERTYPE_AT ) {
- bcopy( at_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
- } else {
- cmn_err( CE_NOTE, "dl_unitdate_req type %X\n", type );
- return( EINVAL );
- }
- llc->llc_ether_type = htons( type );
- linkb( m1, m0 );
-
- if (( m = allocb( DL_UNITDATA_REQ_SIZE + ETHERADDRL + sizeof( ushort ),
- BPRI_HI )) == NULL ) {
- cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 2\n" );
- return( ENOMEM );
- }
- m->b_wptr = m->b_rptr + DL_UNITDATA_REQ_SIZE;
- m->b_datap->db_type = M_PROTO;
- linkb( m, m1 );
-
- dl = (union DL_primitives *)m->b_rptr;
- dl->dl_primitive = DL_UNITDATA_REQ;
- dl->unitdata_req.dl_dest_addr_length = ETHERADDRL + sizeof ( ushort );
- dl->unitdata_req.dl_dest_addr_offset = m->b_wptr - m->b_rptr;
-
- bcopy(addr, m->b_wptr, ETHERADDRL );
- m->b_wptr += ETHERADDRL;
- len = 0;
- bcopy( &len, m->b_wptr, sizeof( ushort ));
- m->b_wptr += sizeof( ushort );
- putnext( q, m );
- return( 0 );
-}
-
- static int
-dlpi_rput( queue_t *q, mblk_t *m )
-{
- struct atif_data *aid = (struct atif_data *)q->q_ptr;
- union DL_primitives *dl;
- mblk_t *m0;
- struct llc *llc;
-
- switch ( m->b_datap->db_type ) {
- case M_IOCNAK :
- putnext( q, m );
- return( 0 );
-
- case M_PCPROTO :
- case M_PROTO :
- if ( m->b_wptr - m->b_rptr < sizeof( dl->dl_primitive )) {
- break;
- }
- dl = (union DL_primitives *)m->b_rptr;
- switch ( dl->dl_primitive ) {
- case DL_UNITDATA_IND :
- if ( m->b_wptr - m->b_rptr < sizeof( DL_UNITDATA_IND_SIZE )) {
- break;
- }
- if (( m0 = unlinkb( m )) == NULL ) {
- break;
- }
- if ( m0->b_wptr - m0->b_rptr < sizeof( struct llc )) {
- freemsg( m0 );
- break;
- }
- llc = (struct llc *)m0->b_rptr;
- if ( llc->llc_dsap != LLC_SNAP_LSAP ||
- llc->llc_ssap != LLC_SNAP_LSAP ||
- llc->llc_control != LLC_UI ) {
- freemsg( m0 );
- break;
- }
-
- if ( bcmp( llc->llc_org_code, at_org_code,
- sizeof( at_org_code )) == 0 &&
- ntohs( llc->llc_ether_type ) == ETHERTYPE_AT ) {
- adjmsg( m0, sizeof( struct llc ));
- ddp_rput( aid, m0 );
- } else if ( bcmp( llc->llc_org_code, aarp_org_code,
- sizeof( aarp_org_code )) == 0 &&
- ntohs( llc->llc_ether_type ) == ETHERTYPE_AARP ) {
- adjmsg( m0, sizeof( struct llc ));
- aarp_rput( q, m0 );
- } else {
- freemsg( m0 );
- }
- break;
-
- case DL_OK_ACK :
- if ( m->b_wptr - m->b_rptr < sizeof( DL_OK_ACK_SIZE )) {
- break;
- }
- switch ( dl->ok_ack.dl_correct_primitive ) {
- case DL_ATTACH_REQ :
- if ( aid->aid_state != DL_ATTACH_PENDING ) {
- cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach state %d\n",
- aid->aid_state );
- break;
- }
- if ( aid->aid_c.c_type != IF_UNITSEL ) {
- cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach context %x\n",
- aid->aid_c.c_type );
- break;
- }
-
- if ( WR(q)->q_next == NULL || WR(q)->q_next->q_qinfo == NULL ||
- WR(q)->q_next->q_qinfo->qi_minfo == NULL ||
- WR(q)->q_next->q_qinfo->qi_minfo->mi_idname == NULL ) {
- cmn_err( CE_NOTE, "dlpi_rput can't get interface name\n" );
- break;
- }
-
- if_name( aid, WR(q)->q_next->q_qinfo->qi_minfo->mi_idname,
- aid->aid_c.c_u.u_unit.uu_ppa );
-
- aid->aid_state = DL_BIND_PENDING;
-
-#ifdef i386
- /*
- * As of Solaris 7 (nice name), the i386 arch needs to be
- * bound as 0 to receive 802 frames. However, in the same
- * OS, Sparcs must be bound as ETHERMTU (or at least not 0)
- * to receive the same frames. A bug? In the Solaris 7
- * (nice name) kernel?
- */
- dl_bind_req( WR( q ), 0 );
-#else /* i386 */
- dl_bind_req( WR( q ), ETHERMTU );
-#endif /* i386 */
- break;
-
- case DL_ENABMULTI_REQ :
- if ( aid->aid_c.c_type != SIOCADDMULTI ) {
- cmn_err( CE_NOTE,
- "dlpi_rput DL_OK_ACK enabmulti context %x\n",
- aid->aid_c.c_type );
- break;
- }
-
- ioc_ok_ack( aid->aid_c.c_u.u_multi.um_q,
- aid->aid_c.c_u.u_multi.um_m, 0 );
- aid->aid_c.c_type = 0;
- aid->aid_c.c_u.u_multi.um_q = NULL;
- aid->aid_c.c_u.u_multi.um_m = 0;
- break;
-
- default :
- cmn_err( CE_CONT, "!dlpi_rput DL_OK_ACK unhandled %d\n",
- dl->ok_ack.dl_correct_primitive );
- break;
- }
- break;
-
- case DL_BIND_ACK :
- if ( m->b_wptr - m->b_rptr < sizeof( DL_BIND_ACK_SIZE )) {
- break;
- }
- if ( aid->aid_state != DL_BIND_PENDING ) {
- break;
- }
- if ( aid->aid_c.c_type != IF_UNITSEL ) {
- break;
- }
- bcopy( m->b_rptr + dl->bind_ack.dl_addr_offset, aid->aid_hwaddr,
- dl->bind_ack.dl_addr_length );
- aid->aid_state = DL_IDLE;
- ioc_ok_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, 0 );
- aid->aid_c.c_type = 0;
- aid->aid_c.c_u.u_unit.uu_m = NULL;
- aid->aid_c.c_u.u_unit.uu_ppa = 0;
- break;
-
- case DL_ERROR_ACK :
- if ( m->b_wptr - m->b_rptr < sizeof( DL_ERROR_ACK_SIZE )) {
- break;
- }
-
- switch ( aid->aid_c.c_type ) {
- case IF_UNITSEL :
- if ( dl->error_ack.dl_errno == DL_SYSERR ) {
- ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m,
- dl->error_ack.dl_unix_errno );
- } else {
- cmn_err( CE_CONT, "dlpi_rput DL_ERROR_ACK 0x%x\n",
- dl->error_ack.dl_errno );
- ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, EINVAL );
- }
- aid->aid_c.c_type = 0;
- aid->aid_c.c_u.u_unit.uu_m = NULL;
- aid->aid_c.c_u.u_unit.uu_ppa = 0;
- break;
-
- default :
- cmn_err( CE_NOTE, "dlpi_rput DL_ERROR_ACK unhandled %d %d %d\n",
- dl->error_ack.dl_error_primitive,
- dl->error_ack.dl_errno, dl->error_ack.dl_unix_errno );
- break;
- }
- break;
-
- default :
- cmn_err( CE_NOTE, "dlpi_rput M_PCPROTO 0x%x\n", dl->dl_primitive );
- break;
- }
- break;
-
- default :
- cmn_err( CE_NOTE, "dlpi_rput 0x%X\n", m->b_datap->db_type );
- break;
- }
-
- freemsg( m );
- return( 0 );
-}
-
- static int
-dlpi_wput( queue_t *q, mblk_t *m )
-{
- struct atif_data *aid = (struct atif_data *)RD(q)->q_ptr;
- struct iocblk *ioc;
- int rc;
-
- switch ( m->b_datap->db_type ) {
- case M_IOCTL :
- if ( m->b_wptr - m->b_rptr < sizeof( struct iocblk )) {
- freemsg( m );
- break;
- }
- ioc = (struct iocblk *)m->b_rptr;
- switch ( ioc->ioc_cmd ) {
- case IF_UNITSEL :
- if ( ioc->ioc_count != TRANSPARENT ) {
- cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL non-TRANSPARENT\n" );
- ioc_error_ack( q, m, EINVAL );
- break;
- }
- if ( m->b_cont == NULL ) {
- cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL no arg\n" );
- ioc_error_ack( q, m, EINVAL );
- break;
- }
- if ( aid->aid_state != DL_UNATTACHED ) {
- cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL already attached\n" );
- ioc_error_ack( q, m, EINVAL );
- break;
- }
- if ( aid->aid_c.c_type != 0 ) {
- cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL context %x\n",
- aid->aid_c.c_type );
- ioc_error_ack( q, m, EINVAL );
- break;
- }
-
- aid->aid_state = DL_ATTACH_PENDING;
- aid->aid_c.c_type = IF_UNITSEL;
- aid->aid_c.c_u.u_unit.uu_m = m;
- aid->aid_c.c_u.u_unit.uu_ppa = *(ulong *)m->b_cont->b_rptr;
- if (( rc = dl_attach_req( q, aid->aid_c.c_u.u_unit.uu_ppa )) < 0 ) {
- ioc_error_ack( q, m, rc );
- break;
- }
- break;
-
- default :
- cmn_err( CE_NOTE, "dlpi_wput M_IOCTL 0x%X\n", ioc->ioc_cmd );
- putnext( q, m );
- break;
- }
- break;
-
- default :
- cmn_err( CE_NOTE, "dlpi_wput 0x%X\n", m->b_datap->db_type );
- freemsg( m );
- break;
- }
-
- return( 0 );
-}
-
-static struct module_info dlpi_info = {
- 0,
- "ddp",
- 0,
- 1500,
- 3000,
- 64
-};
-
-static struct qinit dlpi_rinit = {
- dlpi_rput, /* qi_putp */
- NULL, /* qi_srvp */
- dlpi_open, /* qi_qopen */
- dlpi_close, /* qi_qclose */
- NULL,
- &dlpi_info, /* qi_minfo */
- NULL,
-};
-
-static struct qinit dlpi_winit = {
- dlpi_wput, /* qi_putp */
- NULL, /* qi_srvp */
- NULL, /* qi_qopen */
- NULL, /* qi_qclose */
- NULL,
- &dlpi_info, /* qi_minfo */
- NULL,
-};
-
-static struct streamtab dlpi_stream = {
- &dlpi_rinit,
- &dlpi_winit,
- NULL,
- NULL
-};
-
-static struct fmodsw dlpi_fmodsw = {
- "ddp",
- &dlpi_stream,
- D_NEW | D_MP | D_MTPERMOD
-};
-
-/*
- * DDP Streams module. This module is pushed on DLPI drivers by atalkd.
- */
-struct modlstrmod dlpi_lstrmod = {
- &mod_strmodops,
- "DDP Streams module",
- &dlpi_fmodsw,
-};