diff options
author | denny <denny@cvs.openbsd.org> | 1997-07-23 03:39:56 +0000 |
---|---|---|
committer | denny <denny@cvs.openbsd.org> | 1997-07-23 03:39:56 +0000 |
commit | d5b5fef1bdafdd83fef5c12b6377d14969833223 (patch) | |
tree | 1ad3ced51a31c06338a1a898f59a19ea3ec76764 /sys | |
parent | e3f1ae5edbe93df49723a93fe383d3b3d2282221 (diff) |
netatalk, based on the 1.4a2 dist from the University of Michigan.
The sys/netatalk files rely heavily on previous work done on FreeBSD, and to a lesser extent NetBSD.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netatalk/COPYRIGHT | 34 | ||||
-rw-r--r-- | sys/netatalk/aarp.c | 695 | ||||
-rw-r--r-- | sys/netatalk/aarp.h | 106 | ||||
-rw-r--r-- | sys/netatalk/at.h | 147 | ||||
-rw-r--r-- | sys/netatalk/at_control.c | 650 | ||||
-rw-r--r-- | sys/netatalk/at_extern.h | 108 | ||||
-rw-r--r-- | sys/netatalk/at_proto.c | 113 | ||||
-rw-r--r-- | sys/netatalk/at_var.h | 113 | ||||
-rw-r--r-- | sys/netatalk/ddp.h | 181 | ||||
-rw-r--r-- | sys/netatalk/ddp_input.c | 438 | ||||
-rw-r--r-- | sys/netatalk/ddp_output.c | 250 | ||||
-rw-r--r-- | sys/netatalk/ddp_usrreq.c | 580 | ||||
-rw-r--r-- | sys/netatalk/ddp_var.h | 84 | ||||
-rw-r--r-- | sys/netatalk/endian.h | 1 | ||||
-rw-r--r-- | sys/netatalk/phase2.h | 64 |
15 files changed, 3564 insertions, 0 deletions
diff --git a/sys/netatalk/COPYRIGHT b/sys/netatalk/COPYRIGHT new file mode 100644 index 00000000000..92ba01a6cb5 --- /dev/null +++ b/sys/netatalk/COPYRIGHT @@ -0,0 +1,34 @@ +Copyright (c) 1990,1996 Regents of The University of Michigan. +All Rights Reserved. + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear + in supporting documentation, and that the name of The University + of Michigan not be used in advertising or publicity pertaining to + distribution of the software without specific, written prior + permission. This software is supplied as is without expressed or + implied warranties of any kind. + +This product includes software developed by the University of +California, Berkeley and its contributors. + +Solaris code is encumbered by the following: + + Copyright (C) 1996 by Sun Microsystems Computer Co. + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that copyright notice and this permission + notice appear in supporting documentation. This software is + provided "as is" without express or implied warranty. + +Research Systems Unix Group +The University of Michigan +c/o Wesley Craig +535 W. William Street +Ann Arbor, Michigan ++1-313-764-2278 +netatalk@umich.edu diff --git a/sys/netatalk/aarp.c b/sys/netatalk/aarp.c new file mode 100644 index 00000000000..c09d99555e0 --- /dev/null +++ b/sys/netatalk/aarp.c @@ -0,0 +1,695 @@ +/* $OpenBSD: aarp.c,v 1.1 1997/07/23 03:39:50 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/proc.h> + +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#undef s_net +#include <netinet/if_ether.h> +#include <net/if_llc.h> + +#include <machine/endian.h> + +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#include <netatalk/aarp.h> +#include <netatalk/ddp_var.h> +#include <netatalk/phase2.h> +#include <netatalk/at_extern.h> + +static void aarptimer __P((void *)); +struct ifaddr *at_ifawithnet __P((struct sockaddr_at *, struct ifaddr *)); +static void aarpwhohas __P((struct arpcom *, struct sockaddr_at *)); +int aarpresolve __P((struct arpcom *, struct mbuf *, + struct sockaddr_at *, u_int8_t *)); +void aarpinput __P((struct arpcom *, struct mbuf *)); +static void at_aarpinput __P((struct arpcom *, struct mbuf *)); +static void aarptfree __P((struct aarptab *)); +struct aarptab *aarptnew __P((struct at_addr *)); +void aarpprobe __P((void *)); +void aarp_clean __P((void)); + +#ifdef GATEWAY +#define AARPTAB_BSIZ 16 +#define AARPTAB_NB 37 +#else +#define AARPTAB_BSIZ 9 +#define AARPTAB_NB 19 +#endif GATEWAY + +#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) +struct aarptab aarptab[AARPTAB_SIZE]; +int aarptab_size = AARPTAB_SIZE; + +#define AARPTAB_HASH(a) \ + ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB ) + +#define AARPTAB_LOOK(aat,addr) { \ + int n; \ + aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \ + for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \ + if ( aat->aat_ataddr.s_net == (addr).s_net && \ + aat->aat_ataddr.s_node == (addr).s_node ) \ + break; \ + if ( n >= AARPTAB_BSIZ ) \ + aat = 0; \ +} + +#define AARPT_AGE (60 * 1) +#define AARPT_KILLC 20 +#define AARPT_KILLI 3 + +u_int8_t atmulticastaddr[ 6 ] = { + 0x09, 0x00, 0x07, 0xff, 0xff, 0xff, +}; + +u_int8_t at_org_code[ 3 ] = { + 0x08, 0x00, 0x07, +}; +u_int8_t aarp_org_code[ 3 ] = { + 0x00, 0x00, 0x00, +}; + +/*ARGSUSED*/ +static void +aarptimer(v) + void *v; +{ + struct aarptab *aat; + int i, s; + + timeout( aarptimer, (caddr_t)0, AARPT_AGE * hz ); + aat = aarptab; + for ( i = 0; i < AARPTAB_SIZE; i++, aat++ ) { + if ( aat->aat_flags == 0 || ( aat->aat_flags & ATF_PERM )) + continue; + if ( ++aat->aat_timer < (( aat->aat_flags & ATF_COM ) ? + AARPT_KILLC : AARPT_KILLI )) + continue; + s = splimp(); + aarptfree( aat ); + splx( s ); + } +} + +struct ifaddr * +at_ifawithnet( sat, ifa ) + struct sockaddr_at *sat; + struct ifaddr *ifa; +{ + struct sockaddr_at *sat2; + struct netrange *nr; + + for (; ifa; ifa = ifa->ifa_list.tqe_next ) { + if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) { + continue; + } + sat2 = satosat( ifa->ifa_addr ); + if ( sat2->sat_addr.s_net == sat->sat_addr.s_net ) { + break; + } + nr = (struct netrange *)(sat2->sat_zero); + if( (nr->nr_phase == 2 ) + && (nr->nr_firstnet <= sat->sat_addr.s_net) + && (nr->nr_lastnet >= sat->sat_addr.s_net)) { + break; + } + } + return( ifa ); +} + +static void +aarpwhohas( ac, sat ) + struct arpcom *ac; + struct sockaddr_at *sat; +{ + struct mbuf *m; + struct ether_header *eh; + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct llc *llc; + struct sockaddr sa; + + if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) { + return; + } + m->m_len = sizeof( *ea ); + m->m_pkthdr.len = sizeof( *ea ); + MH_ALIGN( m, sizeof( *ea )); + + ea = mtod( m, struct ether_aarp *); + bzero((caddr_t)ea, sizeof( *ea )); + + ea->aarp_hrd = htons( AARPHRD_ETHER ); + ea->aarp_pro = htons( ETHERTYPE_AT ); + ea->aarp_hln = sizeof( ea->aarp_sha ); + ea->aarp_pln = sizeof( ea->aarp_spu ); + ea->aarp_op = htons( AARPOP_REQUEST ); + bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, + sizeof( ea->aarp_sha )); + + /* + * We need to check whether the output ethernet type should + * be phase 1 or 2. We have the interface that we'll be sending + * the aarp out. We need to find an AppleTalk network on that + * interface with the same address as we're looking for. If the + * net is phase 2, generate an 802.2 and SNAP header. + */ + if (( aa = (struct at_ifaddr *) + at_ifawithnet( sat, ac->ac_if.if_addrlist.tqh_first )) == NULL ) { + m_freem( m ); + return; + } + + eh = (struct ether_header *)sa.sa_data; + + if ( aa->aa_flags & AFA_PHASE2 ) { + bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, + sizeof( eh->ether_dhost )); + eh->ether_type = htons(AT_LLC_SIZE + sizeof(struct ether_aarp)); + M_PREPEND( m, AT_LLC_SIZE, M_WAIT ); + llc = mtod( m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); + llc->llc_ether_type = htons( ETHERTYPE_AARP ); + + bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet, + sizeof( ea->aarp_spnet )); + ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node; + bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet, + sizeof( ea->aarp_tpnet )); + ea->aarp_tpnode = sat->sat_addr.s_node; + } else { + bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, + sizeof( eh->ether_dhost )); + eh->ether_type = htons( ETHERTYPE_AARP ); + + ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node; + ea->aarp_tpa = sat->sat_addr.s_node; + } + + sa.sa_len = sizeof( struct sockaddr ); + sa.sa_family = AF_UNSPEC; + /* XXX The NULL should be a struct rtentry. TBD */ + (*ac->ac_if.if_output)(&ac->ac_if, m, &sa , NULL); +} + +int +aarpresolve( ac, m, destsat, desten ) + struct arpcom *ac; + struct mbuf *m; + struct sockaddr_at *destsat; + u_int8_t *desten; +{ + struct at_ifaddr *aa; + struct aarptab *aat; + int s; + + if ( at_broadcast( destsat )) { + if (( aa = (struct at_ifaddr *)at_ifawithnet( destsat, + ((struct ifnet *)ac)->if_addrlist.tqh_first )) == NULL ) { + m_freem( m ); + return( 0 ); + } + if ( aa->aa_flags & AFA_PHASE2 ) { + bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten, + sizeof( atmulticastaddr )); + } else { + bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten, + sizeof( etherbroadcastaddr )); + } + return( 1 ); + } + + s = splimp(); + AARPTAB_LOOK( aat, destsat->sat_addr ); + if ( aat == 0 ) { /* No entry */ + aat = aarptnew( &destsat->sat_addr ); + if ( aat == 0 ) { /* XXX allocate more */ + panic( "aarpresolve: no free entry" ); + } + aat->aat_hold = m; + aarpwhohas( ac, destsat ); + splx( s ); + return( 0 ); + } + /* found an entry */ + aat->aat_timer = 0; + if ( aat->aat_flags & ATF_COM ) { /* entry is COMplete */ + bcopy( (caddr_t)aat->aat_enaddr, (caddr_t)desten, + sizeof( aat->aat_enaddr )); + splx( s ); + return( 1 ); + } + /* entry has not completed */ + if ( aat->aat_hold ) { + m_freem( aat->aat_hold ); + } + aat->aat_hold = m; + aarpwhohas( ac, destsat ); + splx( s ); + return( 0 ); +} + +void +aarpinput( ac, m ) + struct arpcom *ac; + struct mbuf *m; +{ + struct arphdr *ar; + + if ( ac->ac_if.if_flags & IFF_NOARP ) + goto out; + + if ( m->m_len < sizeof( struct arphdr )) { + goto out; + } + + ar = mtod( m, struct arphdr *); + if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) { + goto out; + } + + if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln + + 2 * ar->ar_pln ) { + goto out; + } + + switch( ntohs( ar->ar_pro )) { + case ETHERTYPE_AT : + at_aarpinput( ac, m ); + return; + + default: + break; + } + +out: + m_freem( m ); +} + + +static void +at_aarpinput( ac, m ) + struct arpcom *ac; + struct mbuf *m; +{ + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct aarptab *aat; + struct ether_header *eh; + struct llc *llc; + struct sockaddr_at sat; + struct sockaddr sa; + struct at_addr spa, tpa, ma; + int op; + u_int16_t net; + + ea = mtod( m, struct ether_aarp *); + + /* Check to see if from my hardware address */ + if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr, + sizeof( ac->ac_enaddr ))) { + m_freem( m ); + return; + } + + /* + * Check if from broadcast address. This could be a more robust + * check, since we could look for multicasts. XXX + */ + if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )etherbroadcastaddr, + sizeof( etherbroadcastaddr ))) { + log( LOG_ERR, + "aarp: source is broadcast!\n" ); + m_freem( m ); + return; + } + + op = ntohs( ea->aarp_op ); + bcopy( ea->aarp_tpnet, &net, sizeof( net )); + + if ( net != 0 ) { + sat.sat_len = sizeof(struct sockaddr_at); + sat.sat_family = AF_APPLETALK; + sat.sat_addr.s_net = net; + if (( aa = (struct at_ifaddr *)at_ifawithnet( &sat, + ac->ac_if.if_addrlist.tqh_first )) == NULL ) { + m_freem( m ); + return; + } + bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net )); + bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net )); + } else { + /* + * Since we don't know the net, we just look for the first + * phase 1 address on the interface. + */ + for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist.tqh_first; aa; + aa = (struct at_ifaddr *)aa->aa_ifa.ifa_list.tqe_next ) { + if ( AA_SAT( aa )->sat_family == AF_APPLETALK && + ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + if ( aa == NULL ) { + m_freem( m ); + return; + } + tpa.s_net = spa.s_net = AA_SAT( aa )->sat_addr.s_net; + } + + spa.s_node = ea->aarp_spnode; + tpa.s_node = ea->aarp_tpnode; + ma.s_net = AA_SAT( aa )->sat_addr.s_net; + ma.s_node = AA_SAT( aa )->sat_addr.s_node; + + /* + * This looks like it's from us. + */ + if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) { + if ( aa->aa_flags & AFA_PROBING ) { + /* + * We're probing, someone either responded to our probe, or + * probed for the same address we'd like to use. Change the + * address we're probing for. + */ + untimeout( aarpprobe, ac ); + wakeup( aa ); + m_freem( m ); + return; + } else if ( op != AARPOP_PROBE ) { + /* + * This is not a probe, and we're not probing. This means + * that someone's saying they have the same source address + * as the one we're using. Get upset... + */ + /* XXX use ether_ntoa */ + log( LOG_ERR, + "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n", + ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ], + ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]); + m_freem( m ); + return; + } + } + + AARPTAB_LOOK( aat, spa ); + if ( aat ) { + if ( op == AARPOP_PROBE ) { + /* + * Someone's probing for spa, dealocate the one we've got, + * so that if the prober keeps the address, we'll be able + * to arp for him. + */ + aarptfree( aat ); + m_freem( m ); + return; + } + + bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr, + sizeof( ea->aarp_sha )); + aat->aat_flags |= ATF_COM; + if ( aat->aat_hold ) { + sat.sat_len = sizeof(struct sockaddr_at); + sat.sat_family = AF_APPLETALK; + sat.sat_addr = spa; + /* XXX the NULL should be a struct rtentry */ + (*ac->ac_if.if_output)( &ac->ac_if, aat->aat_hold, + (struct sockaddr *)&sat, NULL ); + aat->aat_hold = 0; + } + } + + if ( aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node + && op != AARPOP_PROBE ) { + if ( (aat = aarptnew( &spa ))) { + bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr, + sizeof( ea->aarp_sha )); + aat->aat_flags |= ATF_COM; + } + } + + /* + * Don't respond to responses, and never respond if we're + * still probing. + */ + if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node || + op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) { + m_freem( m ); + return; + } + + bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha, + sizeof( ea->aarp_sha )); + bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha, + sizeof( ea->aarp_sha )); + + /* XXX FreeBSD has an 'XXX' here but no comment as to why. */ + eh = (struct ether_header *)sa.sa_data; + bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost, + sizeof( eh->ether_dhost )); + + if ( aa->aa_flags & AFA_PHASE2 ) { + eh->ether_type = htons( AT_LLC_SIZE + + sizeof( struct ether_aarp )); + M_PREPEND( m, AT_LLC_SIZE, M_DONTWAIT ); + if ( m == NULL ) { + return; + } + llc = mtod( m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); + llc->llc_ether_type = htons( ETHERTYPE_AARP ); + + bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); + bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet )); + } else { + eh->ether_type = htons( ETHERTYPE_AARP ); + } + + ea->aarp_tpnode = ea->aarp_spnode; + ea->aarp_spnode = ma.s_node; + ea->aarp_op = htons( AARPOP_RESPONSE ); + + sa.sa_len = sizeof( struct sockaddr ); + sa.sa_family = AF_UNSPEC; + /* XXX the NULL should be a struct rtentry */ + (*ac->ac_if.if_output)( &ac->ac_if, m, &sa, NULL ); + return; +} + +static void +aarptfree( aat ) + struct aarptab *aat; +{ + + if ( aat->aat_hold ) + m_freem( aat->aat_hold ); + aat->aat_hold = 0; + aat->aat_timer = aat->aat_flags = 0; + aat->aat_ataddr.s_net = 0; + aat->aat_ataddr.s_node = 0; +} + +struct aarptab * +aarptnew( addr ) + struct at_addr *addr; +{ + int n; + int oldest = -1; + struct aarptab *aat, *aato = NULL; + static int first = 1; + + if ( first ) { + first = 0; + timeout( aarptimer, (caddr_t)0, hz ); + } + aat = &aarptab[ AARPTAB_HASH( *addr ) * AARPTAB_BSIZ ]; + for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) { + if ( aat->aat_flags == 0 ) + goto out; + if ( aat->aat_flags & ATF_PERM ) + continue; + if ((int) aat->aat_timer > oldest ) { + oldest = aat->aat_timer; + aato = aat; + } + } + if ( aato == NULL ) + return( NULL ); + aat = aato; + aarptfree( aat ); +out: + aat->aat_ataddr = *addr; + aat->aat_flags = ATF_INUSE; + return( aat ); +} + +void +aarpprobe( arg ) + void *arg; +{ + struct arpcom *ac = (struct arpcom *) arg; + struct mbuf *m; + struct ether_header *eh; + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct llc *llc; + struct sockaddr sa; + + /* + * We need to check whether the output ethernet type should + * be phase 1 or 2. We have the interface that we'll be sending + * the aarp out. We need to find an AppleTalk network on that + * interface with the same address as we're looking for. If the + * net is phase 2, generate an 802.2 and SNAP header. + */ + for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist.tqh_first; aa; + aa = (struct at_ifaddr *)aa->aa_ifa.ifa_list.tqe_next) { + if ( AA_SAT( aa )->sat_family == AF_APPLETALK && + ( aa->aa_flags & AFA_PROBING )) { + break; + } + } + if ( aa == NULL ) { /* serious error XXX */ + printf( "aarpprobe why did this happen?!\n" ); + return; + } + + if ( aa->aa_probcnt <= 0 ) { + aa->aa_flags &= ~AFA_PROBING; + wakeup( aa ); + return; + } else { + timeout( aarpprobe, (caddr_t)ac, hz / 5 ); + } + + if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) { + return; + } + m->m_len = sizeof( *ea ); + m->m_pkthdr.len = sizeof( *ea ); + MH_ALIGN( m, sizeof( *ea )); + + ea = mtod( m, struct ether_aarp *); + bzero((caddr_t)ea, sizeof( *ea )); + + ea->aarp_hrd = htons( AARPHRD_ETHER ); + ea->aarp_pro = htons( ETHERTYPE_AT ); + ea->aarp_hln = sizeof( ea->aarp_sha ); + ea->aarp_pln = sizeof( ea->aarp_spu ); + ea->aarp_op = htons( AARPOP_PROBE ); + bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, + sizeof( ea->aarp_sha )); + + eh = (struct ether_header *)sa.sa_data; + + if ( aa->aa_flags & AFA_PHASE2 ) { + bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, + sizeof( eh->ether_dhost )); + eh->ether_type = htons( AT_LLC_SIZE + + sizeof( struct ether_aarp )); + M_PREPEND( m, AT_LLC_SIZE, M_WAIT ); + llc = mtod( m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); + llc->llc_ether_type = htons( ETHERTYPE_AARP ); + + bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet, + sizeof( ea->aarp_spnet )); + bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet, + sizeof( ea->aarp_tpnet )); + ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node; + } else { + bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, + sizeof( eh->ether_dhost )); + eh->ether_type = htons( ETHERTYPE_AARP ); + ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node; + } + + sa.sa_len = sizeof( struct sockaddr ); + sa.sa_family = AF_UNSPEC; + /* XXX the NULL should be a struct rtentry */ + (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, NULL ); + aa->aa_probcnt--; +} + +void +aarp_clean(void) +{ + struct aarptab *aat; + int i; + + untimeout( aarptimer, 0 ); + for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) { + if ( aat->aat_hold ) { + m_freem( aat->aat_hold ); + } + } +} diff --git a/sys/netatalk/aarp.h b/sys/netatalk/aarp.h new file mode 100644 index 00000000000..565db607a95 --- /dev/null +++ b/sys/netatalk/aarp.h @@ -0,0 +1,106 @@ +/* $OpenBSD: aarp.h,v 1.1 1997/07/23 03:39:51 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#ifndef _NETATALK_AARP_H_ +#define _NETATALK_AARP_H_ + +/* + * This structure is used for both phase 1 and 2. Under phase 1 + * the net is not filled in. It is in phase 2. In both cases, the + * hardware address length is (for some unknown reason) 4. If + * anyone at Apple could program their way out of paper bag, it + * would be 1 and 3 respectively for phase 1 and 2. + */ +union aapa { + u_int8_t ap_pa[4]; + struct ap_node { + u_int8_t an_zero; + u_int8_t an_net[2]; + u_int8_t an_node; + } ap_node; +}; + +struct ether_aarp { + struct arphdr eaa_hdr; + u_int8_t aarp_sha[ 6 ]; + union aapa aarp_spu; + u_int8_t aarp_tha[ 6 ]; + union aapa aarp_tpu; +}; +#define aarp_hrd eaa_hdr.ar_hrd +#define aarp_pro eaa_hdr.ar_pro +#define aarp_hln eaa_hdr.ar_hln +#define aarp_pln eaa_hdr.ar_pln +#define aarp_op eaa_hdr.ar_op +#define aarp_spa aarp_spu.ap_node.an_node +#define aarp_tpa aarp_tpu.ap_node.an_node +#define aarp_spnet aarp_spu.ap_node.an_net +#define aarp_tpnet aarp_tpu.ap_node.an_net +#define aarp_spnode aarp_spu.ap_node.an_node +#define aarp_tpnode aarp_tpu.ap_node.an_node + +struct aarptab { + struct at_addr aat_ataddr; + u_int8_t aat_enaddr[ 6 ]; + u_int8_t aat_timer; + u_int8_t aat_flags; + struct mbuf *aat_hold; +}; + +#define AARPHRD_ETHER 0x0001 + +#define AARPOP_REQUEST 0x01 +#define AARPOP_RESPONSE 0x02 +#define AARPOP_PROBE 0x03 + +#endif /* _NETATALK_AARP_H_ */ diff --git a/sys/netatalk/at.h b/sys/netatalk/at.h new file mode 100644 index 00000000000..62dbf13882e --- /dev/null +++ b/sys/netatalk/at.h @@ -0,0 +1,147 @@ +/* $OpenBSD: at.h,v 1.1 1997/07/23 03:39:51 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#ifndef __AT_HEADER__ +#define __AT_HEADER__ +/* + * Supported protocols + */ +#define ATPROTO_DDP 0 +#define ATPROTO_AARP 254 + +/* + * Ethernet types, for DIX. + * These should really be in some global header file, but we can't + * count on them being there, and it's annoying to patch system files. + */ +#define ETHERTYPE_AT 0x809B /* AppleTalk protocol */ +#define ETHERTYPE_AARP 0x80F3 /* AppleTalk ARP */ + +#define DDP_MAXSZ 587 + +#define AT_LLC_SIZE 8 + +/* + * If ATPORT_FIRST <= Port < ATPORT_RESERVED, + * Port was created by a privileged process. + * If ATPORT_RESERVED <= Port < ATPORT_LAST, + * Port was not necessarily created by a + * privileged process. + */ +#define ATPORT_FIRST 1 +#define ATPORT_RESERVED 128 +#define ATPORT_LAST 255 + +/* + * AppleTalk address. + */ +struct at_addr { + u_int16_t s_net; + u_int8_t s_node; +}; + +#define ATADDR_ANYNET (u_int16_t)0x0000 +#define ATADDR_ANYNODE (u_int8_t)0x00 +#define ATADDR_ANYPORT (u_int8_t)0x00 +#define ATADDR_BCAST (u_int8_t)0xff /* There is no BCAST for NET */ + +struct netrange { + u_int8_t nr_phase; + u_int16_t nr_firstnet; + u_int16_t nr_lastnet; +}; + +/* + * Socket address, AppleTalk style. We keep magic information in the + * zero bytes. There are three types, NONE, CONFIG which has the phase + * and a net range, and IFACE which has the network address of an + * interface. IFACE may be filled in by the client, and is filled in + * by the kernel. + */ +struct sockaddr_at { + u_int8_t sat_len; + u_int8_t sat_family; + u_int8_t sat_port; + struct at_addr sat_addr; + union { + struct netrange r_netrange; + int8_t r_zero[ 8 ]; /* Hide a struct netrange in here */ + } sat_range; +}; + +#define sat_zero sat_range.r_zero + +#ifdef _KERNEL +extern struct domain atalkdomain; +extern struct protosw atalksw[]; +#endif + +#endif __AT_HEADER__ diff --git a/sys/netatalk/at_control.c b/sys/netatalk/at_control.c new file mode 100644 index 00000000000..a10831427a8 --- /dev/null +++ b/sys/netatalk/at_control.c @@ -0,0 +1,650 @@ +/* $OpenBSD: at_control.c,v 1.1 1997/07/23 03:39:51 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/proc.h> + +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#undef s_net +#include <netinet/if_ether.h> +#include <net/if_llc.h> + +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#include <netatalk/aarp.h> +#include <netatalk/phase2.h> +#include <netatalk/at_extern.h> + +#include <dev/rndvar.h> + +int at_control __P(( int, caddr_t, struct ifnet *, struct proc * )); +static int at_scrub __P(( struct ifnet *, struct at_ifaddr * )); +static int at_ifinit __P(( struct ifnet *, struct at_ifaddr *, + struct sockaddr_at * )); +int at_broadcast __P(( struct sockaddr_at * )); + +static int aa_dorangeroute __P((struct ifaddr *, u_int, u_int, int)); +static int aa_addsingleroute __P((struct ifaddr *, struct at_addr *, + struct at_addr *)); +static int aa_delsingleroute __P((struct ifaddr *, struct at_addr *, + struct at_addr *)); +static int aa_dosingleroute __P((struct ifaddr *, struct at_addr *, + struct at_addr *, int, int )); + +# define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \ + (a)->sat_family == (b)->sat_family && \ + (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ + (a)->sat_addr.s_node == (b)->sat_addr.s_node ) + +int +at_control( cmd, data, ifp, p ) + int cmd; + caddr_t data; + struct ifnet *ifp; + struct proc *p; +{ + struct ifreq *ifr = (struct ifreq *)data; + struct sockaddr_at *sat; + struct netrange *nr; + struct at_aliasreq *ifra = (struct at_aliasreq *)data; + struct at_ifaddr *aa0; + struct at_ifaddr *aa = 0; + struct ifaddr *ifa, *ifa0; + + if ( ifp ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp ) break; + } + } + + switch ( cmd ) { + case SIOCAIFADDR: + case SIOCDIFADDR: + if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) { + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) { + break; + } + } + } + if ( cmd == SIOCDIFADDR && aa == 0 ) { + return( EADDRNOTAVAIL ); + } + /*FALLTHROUGH*/ + + case SIOCSIFADDR: + /* + * What a great idea this is: Let's reverse the meaning of + * the return... + */ + if ( suser( p->p_ucred, &p->p_acflag )) { + return( EPERM ); + } + + sat = satosat( &ifr->ifr_addr ); + nr = (struct netrange *)sat->sat_zero; + if ( nr->nr_phase == 1 ) { + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + } else { /* default to phase 2 */ + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { + break; + } + } + } + + if ( ifp == 0 ) + panic( "at_control" ); + + if ( aa == (struct at_ifaddr *) 0 ) { + aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, M_WAITOK); + bzero(aa0, sizeof(struct at_ifaddr)); + + if (( aa = at_ifaddr ) != NULL ) { + /* + * Don't let the loopback be first, since the first + * address is the machine's default address for + * binding. + */ + if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) { + aa = aa0; + aa->aa_next = at_ifaddr; + at_ifaddr = aa; + } else { + for ( ; aa->aa_next; aa = aa->aa_next ) + ; + aa->aa_next = aa0; + } + } else { + at_ifaddr = aa0; + } + + aa = aa0; + + if (( ifa = ifp->if_addrlist.tqh_first ) != NULL ) { + for ( ; ifa->ifa_list.tqe_next; ifa = ifa->ifa_list.tqe_next ) + ; + ifa->ifa_list.tqe_next = (struct ifaddr *)aa; + } else { + ifp->if_addrlist.tqh_first = (struct ifaddr *)aa; + } + + /* FreeBSD found this. Whew */ + aa->aa_ifa.ifa_refcnt++; + + aa->aa_ifa.ifa_addr = (struct sockaddr *)&aa->aa_addr; + aa->aa_ifa.ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; + aa->aa_ifa.ifa_netmask = (struct sockaddr *)&aa->aa_netmask; + + /* + * Set/clear the phase 2 bit. + */ + if ( nr->nr_phase == 1 ) { + aa->aa_flags &= ~AFA_PHASE2; + } else { + aa->aa_flags |= AFA_PHASE2; + } + aa->aa_ifp = ifp; + } else { + at_scrub( ifp, aa ); + } + break; + + case SIOCGIFADDR : + sat = satosat( &ifr->ifr_addr ); + nr = (struct netrange *)sat->sat_zero; + if ( nr->nr_phase == 1 ) { + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + } else { /* default to phase 2 */ + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { + break; + } + } + } + + if ( aa == (struct at_ifaddr *) 0 ) + return( EADDRNOTAVAIL ); + break; + } + + switch ( cmd ) { + case SIOCGIFADDR: + *(struct sockaddr_at *)&ifr->ifr_addr = aa->aa_addr; + + /* from FreeBSD : some cleanups about netranges */ + ((struct netrange *)&sat->sat_zero)->nr_phase + = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; + ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet; + ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet; + break; + + case SIOCSIFADDR: + return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); + + case SIOCAIFADDR: + if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) { + return( 0 ); + } + return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); + + case SIOCDIFADDR: + at_scrub( ifp, aa ); + ifa0 = (struct ifaddr *)aa; + if (( ifa = ifp->if_addrlist.tqh_first ) == ifa0 ) { + ifp->if_addrlist.tqh_first = ifa->ifa_list.tqe_next; + } else { + while ( ifa->ifa_list.tqe_next && + ( ifa->ifa_list.tqe_next != ifa0 )) { + ifa = ifa->ifa_list.tqe_next; + } + if ( ifa->ifa_list.tqe_next ) { + ifa->ifa_list.tqe_next = ifa0->ifa_list.tqe_next; + } else { + panic( "at_control" ); + } + } + + /* FreeBSD */ + IFAFREE(ifa0); + + aa0 = aa; + if ( aa0 == ( aa = at_ifaddr )) { + at_ifaddr = aa->aa_next; + } else { + while ( aa->aa_next && ( aa->aa_next != aa0 )) { + aa = aa->aa_next; + } + if ( aa->aa_next ) { + aa->aa_next = aa0->aa_next; + } else { + panic( "at_control" ); + } + } + + /* FreeBSD */ + IFAFREE(ifa0); + break; + + default: + if ( ifp == 0 || ifp->if_ioctl == 0 ) + return( EOPNOTSUPP ); + return( (*ifp->if_ioctl)( ifp, cmd, data )); + } + return( 0 ); +} + +/* replaced this routine with the one from FreeBSD */ +static int +at_scrub( ifp, aa ) + struct ifnet *ifp; + struct at_ifaddr *aa; +{ + int error; + + if ( aa->aa_flags & AFA_ROUTE ) { + if (ifp->if_flags & IFF_LOOPBACK) { + if ((error = aa_delsingleroute(&aa->aa_ifa, + &aa->aa_addr.sat_addr, + &aa->aa_netmask.sat_addr))) { + return( error ); + } + } else if (ifp->if_flags & IFF_POINTOPOINT) { + if ((error = rtinit( &aa->aa_ifa, RTM_DELETE, RTF_HOST)) != 0) + return( error ); + } else if (ifp->if_flags & IFF_BROADCAST) { + error = aa_dorangeroute(&aa->aa_ifa, + ntohs(aa->aa_firstnet), + ntohs(aa->aa_lastnet), + RTM_DELETE ); + } + aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; + aa->aa_flags &= ~AFA_ROUTE; + } + return( 0 ); +} + +static int +at_ifinit( ifp, aa, sat ) + struct ifnet *ifp; + struct at_ifaddr *aa; + struct sockaddr_at *sat; +{ + struct netrange nr, onr; + struct sockaddr_at oldaddr; + int s = splimp(), error = 0, i, j, netinc, nodeinc, nnets; + u_int16_t net; + + oldaddr = aa->aa_addr; + bzero( AA_SAT( aa ), sizeof( struct sockaddr_at )); + bcopy( sat->sat_zero, &nr, sizeof( struct netrange )); + bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange )); + nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1; + + onr.nr_firstnet = aa->aa_firstnet; + onr.nr_lastnet = aa->aa_lastnet; + aa->aa_firstnet = nr.nr_firstnet; + aa->aa_lastnet = nr.nr_lastnet; + + /* + * We could eliminate the need for a second phase 1 probe (post + * autoconf) if we check whether we're resetting the node. Note + * that phase 1 probes use only nodes, not net.node pairs. Under + * phase 2, both the net and node must be the same. + */ + if ( ifp->if_flags & IFF_LOOPBACK ) { + AA_SAT( aa )->sat_len = sat->sat_len; + AA_SAT( aa )->sat_family = AF_APPLETALK; + AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net; + AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; + } else { + aa->aa_flags |= AFA_PROBING; + AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at); + AA_SAT( aa )->sat_family = AF_APPLETALK; + if ( aa->aa_flags & AFA_PHASE2 ) { + if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { + if ( nnets != 1 ) { + net = ntohs( nr.nr_firstnet ) + + arc4random() % ( nnets - 1 ); + } else { + net = ntohs( nr.nr_firstnet ); + } + } else { + if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) || + ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx(s); + return( EINVAL ); + } + net = ntohs( sat->sat_addr.s_net ); + } + } else { + net = ntohs( sat->sat_addr.s_net ); + } + + if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) { + AA_SAT( aa )->sat_addr.s_node = arc4random(); + } else { + AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; + } + + for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) + + (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) { + AA_SAT( aa )->sat_addr.s_net = htons( net ); + + for ( j = 0, nodeinc = arc4random() | 1; j < 256; + j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) { + if ( AA_SAT( aa )->sat_addr.s_node > 253 || + AA_SAT( aa )->sat_addr.s_node < 1 ) { + continue; + } + aa->aa_probcnt = 10; + /* XXX don't use hz so badly */ + timeout( aarpprobe, (caddr_t)ifp, hz / 5 ); + if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) { + printf( "at_ifinit why did this happen?!\n" ); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx( s ); + return( EINTR ); + } + if (( aa->aa_flags & AFA_PROBING ) == 0 ) { + break; + } + } + if (( aa->aa_flags & AFA_PROBING ) == 0 ) { + break; + } + /* reset node for next network */ + AA_SAT( aa )->sat_addr.s_node = time.tv_sec; + } + + if ( aa->aa_flags & AFA_PROBING ) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx( s ); + return( EADDRINUSE ); + } + } + + if ( ifp->if_ioctl && + ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t) aa ))) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx( s ); + return( error ); + } + + bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); + aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); + aa->aa_netmask.sat_family = AF_APPLETALK; + aa->aa_netmask.sat_addr.s_net = 0xffff; + aa->aa_netmask.sat_addr.s_node = 0; + /* XXX From FreeBSD. Why does it do this? */ + aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); + + /* This block came from FreeBSD too */ + /* + * Initialize broadcast (or remote p2p) address + */ + bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); + aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); + aa->aa_broadaddr.sat_family = AF_APPLETALK; + + aa->aa_ifa.ifa_metric = ifp->if_metric; + if (ifp->if_flags & IFF_BROADCAST) { + aa->aa_broadaddr.sat_addr.s_net = htons(0); + aa->aa_broadaddr.sat_addr.s_node = 0xff; + aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr; + /* add the range of routes needed */ + error = aa_dorangeroute(&aa->aa_ifa, + ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD ); + } + else if (ifp->if_flags & IFF_POINTOPOINT) { + struct at_addr rtaddr, rtmask; + + bzero(&rtaddr, sizeof(rtaddr)); + bzero(&rtmask, sizeof(rtmask)); + /* fill in the far end if we know it here XXX */ + aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_broadaddr; + error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); + } + else if ( ifp->if_flags & IFF_LOOPBACK ) { + struct at_addr rtaddr, rtmask; + + bzero(&rtaddr, sizeof(rtaddr)); + bzero(&rtmask, sizeof(rtmask)); + rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net; + rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node; + rtmask.s_net = 0xffff; + rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */ + error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); + } + + if ( error ) { + at_scrub( ifp, aa ); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx( s ); + return( error ); + } + + aa->aa_ifa.ifa_flags |= IFA_ROUTE; + aa->aa_flags |= AFA_ROUTE; + splx( s ); + return( 0 ); +} + +int +at_broadcast( sat ) + struct sockaddr_at *sat; +{ + struct at_ifaddr *aa; + + if ( sat->sat_addr.s_node != ATADDR_BCAST ) { + return( 0 ); + } + if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { + return( 1 ); + } else { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) && + ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) && + ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) { + return( 1 ); + } + } + } + return( 0 ); +} + +/* Yet another bunch of routines from FreeBSD. Those guys are good */ +/* + * aa_dorangeroute() + * + * Add a route for a range of networks from bot to top - 1. + * Algorithm: + * + * Split the range into two subranges such that the middle + * of the two ranges is the point where the highest bit of difference + * between the two addresses, makes it's transition + * Each of the upper and lower ranges might not exist, or might be + * representable by 1 or more netmasks. In addition, if both + * ranges can be represented by the same netmask, then teh can be merged + * by using the next higher netmask.. + */ + +static int +aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd) +{ + u_int mask1; + struct at_addr addr; + struct at_addr mask; + int error; + + /* + * slight sanity check + */ + if (bot > top) return (EINVAL); + + addr.s_node = 0; + mask.s_node = 0; + /* + * just start out with the lowest boundary + * and keep extending the mask till it's too big. + */ + + while (bot <= top) { + mask1 = 1; + while ((( bot & ~mask1) >= bot) + && (( bot | mask1) <= top)) { + mask1 <<= 1; + mask1 |= 1; + } + mask1 >>= 1; + mask.s_net = htons(~mask1); + addr.s_net = htons(bot); + if(cmd == RTM_ADD) { + error = aa_addsingleroute(ifa,&addr,&mask); + if (error) { + /* XXX clean up? */ + return (error); + } + } else { + error = aa_delsingleroute(ifa,&addr,&mask); + } + bot = (bot | mask1) + 1; + } + return 0; +} + +static int +aa_addsingleroute(struct ifaddr *ifa, + struct at_addr *addr, struct at_addr *mask) +{ + int error; + +#if 0 + printf("aa_addsingleroute: %x.%x mask %x.%x ...\n", + ntohs(addr->s_net), addr->s_node, + ntohs(mask->s_net), mask->s_node); +#endif + + error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP); + if (error) + printf("aa_addsingleroute: error %d\n", error); + return(error); +} + +static int +aa_delsingleroute(struct ifaddr *ifa, + struct at_addr *addr, struct at_addr *mask) +{ + int error; + + error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0); + if (error) + printf("aa_delsingleroute: error %d\n", error); + return(error); +} + +static int +aa_dosingleroute(struct ifaddr *ifa, + struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags) +{ + struct sockaddr_at addr, mask; + + bzero(&addr, sizeof(addr)); + bzero(&mask, sizeof(mask)); + addr.sat_family = AF_APPLETALK; + addr.sat_len = sizeof(struct sockaddr_at); + addr.sat_addr.s_net = at_addr->s_net; + addr.sat_addr.s_node = at_addr->s_node; + mask.sat_family = AF_APPLETALK; + mask.sat_len = sizeof(struct sockaddr_at); + mask.sat_addr.s_net = at_mask->s_net; + mask.sat_addr.s_node = at_mask->s_node; + if (at_mask->s_node) + flags |= RTF_HOST; + return(rtrequest(cmd, (struct sockaddr *) &addr, + (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), + (struct sockaddr *) &mask, flags, NULL)); +} diff --git a/sys/netatalk/at_extern.h b/sys/netatalk/at_extern.h new file mode 100644 index 00000000000..ce02b105e92 --- /dev/null +++ b/sys/netatalk/at_extern.h @@ -0,0 +1,108 @@ +/* $OpenBSD: at_extern.h,v 1.1 1997/07/23 03:39:52 denny Exp $ */ +/* $NetBSD: at_extern.h,v 1.3 1997/04/03 18:38:23 christos Exp $ */ + +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + * This file in particular came from NetBSD. + */ + +#ifndef _NETATALK_AT_EXTERN_H_ +#define _NETATALK_AT_EXTERN_H_ + +struct ifnet; +struct mbuf; +struct sockaddr_at; +struct proc; +struct at_ifaddr; +struct route; +struct socket; + +void atintr __P((void)); +void aarpprobe __P((void *)); +int aarpresolve __P((struct arpcom *, struct mbuf *, + struct sockaddr_at *, u_int8_t *)); +void aarpinput __P((struct arpcom *, struct mbuf *)); +int at_broadcast __P((struct sockaddr_at *)); +void aarp_clean __P((void)); +int at_control __P((int, caddr_t, struct ifnet *, + struct proc *)); +u_int16_t at_cksum __P((struct mbuf *, int)); +int ddp_usrreq __P((struct socket *, int, + struct mbuf *, struct mbuf *, + struct mbuf *)); +void ddp_init __P((void )); +struct ifaddr *at_ifawithnet __P((struct sockaddr_at *, struct ifaddr *)); +int ddp_output __P((struct mbuf *, ...)); +struct ddpcb *ddp_search __P((struct sockaddr_at *, + struct sockaddr_at *, struct at_ifaddr *)); +int ddp_route __P((struct mbuf *, struct route *)); + +#endif /* _NETATALK_AT_EXTERN_H_ */ diff --git a/sys/netatalk/at_proto.c b/sys/netatalk/at_proto.c new file mode 100644 index 00000000000..c133bd422d4 --- /dev/null +++ b/sys/netatalk/at_proto.c @@ -0,0 +1,113 @@ +/* $OpenBSD: at_proto.c,v 1.1 1997/07/23 03:39:52 denny Exp $ */ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/protosw.h> +#include <sys/domain.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#undef s_net +#include <netinet/if_ether.h> + +#include <netatalk/at.h> +#include <netatalk/at_extern.h> + +struct protosw atalksw[] = { + { + /* Identifiers */ + SOCK_DGRAM, &atalkdomain, ATPROTO_DDP, PR_ATOMIC|PR_ADDR, + /* + * protocol-protocol interface. + * fields are pr_input, pr_output, pr_ctlinput, and pr_ctloutput. + * pr_input can be called from the udp protocol stack for iptalk + * packets bound for a local socket. + * pr_output can be used by higher level appletalk protocols, should + * they be included in the kernel. + */ + 0, ddp_output, 0, 0, + /* socket-protocol interface. */ + ddp_usrreq, + /* utility routines. */ + ddp_init, 0, 0, 0, + }, +}; + +struct domain atalkdomain = { + AF_APPLETALK, "appletalk", 0, 0, 0, atalksw, + &atalksw[ sizeof( atalksw ) / sizeof( atalksw[ 0 ] ) ], + 0, rn_inithead, + 8 * (u_long) &((struct sockaddr_at *) 0)->sat_addr, /* dom_rtoffset */ + sizeof(struct sockaddr_at) +}; diff --git a/sys/netatalk/at_var.h b/sys/netatalk/at_var.h new file mode 100644 index 00000000000..849c3fe90b4 --- /dev/null +++ b/sys/netatalk/at_var.h @@ -0,0 +1,113 @@ +/* $OpenBSD: at_var.h,v 1.1 1997/07/23 03:39:52 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#ifndef _NETATALK_AT_VAR_H_ +#define _NETATALK_AT_VAR_H_ 1 + +/* + * For phase2, we need to keep not only our address on an interface, + * but also the legal networks on the interface. + */ +struct at_ifaddr { + struct ifaddr aa_ifa; +# define aa_ifp aa_ifa.ifa_ifp + struct sockaddr_at aa_addr; + struct sockaddr_at aa_broadaddr; + struct sockaddr_at aa_netmask; + int aa_flags; + u_short aa_firstnet, aa_lastnet; + int aa_probcnt; + struct at_ifaddr *aa_next; +}; + +struct at_aliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr_at ifra_addr; + struct sockaddr_at ifra_broadaddr; +#define ifra_dstaddr ifra_broadaddr + struct sockaddr_at ifra_mask; +}; + +#define AA_SAT(aa) \ + ((struct sockaddr_at *)&((struct at_ifaddr *)(aa))->aa_addr) +#define satosat(sa) ((struct sockaddr_at *)(sa)) + +#define AFA_ROUTE 0x0001 +#define AFA_PROBING 0x0002 +#define AFA_PHASE2 0x0004 + +#ifdef _KERNEL +struct at_ifaddr *at_ifaddr; +struct ifqueue atintrq1, atintrq2; +int atdebug; +#endif + +#endif /* _NETATALK_AT_VAR_H_ */ diff --git a/sys/netatalk/ddp.h b/sys/netatalk/ddp.h new file mode 100644 index 00000000000..bdd3e53e147 --- /dev/null +++ b/sys/netatalk/ddp.h @@ -0,0 +1,181 @@ +/* $OpenBSD: ddp.h,v 1.1 1997/07/23 03:39:53 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#ifndef _NETATALK_DDP_H_ +#define _NETATALK_DDP_H_ 1 + +/* + * <-1byte(8bits) -> + * +---------------+ + * | 0 | hopc |len| + * +---------------+ + * | len (cont) | + * +---------------+ + * | | + * +- DDP csum -+ + * | | + * +---------------+ + * | | + * +- Dest NET -+ + * | | + * +---------------+ + * | | + * +- Src NET -+ + * | | + * +---------------+ + * | Dest NODE | + * +---------------+ + * | Src NODE | + * +---------------+ + * | Dest PORT | + * +---------------+ + * | Src PORT | + * +---------------+ + * + * On Apples, there is also a ddp_type field, after src_port. However, + * under this unix implementation, user level processes need to be able + * to set the ddp_type. In later revisions, the ddp_type may only be + * available in a raw_appletalk interface. + */ + +struct elaphdr { + u_char el_dnode; + u_char el_snode; + u_char el_type; +}; + +#define SZ_ELAPHDR 3 + +#define ELAP_DDPSHORT 0x01 +#define ELAP_DDPEXTEND 0x02 + +/* + * Extended DDP header. Includes sickness for dealing with arbitrary + * bitfields on a little-endian arch. + */ +struct ddpehdr { + union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned dub_pad:2; + unsigned dub_hops:4; + unsigned dub_len:10; + unsigned dub_sum:16; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned dub_sum:16; + unsigned dub_len:10; + unsigned dub_hops:4; + unsigned dub_pad:2; +#endif + } du_bits; + unsigned du_bytes; + } deh_u; +#define deh_pad deh_u.du_bits.dub_pad +#define deh_hops deh_u.du_bits.dub_hops +#define deh_len deh_u.du_bits.dub_len +#define deh_sum deh_u.du_bits.dub_sum +#define deh_bytes deh_u.du_bytes + u_short deh_dnet; + u_short deh_snet; + u_char deh_dnode; + u_char deh_snode; + u_char deh_dport; + u_char deh_sport; +}; + +#define DDP_MAXHOPS 15 + +struct ddpshdr { + union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned dub_pad:6; + unsigned dub_len:10; + unsigned dub_dport:8; + unsigned dub_sport:8; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned dub_sport:8; + unsigned dub_dport:8; + unsigned dub_len:10; + unsigned dub_pad:6; +#endif + } du_bits; + unsigned du_bytes; + } dsh_u; +#define dsh_pad dsh_u.du_bits.dub_pad +#define dsh_len dsh_u.du_bits.dub_len +#define dsh_dport dsh_u.du_bits.dub_dport +#define dsh_sport dsh_u.du_bits.dub_sport +#define dsh_bytes dsh_u.du_bytes +}; +#endif /* _NETATALK_DDP_H_ */ diff --git a/sys/netatalk/ddp_input.c b/sys/netatalk/ddp_input.c new file mode 100644 index 00000000000..0cf438f9dbc --- /dev/null +++ b/sys/netatalk/ddp_input.c @@ -0,0 +1,438 @@ +/* $OpenBSD: ddp_input.c,v 1.1 1997/07/23 03:39:53 denny Exp $ */ + +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/proc.h> +#include <sys/socketvar.h> + +#include <net/if.h> +#include <net/route.h> + +#include <machine/endian.h> + +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#include <netatalk/ddp.h> +#include <netatalk/ddp_var.h> +#include <netatalk/at_extern.h> + +void atintr __P((void)); +void ddp_input __P((struct mbuf *, struct ifnet *, + struct elaphdr *, int)); +#if 0 +static void m_printm __P((struct mbuf *)); +static void bprint __P(( char *, int )); +#endif + +int ddp_forward = 1; +int ddp_firewall = 0; +extern int ddp_cksum; + +/* + * Could probably merge these two code segments a little better... + */ +void +atintr() +{ + struct elaphdr *elhp, elh; + struct ifnet *ifp; + struct mbuf *m; + struct at_ifaddr *aa; + int s; + + for (;;) { + s = splimp(); + + IF_DEQUEUE( &atintrq2, m ); + + splx( s ); + + if ( m == 0 ) { /* no more queued packets */ + break; + } + + ifp = m->m_pkthdr.rcvif; + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { + break; + } + } + if ( aa == NULL ) { /* ifp not an appletalk interface */ + m_freem( m ); + continue; + } + + ddp_input( m, ifp, (struct elaphdr *)NULL, 2 ); + } + + for (;;) { + s = splimp(); + + IF_DEQUEUE( &atintrq1, m ); + + splx( s ); + + if ( m == 0 ) { /* no more queued packets */ + break; + } + + ifp = m->m_pkthdr.rcvif; + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + if ( aa == NULL ) { /* ifp not an appletalk interface */ + m_freem( m ); + continue; + } + + if ( m->m_len < SZ_ELAPHDR && + (( m = m_pullup( m, SZ_ELAPHDR )) == 0 )) { + ddpstat.ddps_tooshort++; + continue; + } + + elhp = mtod( m, struct elaphdr *); + m_adj( m, SZ_ELAPHDR ); + + if ( elhp->el_type == ELAP_DDPEXTEND ) { + ddp_input( m, ifp, (struct elaphdr *)NULL, 1 ); + } else { + bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR ); + ddp_input( m, ifp, &elh, 1 ); + } + } + return; +} + +struct route forwro; + +void +ddp_input( m, ifp, elh, phase ) + struct mbuf *m; + struct ifnet *ifp; + struct elaphdr *elh; + int phase; +{ + struct sockaddr_at from, to; + struct ddpshdr *dsh, ddps; + struct at_ifaddr *aa; + struct ddpehdr *deh, ddpe; + struct ddpcb *ddp; + int dlen, mlen; + u_int16_t cksum; + + bzero( (caddr_t)&from, sizeof( struct sockaddr_at )); + if ( elh ) { + ddpstat.ddps_short++; + + if ( m->m_len < sizeof( struct ddpshdr ) && + (( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) { + ddpstat.ddps_tooshort++; + return; + } + + dsh = mtod( m, struct ddpshdr *); + bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr )); + ddps.dsh_bytes = ntohl( ddps.dsh_bytes ); + dlen = ddps.dsh_len; + + to.sat_addr.s_net = 0; + to.sat_addr.s_node = elh->el_dnode; + to.sat_port = ddps.dsh_dport; + from.sat_addr.s_net = 0; + from.sat_addr.s_node = elh->el_snode; + from.sat_port = ddps.dsh_sport; + + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 && + ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || + to.sat_addr.s_node == ATADDR_BCAST )) { + break; + } + } + if ( aa == NULL ) { + m_freem( m ); + return; + } + } else { + ddpstat.ddps_long++; + + if ( m->m_len < sizeof( struct ddpehdr ) && + (( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) { + ddpstat.ddps_tooshort++; + return; + } + + deh = mtod( m, struct ddpehdr *); + bcopy( (caddr_t)deh, (caddr_t)&ddpe, sizeof( struct ddpehdr )); + ddpe.deh_bytes = ntohl( ddpe.deh_bytes ); + dlen = ddpe.deh_len; + + if (( cksum = ddpe.deh_sum ) == 0 ) { + ddpstat.ddps_nosum++; + } + + from.sat_addr.s_net = ddpe.deh_snet; + from.sat_addr.s_node = ddpe.deh_snode; + from.sat_port = ddpe.deh_sport; + to.sat_addr.s_net = ddpe.deh_dnet; + to.sat_addr.s_node = ddpe.deh_dnode; + to.sat_port = ddpe.deh_dport; + + if ( to.sat_addr.s_net == 0 ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) { + continue; + } + if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + continue; + } + if ( aa->aa_ifp == ifp && + ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || + to.sat_addr.s_node == ATADDR_BCAST || + ( ifp->if_flags & IFF_LOOPBACK ))) { + break; + } + } + } else { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( to.sat_addr.s_net == aa->aa_firstnet && + to.sat_addr.s_node == 0 ) { + break; + } + if (( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ) || + ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )) && + ( ntohs( to.sat_addr.s_net ) < ntohs( 0xff00 ) || + ntohs( to.sat_addr.s_net ) > ntohs( 0xfffe ))) { + continue; + } + if ( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node && + to.sat_addr.s_node != ATADDR_BCAST ) { + continue; + } + break; + } + } + } + + /* + * Adjust the length, removing any padding that may have been added + * at a link layer. We do this before we attempt to forward a packet, + * possibly on a different media. + */ + mlen = m->m_pkthdr.len; + if ( mlen < dlen ) { + ddpstat.ddps_toosmall++; + m_freem( m ); + return; + } + if ( mlen > dlen ) { + m_adj( m, dlen - mlen ); + } + + /* + * XXX Should we deliver broadcasts locally, also, or rely on the + * link layer to give us a copy? For the moment, the latter. + */ + if ( aa == NULL || ( to.sat_addr.s_node == ATADDR_BCAST && + aa->aa_ifp != ifp && ( ifp->if_flags & IFF_LOOPBACK ) == 0 )) { + if ( ddp_forward == 0 ) { + m_freem( m ); + return; + } + if ( forwro.ro_rt && ( satosat( &forwro.ro_dst )->sat_addr.s_net != + to.sat_addr.s_net || + satosat( &forwro.ro_dst )->sat_addr.s_node != + to.sat_addr.s_node )) { + RTFREE( forwro.ro_rt ); + forwro.ro_rt = (struct rtentry *)0; + } + if ( forwro.ro_rt == (struct rtentry *)0 || + forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) { + forwro.ro_dst.sa_len = sizeof( struct sockaddr_at ); + forwro.ro_dst.sa_family = AF_APPLETALK; + satosat( &forwro.ro_dst )->sat_addr.s_net = to.sat_addr.s_net; + satosat( &forwro.ro_dst )->sat_addr.s_node = to.sat_addr.s_node; + rtalloc( &forwro ); + } + + if ( to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net && + ddpe.deh_hops == DDP_MAXHOPS ) { + m_freem( m ); + return; + } + + /* XXX FreeBSD doesn't have this */ + if ( ddp_firewall && + ( forwro.ro_rt == NULL || ( forwro.ro_rt->rt_ifp != ifp && + forwro.ro_rt->rt_ifp != at_ifaddr->aa_ifp ))) { + m_freem( m ); + return; + } + + ddpe.deh_hops++; + ddpe.deh_bytes = htonl( ddpe.deh_bytes ); + bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_int16_t )); + if ( ddp_route( m, &forwro )) { + ddpstat.ddps_cantforward++; + } else { + ddpstat.ddps_forward++; + } + return; + } + + from.sat_len = sizeof( struct sockaddr_at ); + from.sat_family = AF_APPLETALK; + + if ( elh ) { + m_adj( m, sizeof( struct ddpshdr )); + } else { + /* + * XXX I've always hated this about the TCP checksum, and here it + * is again. ddp_cksum determines whether we compute checksums on + * outgoing packets. Why is it used to disable checkumming on + * incoming packets as well? If the remote node went to the + * trouble of computing the checksum, shouldn't we check it? + */ + if ( ddp_cksum && cksum && cksum != at_cksum( m, sizeof( int ))) { + ddpstat.ddps_badsum++; + m_freem( m ); + return; + } + m_adj( m, sizeof( struct ddpehdr )); + } + + if (( ddp = ddp_search( &from, &to, aa )) == NULL ) { + m_freem( m ); + return; + } + + if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from, + m, (struct mbuf *)0 ) == 0 ) { + ddpstat.ddps_nosockspace++; + m_freem( m ); + return; + } + sorwakeup( ddp->ddp_socket ); +} + +#if 0 +static void +m_printm( m ) + struct mbuf *m; +{ + for (; m; m = m->m_next ) { + bprint( mtod( m, char * ), m->m_len ); + } +} + +#define BPXLEN 48 +#define BPALEN 16 +char hexdig[] = "0123456789ABCDEF"; + +static void +bprint( data, len ) + char *data; + int len; +{ + char xout[ BPXLEN ], aout[ BPALEN ]; + int i = 0; + + bzero( xout, BPXLEN ); + bzero( aout, BPALEN ); + + for ( ;; ) { + if ( len < 1 ) { + if ( i != 0 ) { + printf( "%s\t%s\n", xout, aout ); + } + printf( "%s\n", "(end)" ); + break; + } + + xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ]; + xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ]; + + if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) { + aout[ i ] = *data; + } else { + aout[ i ] = '.'; + } + + xout[ (i*3) + 2 ] = ' '; + + i++; + len--; + data++; + + if ( i > BPALEN - 2 ) { + printf( "%s\t%s\n", xout, aout ); + bzero( xout, BPXLEN ); + bzero( aout, BPALEN ); + i = 0; + continue; + } + } +} +#endif diff --git a/sys/netatalk/ddp_output.c b/sys/netatalk/ddp_output.c new file mode 100644 index 00000000000..5e75c985881 --- /dev/null +++ b/sys/netatalk/ddp_output.c @@ -0,0 +1,250 @@ +/* $OpenBSD: ddp_output.c,v 1.1 1997/07/23 03:39:54 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/syslog.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#undef s_net +#include <netinet/if_ether.h> + +#include <machine/endian.h> + +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#include <netatalk/ddp.h> +#include <netatalk/ddp_var.h> +#include <netatalk/at_extern.h> + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +int ddp_output __P(( struct mbuf *, ... )); +u_int16_t at_cksum __P(( struct mbuf *, int )); +int ddp_route __P((struct mbuf *, struct route * )); + +int ddp_cksum = 1; + +int +#if __STDC__ +ddp_output(struct mbuf *m, ...) +#else +ddp_output(m, va_alist) + struct mbuf *m; + va_dcl +#endif +{ + struct ddpcb *ddp; + struct ddpehdr *deh; + va_list ap; + + va_start(ap, m); + ddp = va_arg(ap, struct ddpcb *); + va_end(ap); + + M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT ); + + deh = mtod( m, struct ddpehdr *); + deh->deh_pad = 0; + deh->deh_hops = 0; + + deh->deh_len = m->m_pkthdr.len; + + deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; + deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; + deh->deh_dport = ddp->ddp_fsat.sat_port; + deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; + deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; + deh->deh_sport = ddp->ddp_lsat.sat_port; + + /* + * The checksum calculation is done after all of the other bytes have + * been filled in. + */ + if ( ddp_cksum ) { + deh->deh_sum = at_cksum( m, sizeof( int )); + } else { + deh->deh_sum = 0; + } + deh->deh_bytes = htonl( deh->deh_bytes ); + + return( ddp_route( m, &ddp->ddp_route )); +} + +u_int16_t +at_cksum( m, skip ) + struct mbuf *m; + int skip; +{ + u_int8_t *data, *end; + u_long cksum = 0; + + for (; m; m = m->m_next ) { + for ( data = mtod( m, u_int8_t * ), end = data + m->m_len; data < end; + data++ ) { + if ( skip ) { + skip--; + continue; + } + cksum = ( cksum + *data ) << 1; + if ( cksum & 0x00010000 ) { + cksum++; + } + cksum &= 0x0000ffff; + } + } + + if ( cksum == 0 ) { + cksum = 0x0000ffff; + } + return( (u_int16_t)cksum ); +} + +int +ddp_route( m, ro ) + struct mbuf *m; + struct route *ro; +{ + struct sockaddr_at gate; + struct elaphdr *elh; + struct mbuf *m0; + struct at_ifaddr *aa = NULL; + struct ifnet *ifp; + u_int16_t net; + + if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { + net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net; + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ntohs( net ) >= ntohs( aa->aa_firstnet ) && + ntohs( net ) <= ntohs( aa->aa_lastnet )) { + break; + } + } + } + if ( aa == NULL ) { + m_freem( m ); + return( EINVAL ); + } + + /* + * There are several places in the kernel where data is added to + * an mbuf without ensuring that the mbuf pointer is aligned. + * This is bad for transition routing, since phase 1 and phase 2 + * packets end up poorly aligned due to the three byte elap header. + */ + if ( aa->aa_flags & AFA_PHASE2 ) { + if (( m = m_pullup( m, MIN( MHLEN, m->m_pkthdr.len ))) == 0 ) { + return( ENOBUFS ); + } + } else { + MGET( m0, M_WAIT, MT_HEADER ); + if ( m0 == 0 ) { + m_freem( m ); + return( ENOBUFS ); + } + m0->m_next = m; + m0->m_len = SZ_ELAPHDR; + m = m0; + + elh = mtod( m, struct elaphdr *); + elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node; + elh->el_type = ELAP_DDPEXTEND; + if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node; + } else { + elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node; + } + } + + if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + gate = *satosat( &ro->ro_dst ); + } else { + gate = *satosat( ro->ro_rt->rt_gateway ); + } + ro->ro_rt->rt_use++; + + /* XXX The NULL should be a struct rtentry */ + return((*ifp->if_output)( ifp, m, (struct sockaddr *) &gate, NULL )); +} diff --git a/sys/netatalk/ddp_usrreq.c b/sys/netatalk/ddp_usrreq.c new file mode 100644 index 00000000000..6c6dac6970e --- /dev/null +++ b/sys/netatalk/ddp_usrreq.c @@ -0,0 +1,580 @@ +/* $OpenBSD: ddp_usrreq.c,v 1.1 1997/07/23 03:39:54 denny Exp $ */ + +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <net/if.h> +#include <net/route.h> + +#include <machine/endian.h> + +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#include <netatalk/ddp_var.h> +#include <netatalk/at_extern.h> + +int ddp_usrreq __P((struct socket *, int, struct mbuf *, + struct mbuf *, struct mbuf * )); +static void at_sockaddr __P(( struct ddpcb *, struct mbuf * )); +static int at_pcbsetaddr __P(( struct ddpcb *, struct mbuf *, + struct proc * )); +static int at_pcbconnect __P(( struct ddpcb *, struct mbuf *, + struct proc *)); +static void at_pcbdisconnect __P(( struct ddpcb * )); +static int at_pcballoc __P(( struct socket * )); +static void at_pcbdetach __P(( struct socket *, struct ddpcb * )); +struct ddpcb *ddp_search __P(( struct sockaddr_at *, + struct sockaddr_at *, struct at_ifaddr * )); +void ddp_init __P((void)); + +struct ddpcb *ddpcb = NULL; +u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ +u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at )); + +/*ARGSUSED*/ +int +ddp_usrreq( so, req, m, addr, rights ) + struct socket *so; + int req; + struct mbuf *m, *addr, *rights; +{ + /* XXX Need to pass p into this routine */ + struct proc *p = curproc; + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb( so ); + + if ( req == PRU_CONTROL ) { + return( at_control( (int) m, (caddr_t) addr, + (struct ifnet *) rights, p )); + } + + if ( rights && rights->m_len ) { + error = EINVAL; + goto release; + } + + if ( ddp == NULL && req != PRU_ATTACH ) { + error = EINVAL; + goto release; + } + + switch ( req ) { + case PRU_ATTACH : + if ( ddp != NULL ) { + error = EINVAL; + break; + } + if (( error = at_pcballoc( so )) != 0 ) { + break; + } + error = soreserve( so, ddp_sendspace, ddp_recvspace ); + break; + + case PRU_DETACH : + at_pcbdetach( so, ddp ); + break; + + case PRU_BIND : + error = at_pcbsetaddr( ddp, addr, p ); + break; + + case PRU_SOCKADDR : + at_sockaddr( ddp, addr ); + break; + + case PRU_CONNECT: + if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { + error = EISCONN; + break; + } + + error = at_pcbconnect( ddp, addr, p ); + if ( error == 0 ) + soisconnected( so ); + break; + + case PRU_DISCONNECT: + if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) { + error = ENOTCONN; + break; + } + at_pcbdisconnect( ddp ); + soisdisconnected( so ); + break; + + case PRU_SHUTDOWN: + socantsendmore( so ); + break; + + case PRU_SEND: { + int s; + + if ( addr ) { + if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { + error = EISCONN; + break; + } + + s = splnet(); + error = at_pcbconnect( ddp, addr, p ); + if ( error ) { + splx( s ); + break; + } + } else { + if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) { + error = ENOTCONN; + break; + } + } + + error = ddp_output( m, ddp ); + m = NULL; + if ( addr ) { + at_pcbdisconnect( ddp ); + splx( s ); + } + } + break; + + case PRU_ABORT: + soisdisconnected( so ); + at_pcbdetach( so, ddp ); + break; + + case PRU_LISTEN: + case PRU_CONNECT2: + case PRU_ACCEPT: + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + /* + * Don't mfree. Good architecture... + */ + return( EOPNOTSUPP ); + + case PRU_SENSE: + /* + * 1. Don't return block size. + * 2. Don't mfree. + */ + return( 0 ); + + default: + error = EOPNOTSUPP; + } + +release: + if ( m != NULL ) { + m_freem( m ); + } + return( error ); +} + +static void +at_sockaddr( ddp, addr ) + struct ddpcb *ddp; + struct mbuf *addr; +{ + struct sockaddr_at *sat; + + addr->m_len = sizeof( struct sockaddr_at ); + sat = mtod( addr, struct sockaddr_at *); + *sat = ddp->ddp_lsat; +} + +static int +at_pcbsetaddr( ddp, addr, p ) + struct ddpcb *ddp; + struct mbuf *addr; + struct proc *p; +{ + struct sockaddr_at lsat, *sat; + struct at_ifaddr *aa; + struct ddpcb *ddpp; + + if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */ + return( EINVAL ); + } + + if ( addr != 0 ) { /* validate passed address */ + sat = mtod( addr, struct sockaddr_at *); + if ( addr->m_len != sizeof( *sat )) { + return( EINVAL ); + } + if ( sat->sat_family != AF_APPLETALK ) { + return( EAFNOSUPPORT ); + } + + if ( sat->sat_addr.s_node != ATADDR_ANYNODE || + sat->sat_addr.s_net != ATADDR_ANYNET ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && + ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { + break; + } + } + if ( !aa ) { + return( EADDRNOTAVAIL ); + } + } + + if ( sat->sat_port != ATADDR_ANYPORT ) { + if ( sat->sat_port < ATPORT_FIRST || + sat->sat_port >= ATPORT_LAST ) { + return( EINVAL ); + } + if ( sat->sat_port < ATPORT_RESERVED && + suser( p->p_ucred, &p->p_acflag )) { + return( EACCES ); + } + } + } else { + bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); + lsat.sat_family = AF_APPLETALK; + sat = &lsat; + } + + if ( sat->sat_addr.s_node == ATADDR_ANYNODE && + sat->sat_addr.s_net == ATADDR_ANYNET ) { + if ( at_ifaddr == NULL ) { + return( EADDRNOTAVAIL ); + } + sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr; + } + ddp->ddp_lsat = *sat; + + /* + * Choose port. + */ + if ( sat->sat_port == ATADDR_ANYPORT ) { + for ( sat->sat_port = ATPORT_RESERVED; + sat->sat_port < ATPORT_LAST; sat->sat_port++ ) { + if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) { + break; + } + } + if ( sat->sat_port == ATPORT_LAST ) { + return( EADDRNOTAVAIL ); + } + ddp->ddp_lsat.sat_port = sat->sat_port; + ddp_ports[ sat->sat_port - 1 ] = ddp; + } else { + for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; + ddpp = ddpp->ddp_pnext ) { + if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && + ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) { + break; + } + } + if ( ddpp != NULL ) { + return( EADDRINUSE ); + } + ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; + ddp_ports[ sat->sat_port - 1 ] = ddp; + if ( ddp->ddp_pnext ) { + ddp->ddp_pnext->ddp_pprev = ddp; + } + } + + return( 0 ); +} + +static int +at_pcbconnect( ddp, addr, p ) + struct ddpcb *ddp; + struct mbuf *addr; + struct proc *p; +{ + struct sockaddr_at *sat = mtod( addr, struct sockaddr_at *); + struct route *ro; + struct at_ifaddr *aa = 0; + struct ifnet *ifp; + u_int16_t hintnet = 0, net; + + if ( addr->m_len != sizeof( *sat )) + return( EINVAL ); + if ( sat->sat_family != AF_APPLETALK ) { + return( EAFNOSUPPORT ); + } + + /* + * Under phase 2, network 0 means "the network". We take "the + * network" to mean the network the control block is bound to. + * If the control block is not bound, there is an error. + */ + if ( sat->sat_addr.s_net == 0 && sat->sat_addr.s_node != ATADDR_ANYNODE ) { + if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { + return( EADDRNOTAVAIL ); + } + hintnet = ddp->ddp_lsat.sat_addr.s_net; + } + + ro = &ddp->ddp_route; + /* + * If we've got an old route for this pcb, check that it is valid. + * If we've changed our address, we may have an old "good looking" + * route here. Attempt to detect it. + */ + if ( ro->ro_rt ) { + if ( hintnet ) { + net = hintnet; + } else { + net = sat->sat_addr.s_net; + } + aa = 0; + if ( (ifp = ro->ro_rt->rt_ifp) != NULL ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ntohs( net ) >= ntohs( aa->aa_firstnet ) && + ntohs( net ) <= ntohs( aa->aa_lastnet )) { + break; + } + } + } + if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net != + ( hintnet ? hintnet : sat->sat_addr.s_net ) || + satosat( &ro->ro_dst )->sat_addr.s_node != + sat->sat_addr.s_node )) { + RTFREE( ro->ro_rt ); + ro->ro_rt = (struct rtentry *)0; + } + } + + /* + * If we've got no route for this interface, try to find one. + */ + if ( ro->ro_rt == (struct rtentry *)0 || + ro->ro_rt->rt_ifp == (struct ifnet *)0 ) { + ro->ro_dst.sa_len = sizeof( struct sockaddr_at ); + ro->ro_dst.sa_family = AF_APPLETALK; + if ( hintnet != 0 ) { + satosat( &ro->ro_dst )->sat_addr.s_net = hintnet; + } else { + satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net; + } + satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node; + rtalloc( ro ); + } + + /* + * Make sure any route that we have has a valid interface. + */ + aa = 0; + if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp ) { + break; + } + } + } + if ( aa == 0 ) { + return( ENETUNREACH ); + } + + ddp->ddp_fsat = *sat; + if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { + return( at_pcbsetaddr( ddp, (struct mbuf *)0, p )); + } + return( 0 ); +} + +static void +at_pcbdisconnect( ddp ) + struct ddpcb *ddp; +{ + ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; + ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; + ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; +} + +static int +at_pcballoc( so ) + struct socket *so; +{ + struct ddpcb *ddp; + struct mbuf *m; + + m = m_getclr( M_WAIT, MT_PCB ); + ddp = mtod( m, struct ddpcb * ); + ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; + + ddp->ddp_next = ddpcb; + ddp->ddp_prev = NULL; + ddp->ddp_pprev = NULL; + ddp->ddp_pnext = NULL; + if ( ddpcb ) { + ddpcb->ddp_prev = ddp; + } + ddpcb = ddp; + + ddp->ddp_socket = so; + so->so_pcb = (caddr_t)ddp; + return( 0 ); +} + +static void +at_pcbdetach( so, ddp ) + struct socket *so; + struct ddpcb *ddp; +{ + soisdisconnected( so ); + so->so_pcb = 0; + sofree( so ); + + /* remove ddp from ddp_ports list */ + if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && + ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) { + if ( ddp->ddp_pprev != NULL ) { + ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; + } else { + ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext; + } + if ( ddp->ddp_pnext != NULL ) { + ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; + } + } + + if ( ddp->ddp_route.ro_rt ) { + rtfree( ddp->ddp_route.ro_rt ); + } + + if ( ddp->ddp_prev ) { + ddp->ddp_prev->ddp_next = ddp->ddp_next; + } else { + ddpcb = ddp->ddp_next; + } + if ( ddp->ddp_next ) { + ddp->ddp_next->ddp_prev = ddp->ddp_prev; + } + + (void) m_free( dtom( ddp )); +} + +/* + * For the moment, this just find the pcb with the correct local address. + * In the future, this will actually do some real searching, so we can use + * the sender's address to do de-multiplexing on a single port to many + * sockets (pcbs). + */ +struct ddpcb * +ddp_search( from, to, aa ) + struct sockaddr_at *from, *to; + struct at_ifaddr *aa; +{ + struct ddpcb *ddp; + + /* + * Check for bad ports. + */ + if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) { + return( NULL ); + } + + /* + * Make sure the local address matches the sent address. What about + * the interface? + */ + for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) { + /* XXX should we handle 0.YY? */ + + /* XXXX.YY to socket on destination interface */ + if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && + to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) { + break; + } + + /* 0.255 to socket on receiving interface */ + if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 || + to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) && + ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) { + break; + } + + /* XXXX.0 to socket on destination interface */ + if ( to->sat_addr.s_net == aa->aa_firstnet && + to->sat_addr.s_node == 0 && + ntohs( ddp->ddp_lsat.sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( ddp->ddp_lsat.sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + break; + } + } + return( ddp ); +} + +void +ddp_init() +{ + atintrq1.ifq_maxlen = IFQ_MAXLEN; + atintrq2.ifq_maxlen = IFQ_MAXLEN; +} diff --git a/sys/netatalk/ddp_var.h b/sys/netatalk/ddp_var.h new file mode 100644 index 00000000000..5fb6a99ab3d --- /dev/null +++ b/sys/netatalk/ddp_var.h @@ -0,0 +1,84 @@ +/* $OpenBSD: ddp_var.h,v 1.1 1997/07/23 03:39:54 denny Exp $ */ + +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#ifndef _NETATALK_DDP_VAR_H_ +#define _NETATALK_DDP_VAR_H_ +struct ddpcb { + struct sockaddr_at ddp_fsat, ddp_lsat; + struct route ddp_route; + struct socket *ddp_socket; + struct ddpcb *ddp_prev, *ddp_next; + struct ddpcb *ddp_pprev, *ddp_pnext; +}; + +#define sotoddpcb(so) ((struct ddpcb *)(so)->so_pcb) + +struct ddpstat { + u_long ddps_short; /* short header packets received */ + u_long ddps_long; /* long header packets received */ + u_long ddps_nosum; /* no checksum */ + u_long ddps_badsum; /* bad checksum */ + u_long ddps_tooshort; /* packet too short */ + u_long ddps_toosmall; /* not enough data */ + u_long ddps_forward; /* packets forwarded */ + u_long ddps_cantforward; /* packets rcvd for unreachable dest */ + u_long ddps_nosockspace; /* no space in sockbuf for packet */ +}; + +#ifdef _KERNEL +struct ddpcb *ddp_ports[ ATPORT_LAST ]; +struct ddpcb *ddpcb; +struct ddpstat ddpstat; +#endif + +#endif /* _NETATALK_DDP_VAR_H_ */ diff --git a/sys/netatalk/endian.h b/sys/netatalk/endian.h new file mode 100644 index 00000000000..0de2c02c863 --- /dev/null +++ b/sys/netatalk/endian.h @@ -0,0 +1 @@ +#include <machine/endian.h> diff --git a/sys/netatalk/phase2.h b/sys/netatalk/phase2.h new file mode 100644 index 00000000000..5111557ed40 --- /dev/null +++ b/sys/netatalk/phase2.h @@ -0,0 +1,64 @@ +/* $OpenBSD: phase2.h,v 1.1 1997/07/23 03:39:55 denny Exp $ */ + +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +/* + * The following is the contents of the COPYRIGHT file from the + * netatalk-1.4a2 distribution, from which this file is derived. + */ +/* + * Copyright (c) 1990,1996 Regents of The University of Michigan. + * + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Solaris code is encumbered by the following: + * + * Copyright (C) 1996 by Sun Microsystems Computer Co. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation. This software is + * provided "as is" without express or implied warranty. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ +/* + * None of the Solaris code mentioned is included in OpenBSD. + * This code also relies heavily on previous effort in FreeBSD and NetBSD. + */ + +#ifndef _NETATALK_PHASE2_H_ +#define _NETATALK_PHASE2_H_ + +/* XXX Should these two go in <net/if_llc.h> ? */ +#define llc_org_code llc_un.type_snap.org_code +#define llc_ether_type llc_un.type_snap.ether_type + +#define SIOCPHASE1 _IOW('i', 100, struct ifreq) /* AppleTalk phase 1 */ +#define SIOCPHASE2 _IOW('i', 101, struct ifreq) /* AppleTalk phase 2 */ + +#endif /* _NETATALK_PHASE2_H_ */ |