summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authordenny <denny@cvs.openbsd.org>1997-07-23 03:39:56 +0000
committerdenny <denny@cvs.openbsd.org>1997-07-23 03:39:56 +0000
commitd5b5fef1bdafdd83fef5c12b6377d14969833223 (patch)
tree1ad3ced51a31c06338a1a898f59a19ea3ec76764 /sys
parente3f1ae5edbe93df49723a93fe383d3b3d2282221 (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/COPYRIGHT34
-rw-r--r--sys/netatalk/aarp.c695
-rw-r--r--sys/netatalk/aarp.h106
-rw-r--r--sys/netatalk/at.h147
-rw-r--r--sys/netatalk/at_control.c650
-rw-r--r--sys/netatalk/at_extern.h108
-rw-r--r--sys/netatalk/at_proto.c113
-rw-r--r--sys/netatalk/at_var.h113
-rw-r--r--sys/netatalk/ddp.h181
-rw-r--r--sys/netatalk/ddp_input.c438
-rw-r--r--sys/netatalk/ddp_output.c250
-rw-r--r--sys/netatalk/ddp_usrreq.c580
-rw-r--r--sys/netatalk/ddp_var.h84
-rw-r--r--sys/netatalk/endian.h1
-rw-r--r--sys/netatalk/phase2.h64
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_ */