Obtained from: netatalk distribution netatalk@itd.umich.edu

Kernel Appletalk protocol support
both CAP and netatalk can make use of this..
still needs some owrk but  it seemd the right tiime to commit it
so other can experiment.
This commit is contained in:
Julian Elischer 1996-05-24 01:35:45 +00:00
parent f66e235a13
commit 655929bfba
20 changed files with 4312 additions and 8 deletions

View File

@ -156,6 +156,13 @@ net/rtsock.c standard
net/slcompress.c optional ppp
net/slcompress.c optional sl
net/if_tun.c optional tun
netatalk/aarp.c optional netatalk
netatalk/at_control.c optional netatalk
netatalk/at_proto.c optional netatalk
netatalk/at_rmx.c optional netatalkdebug
netatalk/ddp_input.c optional netatalk
netatalk/ddp_output.c optional netatalk
netatalk/ddp_usrreq.c optional netatalk
#netccitt/ccitt_proto.c optional ccitt
#netccitt/hd_debug.c optional hdlc
#netccitt/hd_input.c optional hdlc

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
* $Id: if_ethersubr.c,v 1.14 1996/01/24 21:09:06 phk Exp $
* $Id: if_ethersubr.c,v 1.15 1996/04/07 17:39:03 bde Exp $
*/
#include <sys/param.h>
@ -76,15 +76,27 @@
#include <netiso/iso_snpac.h>
#endif
#ifdef LLC
/*#ifdef LLC
#include <netccitt/dll.h>
#include <netccitt/llc_var.h>
#endif
#endif*/
#if defined(LLC) && defined(CCITT)
extern struct ifqueue pkintrq;
#endif
#ifdef NETATALK
#include <netatalk/at.h>
#include <netatalk/at_var.h>
#include <netatalk/at_extern.h>
#define llc_snap_org_code llc_un.type_snap.org_code
#define llc_snap_ether_type llc_un.type_snap.ether_type
extern u_char at_org_code[ 3 ];
extern u_char aarp_org_code[ 3 ];
#endif NETATALK
u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#define senderr(e) { error = (e); goto bad;}
@ -111,6 +123,9 @@ ether_output(ifp, m0, dst, rt0)
register struct ether_header *eh;
int off, len = m->m_pkthdr.len;
struct arpcom *ac = (struct arpcom *)ifp;
#ifdef NETATALK
struct at_ifaddr *aa;
#endif NETATALK
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
senderr(ENETDOWN);
@ -165,6 +180,44 @@ ether_output(ifp, m0, dst, rt0)
mcopy = m_copy(m, 0, (int)M_COPYALL);
break;
#endif
#ifdef NETATALK
case AF_APPLETALK:
if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) {
#ifdef NETATALKDEBUG
extern char *prsockaddr(struct sockaddr *);
printf("aarpresolv: failed for %s\n", prsockaddr(dst));
#endif NETATALKDEBUG
return (0);
}
/*
* ifaddr is the first thing in at_ifaddr
*/
if ((aa = (struct at_ifaddr *)at_ifawithnet(
(struct sockaddr_at *)dst, ifp->if_addrlist))
== 0)
goto bad;
/*
* In the phase 2 case, we need to prepend an mbuf for the llc header.
* Since we must preserve the value of m, which is passed to us by
* value, we m_copy() the first mbuf, and use it for our llc header.
*/
if ( aa->aa_flags & AFA_PHASE2 ) {
struct llc llc;
M_PREPEND(m, sizeof(struct llc), M_WAIT);
len += sizeof(struct llc);
llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
llc.llc_control = LLC_UI;
bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code));
llc.llc_snap_ether_type = htons( ETHERTYPE_AT );
bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc));
type = m->m_pkthdr.len;
} else {
type = ETHERTYPE_AT;
}
break;
#endif NETATALK
#ifdef NS
case AF_NS:
type = ETHERTYPE_NS;
@ -371,12 +424,51 @@ ether_input(ifp, eh, m)
inq = &nsintrq;
break;
#endif
#ifdef NETATALK
case ETHERTYPE_AT:
schednetisr(NETISR_ATALK);
inq = &atintrq1;
break;
case ETHERTYPE_AARP:
/* probably this should be done with a NETISR as well */
aarpinput((struct arpcom *)ifp, m); /* XXX */
return;
#endif NETATALK
default:
#if defined (ISO) || defined (LLC)
#if defined (ISO) || defined (LLC) || defined(NETATALK)
if (ether_type > ETHERMTU)
goto dropanyway;
l = mtod(m, struct llc *);
switch (l->llc_dsap) {
#ifdef NETATALK
case LLC_SNAP_LSAP:
switch (l->llc_control) {
case LLC_UI:
if (l->llc_ssap != LLC_SNAP_LSAP)
goto dropanyway;
if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code,
sizeof(at_org_code)) == 0 &&
ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) {
inq = &atintrq2;
m_adj( m, sizeof( struct llc ));
schednetisr(NETISR_ATALK);
break;
}
if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code,
sizeof(aarp_org_code)) == 0 &&
ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) {
m_adj( m, sizeof( struct llc ));
aarpinput((struct arpcom *)ifp, m); /* XXX */
return;
}
default:
goto dropanyway;
}
break;
#endif NETATALK
#ifdef ISO
case LLC_ISO_LSAP:
switch (l->llc_control) {
@ -469,10 +561,10 @@ ether_input(ifp, eh, m)
m_freem(m);
return;
}
#else /* ISO || LLC */
#else /* ISO || LLC || NETATALK */
m_freem(m);
return;
#endif /* ISO || LLC */
#endif /* ISO || LLC || NETATALK */
}
s = splimp();

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if_loop.c 8.1 (Berkeley) 6/10/93
* $Id: if_loop.c,v 1.18 1996/02/06 18:51:11 wollman Exp $
* $Id: if_loop.c,v 1.19 1996/04/07 17:39:06 bde Exp $
*/
/*
@ -77,6 +77,12 @@
#include <netiso/iso_var.h>
#endif
#ifdef NETATALK
#include <netinet/if_ether.h>
#include <netatalk/at.h>
#include <netatalk/at_var.h>
#endif NETATALK
#include "bpfilter.h"
static int loioctl __P((struct ifnet *, int, caddr_t));
@ -194,6 +200,12 @@ looutput(ifp, m, dst, rt)
isr = NETISR_ISO;
break;
#endif
#ifdef NETATALK
case AF_APPLETALK:
ifq = &atintrq2;
isr = NETISR_ATALK;
break;
#endif NETATALK
default:
printf("lo%d: can't handle af%d\n", ifp->if_unit,
dst->sa_family);

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)netisr.h 8.1 (Berkeley) 6/10/93
* $Id: netisr.h,v 1.7 1995/10/26 20:30:22 julian Exp $
* $Id: netisr.h,v 1.8 1995/10/31 19:07:49 peter Exp $
*/
#ifndef _NET_NETISR_H_
@ -61,6 +61,7 @@
#define NETISR_NS 6 /* same as AF_NS */
#define NETISR_ISO 7 /* same as AF_ISO */
#define NETISR_CCITT 10 /* same as AF_CCITT */
#define NETISR_ATALK 16 /* same as AF_APPLETALK */
#define NETISR_ARP 18 /* same as AF_LINK */
#define NETISR_IPX 23 /* same as AF_IPX */
#define NETISR_ISDN 26 /* same as AF_E164 */

816
sys/netatalk/aarp.c Normal file
View File

@ -0,0 +1,816 @@
/*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*/
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/param.h>
#if defined( __FreeBSD__ )
#include <machine/endian.h>
#include <sys/systm.h>
#include <sys/proc.h>
#endif
#include <sys/mbuf.h>
#include <sys/time.h>
#ifndef _IBMR2
#include <sys/kernel.h>
#endif _IBMR2
#include <net/if.h>
#include <net/route.h>
#if !defined( __FreeBSD__ )
#include <net/af.h>
#endif
#include <netinet/in.h>
#undef s_net
#include <netinet/if_ether.h>
#ifdef _IBMR2
#include <netinet/in_netarp.h>
#include <net/spl.h>
#include <sys/errno.h>
#include <sys/err_rec.h>
#endif _IBMR2
#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 aarptfree( struct aarptab *aat);
static void at_aarpinput( struct arpcom *ac, struct mbuf *m);
#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
#ifdef sun
extern struct ether_addr etherbroadcastaddr;
#else sun
# if !defined( __FreeBSD__ )
extern u_char etherbroadcastaddr[6];
# endif __FreeBSD__
#endif sun
u_char atmulticastaddr[ 6 ] = {
0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
};
u_char at_org_code[ 3 ] = {
0x08, 0x00, 0x07,
};
u_char aarp_org_code[ 3 ] = {
0x00, 0x00, 0x00,
};
static void
aarptimer(void *ignored)
{
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 at_ifaddr *aa;
for (; ifa; ifa = ifa->ifa_next ) {
#ifdef BSD4_4
if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) {
continue;
}
if ( satosat( ifa->ifa_addr )->sat_addr.s_net ==
sat->sat_addr.s_net ) {
break;
}
#else BSD4_4
if ( ifa->ifa_addr.sa_family != AF_APPLETALK ) {
continue;
}
aa = (struct at_ifaddr *)ifa;
if ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) &&
ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet )) {
break;
}
#endif BSD4_4
}
return( ifa );
}
static void
aarpwhohas( 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;
#ifdef BSD4_4
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 ));
#else BSD4_4
if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) {
return;
}
m->m_len = sizeof( *ea );
m->m_off = MMAXOFF - sizeof( *ea );
#endif BSD4_4
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 );
#ifdef sun
bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha,
sizeof( ea->aarp_sha ));
#else sun
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
sizeof( ea->aarp_sha ));
#endif sun
/*
* 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 ))
== NULL ) {
m_freem( m );
return;
}
eh = (struct ether_header *)sa.sa_data;
if ( aa->aa_flags & AFA_PHASE2 ) {
#ifdef sun
bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost,
sizeof( eh->ether_dhost ));
#else sun
bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
sizeof( eh->ether_dhost ));
#endif sun
#if defined(sun) && defined(i386)
eh->ether_type = htons(sizeof(struct llc) + sizeof(struct ether_aarp));
#else
eh->ether_type = sizeof(struct llc) + sizeof(struct ether_aarp);
#endif
#ifdef BSD4_4
M_PREPEND( m, sizeof( struct llc ), M_WAIT );
#else BSD4_4
m->m_len += sizeof( struct llc );
m->m_off -= sizeof( struct llc );
#endif BSD4_4
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( &sat->sat_addr.s_net, ea->aarp_tpnet,
sizeof( ea->aarp_tpnet ));
ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node;
ea->aarp_tpnode = sat->sat_addr.s_node;
} else {
#ifdef sun
bcopy((caddr_t)&etherbroadcastaddr, (caddr_t)&eh->ether_dhost,
sizeof( eh->ether_dhost ));
#else sun
bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
sizeof( eh->ether_dhost ));
#endif sun
#if defined(sun) && defined(i386)
eh->ether_type = htons( ETHERTYPE_AARP );
#else
eh->ether_type = ETHERTYPE_AARP;
#endif
ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
ea->aarp_tpa = sat->sat_addr.s_node;
}
#ifdef NETATALKDEBUG
printf("aarp: sending request for %u.%u\n",
ntohs(AA_SAT( aa )->sat_addr.s_net),
AA_SAT( aa )->sat_addr.s_node);
#endif NETATALKDEBUG
#ifdef BSD4_4
sa.sa_len = sizeof( struct sockaddr );
#endif BSD4_4
sa.sa_family = AF_UNSPEC;
(*ac->ac_if.if_output)(&ac->ac_if, m, &sa
#if defined( __FreeBSD__ )
, NULL /* XXX should be routing information */
#endif __FreeBSD__
);
}
int
aarpresolve( ac, m, destsat, desten )
struct arpcom *ac;
struct mbuf *m;
struct sockaddr_at *destsat;
#ifdef sun
struct ether_addr *desten;
#else sun
u_char *desten;
#endif sun
{
struct at_ifaddr *aa;
struct ifaddr ifa;
struct aarptab *aat;
int s;
if ( at_broadcast( destsat )) {
if (( aa = (struct at_ifaddr *)at_ifawithnet( destsat,
((struct ifnet *)ac)->if_addrlist )) == NULL ) {
m_freem( m );
return( 0 );
}
if ( aa->aa_flags & AFA_PHASE2 ) {
bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten,
sizeof( atmulticastaddr ));
} else {
#ifdef sun
bcopy( (caddr_t)&etherbroadcastaddr, (caddr_t)desten,
sizeof( etherbroadcastaddr ));
#else sun
bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten,
sizeof( etherbroadcastaddr ));
#endif sun
}
return( 1 );
}
s = splimp();
AARPTAB_LOOK( aat, destsat->sat_addr );
if ( aat == 0 ) { /* No entry */
aat = aarptnew( &destsat->sat_addr );
if ( aat == 0 ) {
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;
#ifndef BSD4_4
IF_ADJ( m );
#endif BSD4_4
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( struct arpcom *ac, struct mbuf *m)
{
struct mbuf *m0;
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, s;
u_short net;
ea = mtod( m, struct ether_aarp *);
/* Check to see if from my hardware address */
#ifdef sun
if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )&ac->ac_enaddr,
sizeof( ac->ac_enaddr ))) {
m_freem( m );
return;
}
#else sun
if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr,
sizeof( ac->ac_enaddr ))) {
m_freem( m );
return;
}
#endif sun
op = ntohs( ea->aarp_op );
bcopy( ea->aarp_tpnet, &net, sizeof( net ));
if ( net != 0 ) { /* should be ATADDR_ANYNET? */
#ifdef BSD4_4
sat.sat_len = sizeof(struct sockaddr_at);
#endif BSD4_4
sat.sat_family = AF_APPLETALK;
sat.sat_addr.s_net = net;
if (( aa = (struct at_ifaddr *)at_ifawithnet( &sat,
ac->ac_if.if_addrlist )) == 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; aa;
aa = (struct at_ifaddr *)aa->aa_ifa.ifa_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((timeout_func_t) 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...
*/
#ifndef _IBMR2
#ifdef ultrix
mprintf( LOG_ERR,
#else ultrix
log( LOG_ERR,
#endif ultrix
"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 ]);
#endif _IBMR2
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 ) {
#ifdef _IBMR2
/*
* Like in ddp_output(), we can't rely on the if_output
* routine to resolve AF_APPLETALK addresses, on the rs6k.
* So, we fill the destination ethernet address here.
*
* This should really be replaced with something like
* rsif_output(). XXX Will have to be for phase 2.
*/
/* XXX maybe fill in the rest of the frame header */
sat.sat_family = AF_UNSPEC;
bcopy( aat->aat_enaddr, (*(struct sockaddr *)&sat).sa_data,
sizeof( aat->aat_enaddr ));
#else _IBMR2
#ifdef BSD4_4
sat.sat_len = sizeof(struct sockaddr_at);
#endif BSD4_4
sat.sat_family = AF_APPLETALK;
sat.sat_addr = spa;
#endif _IBMR2
(*ac->ac_if.if_output)( &ac->ac_if, aat->aat_hold,
(struct sockaddr *)&sat
#if defined( __FreeBSD__ )
, NULL /* XXX */
#endif __FreeBSD__
);
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 ));
#ifdef sun
bcopy(( caddr_t )&ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
sizeof( ea->aarp_sha ));
#else sun
bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
sizeof( ea->aarp_sha ));
#endif sun
/* XXX */
eh = (struct ether_header *)sa.sa_data;
#ifdef sun
bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )&eh->ether_dhost,
sizeof( eh->ether_dhost ));
#else sun
bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost,
sizeof( eh->ether_dhost ));
#endif sun
if ( aa->aa_flags & AFA_PHASE2 ) {
#if defined(sun) && defined(i386)
eh->ether_type = htons( sizeof( struct llc ) +
sizeof( struct ether_aarp ));
#else
eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
#endif
#ifdef BSD4_4
M_PREPEND( m, sizeof( struct llc ), M_DONTWAIT );
if ( m == NULL ) {
return;
}
#else BSD4_4
MGET( m0, M_DONTWAIT, MT_HEADER );
if ( m0 == NULL ) {
m_freem( m );
return;
}
m0->m_next = m;
m = m0;
m->m_off = MMAXOFF - sizeof( struct llc );
m->m_len = sizeof ( struct llc );
#endif BSD4_4
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 {
#if defined(sun) && defined(i386)
eh->ether_type = htons( ETHERTYPE_AARP );
#else
eh->ether_type = ETHERTYPE_AARP;
#endif
}
ea->aarp_tpnode = ea->aarp_spnode;
ea->aarp_spnode = ma.s_node;
ea->aarp_op = htons( AARPOP_RESPONSE );
#ifdef BSD4_4
sa.sa_len = sizeof( struct sockaddr );
#endif BSD4_4
sa.sa_family = AF_UNSPEC;
(*ac->ac_if.if_output)( &ac->ac_if, m, &sa
#if defined( __FreeBSD__ )
, NULL /* XXX */
#endif
);
return;
}
static void
aarptfree( 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( struct arpcom *ac )
{
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; aa;
aa = (struct at_ifaddr *)aa->aa_ifa.ifa_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( (timeout_func_t)aarpprobe, (caddr_t)ac, hz / 5 );
}
#ifdef BSD4_4
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 ));
#else BSD4_4
if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) {
return;
}
m->m_len = sizeof( *ea );
m->m_off = MMAXOFF - sizeof( *ea );
#endif BSD4_4
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 );
#ifdef sun
bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha,
sizeof( ea->aarp_sha ));
#else sun
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
sizeof( ea->aarp_sha ));
#endif sun
eh = (struct ether_header *)sa.sa_data;
if ( aa->aa_flags & AFA_PHASE2 ) {
#ifdef sun
bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost,
sizeof( eh->ether_dhost ));
#else sun
bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
sizeof( eh->ether_dhost ));
#endif sun
#if defined(sun) && defined(i386)
eh->ether_type = htons( sizeof( struct llc ) +
sizeof( struct ether_aarp ));
#else
eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
#endif
#ifdef BSD4_4
M_PREPEND( m, sizeof( struct llc ), M_WAIT );
#else BSD4_4
m->m_len += sizeof( struct llc );
m->m_off -= sizeof( struct llc );
#endif BSD4_4
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 {
#ifdef sun
bcopy((caddr_t)&etherbroadcastaddr, (caddr_t)&eh->ether_dhost,
sizeof( eh->ether_dhost ));
#else sun
bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
sizeof( eh->ether_dhost ));
#endif sun
#if defined(sun) && defined(i386)
eh->ether_type = htons( ETHERTYPE_AARP );
#else
eh->ether_type = ETHERTYPE_AARP;
#endif
ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node;
}
#ifdef NETATALKDEBUG
printf("aarp: sending probe for %u.%u\n",
ntohs(AA_SAT( aa )->sat_addr.s_net),
AA_SAT( aa )->sat_addr.s_node);
#endif NETATALKDEBUG
#ifdef BSD4_4
sa.sa_len = sizeof( struct sockaddr );
#endif BSD4_4
sa.sa_family = AF_UNSPEC;
(*ac->ac_if.if_output)(&ac->ac_if, m, &sa
#if defined( __FreeBSD__ )
, NULL /* XXX */
#endif __FreeBSD__
);
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 );
}
}
}

62
sys/netatalk/aarp.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*/
#ifndef _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_char ap_pa[4];
struct ap_node {
u_char an_zero;
u_char an_net[2];
u_char an_node;
} ap_node;
};
struct ether_aarp {
struct arphdr eaa_hdr;
u_char aarp_sha[6];
union aapa aarp_spu;
u_char 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_char aat_enaddr[ 6 ];
u_char aat_timer;
u_char aat_flags;
struct mbuf *aat_hold;
};
#define AARPHRD_ETHER 0x0001
#define AARPOP_REQUEST 0x01
#define AARPOP_RESPONSE 0x02
#define AARPOP_PROBE 0x03
#ifdef KERNEL
struct aarptab *aarptnew(struct at_addr *);
#if !defined( __FreeBSD__ )
int aarpprobe();
#endif
#endif
#endif /* _NETATALK_AARP_H_ */

117
sys/netatalk/at.h Normal file
View File

@ -0,0 +1,117 @@
/*
* 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
*/
#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
/*
* 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_short s_net;
u_char s_node;
};
#if defined( BSD4_4 ) && !defined( __FreeBSD__ )
#define ATADDR_ANYNET (u_short)0xffff
#else
#define ATADDR_ANYNET (u_short)0x0000
#endif
#define ATADDR_ANYNODE (u_char)0x00
#define ATADDR_ANYPORT (u_char)0x00
#define ATADDR_BCAST (u_char)0xff /* There is no BCAST for NET */
/*
* 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 {
#ifdef BSD4_4
u_char sat_len;
u_char sat_family;
#else BSD4_4
short sat_family;
#endif BSD4_4
u_char sat_port;
struct at_addr sat_addr;
#ifdef notdef
struct {
u_char sh_type;
# define SATHINT_NONE 0
# define SATHINT_CONFIG 1
# define SATHINT_IFACE 2
union {
char su_zero[ 7 ]; /* XXX check size */
struct {
u_char sr_phase;
u_short sr_firstnet, sr_lastnet;
} su_range;
u_short su_interface;
} sh_un;
} sat_hints;
#else notdef
char sat_zero[ 8 ];
#endif notdef
};
struct netrange {
u_char nr_phase;
u_short nr_firstnet;
u_short nr_lastnet;
};
#ifdef KERNEL
extern struct domain atalkdomain;
extern struct protosw atalksw[];
#endif
#endif __AT_HEADER__

614
sys/netatalk/at_control.c Normal file
View File

@ -0,0 +1,614 @@
/*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#ifdef ibm032
#include <sys/dir.h>
#endif ibm032
#include <sys/proc.h>
#ifndef BSD4_4
#include <sys/user.h>
#endif
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/mbuf.h>
#ifndef _IBMR2
#include <sys/kernel.h>
#endif _IBMR2
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
/* #include <net/af.h> */
#include <net/route.h>
#include <netinet/in.h>
#undef s_net
#include <netinet/if_ether.h>
#ifdef _IBMR2
#include <net/spl.h>
#endif _IBMR2
#include "at.h"
#include "at_var.h"
#include "aarp.h"
#include "phase2.h"
#include <netatalk/at_extern.h>
static int at_scrub( struct ifnet *ifp, struct at_ifaddr *aa );
static int at_ifinit( struct ifnet *ifp, struct at_ifaddr *aa,
struct sockaddr_at *sat );
#ifdef BSD4_4
# 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 )
#else BSD4_4
atalk_hash( sat, hp )
struct sockaddr_at *sat;
struct afhash *hp;
{
hp->afh_nethash = sat->sat_addr.s_net;
hp->afh_hosthash = ( sat->sat_addr.s_net << 8 ) +
sat->sat_addr.s_node;
}
/*
* Note the magic to get ifa_ifwithnet() to work without adding an
* ifaddr entry for each net in our local range.
*/
int
atalk_netmatch( sat1, sat2 )
struct sockaddr_at *sat1, *sat2;
{
struct at_ifaddr *aa;
for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
if ( AA_SAT( aa ) == sat1 ) {
break;
}
}
if ( aa ) {
return( ntohs( aa->aa_firstnet ) <= ntohs( sat2->sat_addr.s_net ) &&
ntohs( aa->aa_lastnet ) >= ntohs( sat2->sat_addr.s_net ));
}
return( sat1->sat_addr.s_net == sat2->sat_addr.s_net );
}
#endif BSD4_4
int
at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p )
{
struct ifreq *ifr = (struct ifreq *)data;
struct sockaddr_at *sat;
struct netrange *nr;
#ifdef BSD4_4
struct at_aliasreq *ifra = (struct at_aliasreq *)data;
struct at_ifaddr *aa0;
#endif BSD4_4
struct at_ifaddr *aa = 0;
struct mbuf *m;
struct ifaddr *ifa;
if ( ifp ) {
for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
if ( aa->aa_ifp == ifp ) break;
}
}
switch ( cmd ) {
#ifdef BSD4_4
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*/
#endif BSD4_4
case SIOCSIFADDR:
#ifdef BSD4_4
/*
* What a great idea this is: Let's reverse the meaning of
* the return...
*/
#if defined( __FreeBSD__ )
if ( suser(p->p_ucred, &p->p_acflag) ) {
#else
if ( suser( u.u_cred, &u.u_acflag )) {
#endif
return( EPERM );
}
#else BSD4_4
if ( !suser()) {
return( EPERM );
}
#endif BSD4_4
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 ) {
m = m_getclr( M_WAIT, MT_IFADDR );
if ( m == (struct mbuf *)NULL ) {
return( ENOBUFS );
}
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 = mtod( m, struct at_ifaddr *);
aa->aa_next = at_ifaddr;
at_ifaddr = aa;
} else {
for ( ; aa->aa_next; aa = aa->aa_next )
;
aa->aa_next = mtod( m, struct at_ifaddr *);
}
} else {
at_ifaddr = mtod( m, struct at_ifaddr *);
}
aa = mtod( m, struct at_ifaddr *);
if (( ifa = ifp->if_addrlist ) != NULL ) {
for ( ; ifa->ifa_next; ifa = ifa->ifa_next )
;
ifa->ifa_next = (struct ifaddr *)aa;
} else {
ifp->if_addrlist = (struct ifaddr *)aa;
}
#ifdef BSD4_4
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;
#endif BSD4_4
/*
* 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:
#ifdef BSD4_4
*(struct sockaddr_at *)&ifr->ifr_addr = aa->aa_addr;
#else BSD4_4
ifr->ifr_addr = aa->aa_addr;
#endif BSD4_4
break;
case SIOCSIFADDR:
return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));
#ifdef BSD4_4
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 );
if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) {
ifp->if_addrlist = ifa->ifa_next;
} else {
while ( ifa->ifa_next && ( ifa->ifa_next != (struct ifaddr *)aa )) {
ifa = ifa->ifa_next;
}
if ( ifa->ifa_next ) {
ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next;
} else {
panic( "at_control" );
}
}
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" );
}
}
m_free( dtom( aa0 ));
break;
#endif BSD4_4
default:
if ( ifp == 0 || ifp->if_ioctl == 0 )
return( EOPNOTSUPP );
return( (*ifp->if_ioctl)( ifp, cmd, data ));
}
return( 0 );
}
static int
at_scrub( ifp, aa )
struct ifnet *ifp;
struct at_ifaddr *aa;
{
#ifndef BSD4_4
struct sockaddr_at netsat;
u_short net;
#endif BSD4_4
int error;
if ( aa->aa_flags & AFA_ROUTE ) {
#ifdef BSD4_4
if (( error = rtinit( &(aa->aa_ifa), RTM_DELETE,
( ifp->if_flags & IFF_LOOPBACK ) ? RTF_HOST : 0 )) != 0 ) {
return( error );
}
aa->aa_ifa.ifa_flags &= ~IFA_ROUTE;
#else BSD4_4
if ( ifp->if_flags & IFF_LOOPBACK ) {
rtinit( &aa->aa_addr, &aa->aa_addr, SIOCDELRT, RTF_HOST );
} else {
bzero( &netsat, sizeof( struct sockaddr_at ));
netsat.sat_family = AF_APPLETALK;
netsat.sat_addr.s_node = ATADDR_ANYNODE;
/*
* If the range is the full 0-fffe range, just use
* the default route.
*/
if ( aa->aa_firstnet == htons( 0x0000 ) &&
aa->aa_lastnet == htons( 0xfffe )) {
netsat.sat_addr.s_net = 0;
rtinit((struct sockaddr *)&netsat, &aa->aa_addr,
(int)SIOCDELRT, 0 );
} else {
for ( net = ntohs( aa->aa_firstnet );
net <= ntohs( aa->aa_lastnet ); net++ ) {
netsat.sat_addr.s_net = htons( net );
rtinit((struct sockaddr *)&netsat, &aa->aa_addr,
(int)SIOCDELRT, 0 );
}
}
}
#endif BSD4_4
aa->aa_flags &= ~AFA_ROUTE;
}
return( 0 );
}
#if !defined( __FreeBSD__ )
extern struct timeval time;
#endif __FreeBSD__
static int
at_ifinit( ifp, aa, sat )
struct ifnet *ifp;
struct at_ifaddr *aa;
struct sockaddr_at *sat;
{
struct netrange nr, onr;
#ifdef BSD4_4
struct sockaddr_at oldaddr;
#else BSD4_4
struct sockaddr oldaddr;
#endif BSD4_4
struct sockaddr_at netaddr;
int s = splimp(), error = 0, i, j, netinc, nodeinc, nnets;
u_short net;
oldaddr = aa->aa_addr;
bzero( AA_SAT( aa ), sizeof( struct sockaddr_at ));
bcopy( sat->sat_zero, &nr, 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 ) {
#ifdef BSD4_4
AA_SAT( aa )->sat_len = sat->sat_len;
#endif BSD4_4
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;
#ifdef BSD4_4
AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at);
#endif BSD4_4
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 ) + time.tv_sec % ( 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;
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 = time.tv_sec;
} 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 = time.tv_sec | 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;
timeout( (timeout_func_t)aarpprobe, (caddr_t)ifp, hz / 5 );
splx( s );
if (
#if defined( __FreeBSD__ )
tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )
#else
sleep( aa, PSLEP|PCATCH )
#endif
) {
printf( "at_ifinit why did this happen?!\n" );
aa->aa_addr = oldaddr;
aa->aa_firstnet = onr.nr_firstnet;
aa->aa_lastnet = onr.nr_lastnet;
return( EINTR );
}
s = splimp();
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 ))) {
splx( s );
aa->aa_addr = oldaddr;
aa->aa_firstnet = onr.nr_firstnet;
aa->aa_lastnet = onr.nr_lastnet;
return( error );
}
#ifdef BSD4_4
aa->aa_netmask.sat_len = 6/*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;
#if defined( __FreeBSD__ )
aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */
#endif __FreeBSD__
#endif BSD4_4
if ( ifp->if_flags & IFF_LOOPBACK ) {
#ifndef BSD4_4
rtinit( &aa->aa_addr, &aa->aa_addr, (int)SIOCADDRT,
RTF_HOST|RTF_UP );
#else BSD4_4
error = rtinit( &(aa->aa_ifa), (int)RTM_ADD,
#if !defined( __FreeBSD__ )
RTF_HOST |
#else
/* XXX not a host route? */
#endif __FreeBSD__
RTF_UP );
#endif BSD4_4
} else {
#ifndef BSD4_4
/*
* rtrequest looks for point-to-point links first. The
* broadaddr is in the same spot as the destaddr. So, if
* ATADDR_ANYNET is 0, and we don't fill in the broadaddr, we
* get 0.0 routed out the ether interface. So, initialize the
* broadaddr, even tho we don't use it.
*
* We *could* use the broadaddr field to reduce some of the
* sockaddr_at overloading that we've done. E.g. Just send
* to INTERFACE-NET.255, and have the kernel reroute that
* to broadaddr, which would be 0.255 for phase 2 interfaces,
* and IFACE-NET.255 for phase 1 interfaces.
*/
((struct sockaddr_at *)&aa->aa_broadaddr)->sat_addr.s_net =
sat->sat_addr.s_net;
((struct sockaddr_at *)&aa->aa_broadaddr)->sat_addr.s_node =
ATADDR_BCAST;
bzero( &netaddr, sizeof( struct sockaddr_at ));
netaddr.sat_family = AF_APPLETALK;
netaddr.sat_addr.s_node = ATADDR_ANYNODE;
if (( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
netaddr.sat_addr.s_net = AA_SAT( aa )->sat_addr.s_net;
rtinit((struct sockaddr *)&netaddr, &aa->aa_addr,
(int)SIOCADDRT, RTF_UP );
} else {
/*
* If the range is the full 0-fffe range, just use
* the default route.
*/
if ( aa->aa_firstnet == htons( 0x0000 ) &&
aa->aa_lastnet == htons( 0xfffe )) {
netaddr.sat_addr.s_net = 0;
rtinit((struct sockaddr *)&netaddr, &aa->aa_addr,
(int)SIOCADDRT, RTF_UP );
} else {
for ( net = ntohs( aa->aa_firstnet );
net <= ntohs( aa->aa_lastnet ); net++ ) {
netaddr.sat_addr.s_net = htons( net );
rtinit((struct sockaddr *)&netaddr, &aa->aa_addr,
(int)SIOCADDRT, RTF_UP );
}
}
}
#else BSD4_4
error = rtinit( &(aa->aa_ifa), (int)RTM_ADD, RTF_UP );
#endif BSD4_4
}
if ( error ) {
aa->aa_addr = oldaddr;
aa->aa_firstnet = onr.nr_firstnet;
aa->aa_lastnet = onr.nr_lastnet;
splx( s );
return( error );
}
#ifdef BSD4_4
aa->aa_ifa.ifa_flags |= IFA_ROUTE;
#endif BSD4_4
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 );
}
static void
aa_clean(void)
{
struct at_ifaddr *aa;
struct ifaddr *ifa;
struct ifnet *ifp;
while ( aa = at_ifaddr ) {
ifp = aa->aa_ifp;
at_scrub( ifp, aa );
at_ifaddr = aa->aa_next;
if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) {
ifp->if_addrlist = ifa->ifa_next;
} else {
while ( ifa->ifa_next &&
( ifa->ifa_next != (struct ifaddr *)aa )) {
ifa = ifa->ifa_next;
}
if ( ifa->ifa_next ) {
ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next;
} else {
panic( "at_entry" );
}
}
}
}

41
sys/netatalk/at_extern.h Normal file
View File

@ -0,0 +1,41 @@
#ifdef _NETINET_IF_ETHER_H_
extern void aarpprobe __P((struct arpcom *));
extern int aarpresolve __P((struct arpcom *,
struct mbuf *,
struct sockaddr_at *,
u_char *));
extern void aarpinput __P(( struct arpcom *, struct mbuf *));
extern int at_broadcast __P((struct sockaddr_at *));
#endif
#ifdef _NETATALK_AARP_H_
extern void aarptfree __P((struct aarptab *));
#endif
extern void aarp_clean __P((void));
extern int at_control __P(( int cmd,
caddr_t data,
struct ifnet *ifp,
struct proc *p ));
extern u_short at_cksum __P(( struct mbuf *m, int skip));
extern int ddp_usrreq __P(( struct socket *so, int req,
struct mbuf *m,
struct mbuf *addr,
struct mbuf *rights));
extern void ddp_init __P((void ));
extern struct ifaddr *at_ifawithnet __P((struct sockaddr_at *,
struct ifaddr *));
#ifdef _NETATALK_DDP_VAR_H_
extern int ddp_output __P(( struct ddpcb *ddp, struct mbuf *m));
#endif
#if defined (_NETATALK_DDP_VAR_H_) && defined(_NETATALK_AT_VAR_H_)
extern struct ddpcb *ddp_search __P((struct sockaddr_at *,
struct sockaddr_at *,
struct at_ifaddr *));
#endif
#ifdef _NET_ROUTE_H_
int ddp_route( struct mbuf *m, struct route *ro);
#endif

95
sys/netatalk/at_proto.c Normal file
View File

@ -0,0 +1,95 @@
/*
* 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
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/types.h>
#include <sys/socket.h>
#if defined( __FreeBSD__ )
#include <sys/kernel.h>
#include <net/if.h>
#include <net/radix.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <net/route.h>
#endif
#include "at.h"
#include "ddp.h"
#include "at_var.h"
#include "ddp_var.h"
#include <netatalk/at_extern.h>
#ifdef ultrix
extern int ddp_ifoutput();
extern int ddp_ifinput();
extern int ddp_ifioctl();
#endif ultrix
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,
#ifdef ultrix
/* interface hooks */
ddp_ifoutput, ddp_ifinput, ddp_ifioctl, 0,
#endif ultrix
},
};
#if defined( __FreeBSD__ ) && defined ( NETATALKDEBUG )
extern int at_inithead();
#endif
struct domain atalkdomain = {
AF_APPLETALK, "appletalk", 0, 0, 0,
atalksw, &atalksw[sizeof(atalksw)/sizeof(atalksw[0])]
#if defined( __FreeBSD__ )
#ifdef NETATALKDEBUG
, 0, at_inithead, 32, sizeof(struct sockaddr_at)
#else
, 0, rn_inithead, 32, sizeof(struct sockaddr_at)
#endif
#endif
};
#if defined( __FreeBSD__ )
DOMAIN_SET(atalk);
#endif

160
sys/netatalk/at_rmx.c Normal file
View File

@ -0,0 +1,160 @@
/*
* Copyright 1994, 1995 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* at_rmx.c,v 1.13 1995/05/30 08:09:31 rgrimes Exp
*/
/* This code generates debugging traces to the radix code */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <net/route.h>
#include <netatalk/at.h>
#include <netatalk/at_extern.h>
static char hexbuf[256];
char *
prsockaddr(void *v)
{
char *bp = &hexbuf[0];
u_char *cp = v;
if (v) {
int len = *cp;
u_char *cplim = cp + len;
/* return: "(len) hexdump" */
bp += sprintf(bp, "(%d)", len);
for (cp++; cp < cplim && bp < hexbuf+252; cp++) {
*bp++ = "0123456789abcdef"[*cp / 16];
*bp++ = "0123456789abcdef"[*cp % 16];
}
} else {
bp+= sprintf(bp, "null");
}
*bp = '\0';
return &hexbuf[0];
}
static struct radix_node *
at_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
struct radix_node *treenodes)
{
struct radix_node *rn;
struct sockaddr_at *dst = v_arg, *mask = n_arg;
printf("at_addroute: v=%s\n", prsockaddr(v_arg));
printf("at_addroute: n=%s\n", prsockaddr(n_arg));
printf("at_addroute: head=%x treenodes=%x\n", head, treenodes);
rn = rn_addroute(v_arg, n_arg, head, treenodes);
printf("at_addroute: returns rn=%x\n", rn);
return rn;
}
static struct radix_node *
at_matroute(void *v_arg, struct radix_node_head *head)
{
struct radix_node *rn;
struct sockaddr_at *dst = v_arg;
printf("at_matroute: v=%s\n", prsockaddr(v_arg));
printf("at_matroute: head=%x\n", head);
rn = rn_match(v_arg, head);
printf("at_matroute: returns rn=%x\n", rn);
return rn;
}
static struct radix_node *
at_lookup(void *v_arg, void *m_arg, struct radix_node_head *head)
{
struct radix_node *rn;
printf("at_lookup: v=%s\n", prsockaddr(v_arg));
printf("at_lookup: n=%s\n", prsockaddr(m_arg));
printf("at_lookup: head=%x\n", head);
rn = rn_lookup(v_arg, m_arg, head);
printf("at_lookup: returns rn=%x\n", rn);
return rn;
}
static struct radix_node *
at_delroute(void *v_arg, void *netmask_arg, struct radix_node_head *head)
{
struct radix_node *rn;
printf("at_delroute: v=%s\n", prsockaddr(v_arg));
printf("at_delroute: n=%s\n", prsockaddr(netmask_arg));
printf("at_delroute: head=%x\n", head);
rn = rn_delete(v_arg, netmask_arg, head);
printf("at_delroute: returns rn=%x\n", rn);
return rn;
}
/*
* Initialize our routing tree with debugging hooks.
*/
int
at_inithead(void **head, int off)
{
struct radix_node_head *rnh;
if(!rn_inithead(head, off))
return 0;
rnh = *head;
rnh->rnh_addaddr = at_addroute;
rnh->rnh_deladdr = at_delroute;
rnh->rnh_matchaddr = at_matroute;
rnh->rnh_lookup = at_lookup;
return 1;
}

71
sys/netatalk/at_var.h Normal file
View File

@ -0,0 +1,71 @@
/*
* 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
*/
#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
#ifdef BSD4_4
struct sockaddr_at aa_addr;
struct sockaddr_at aa_broadaddr;
struct sockaddr_at aa_netmask;
#else BSD4_4
# define aa_addr aa_ifa.ifa_addr
# define aa_broadaddr aa_ifa.ifa_broadaddr
# define aa_dstaddr aa_ifa.ifa_dstaddr
#endif BSD4_4
int aa_flags;
u_short aa_firstnet, aa_lastnet;
int aa_probcnt;
struct at_ifaddr *aa_next;
};
#ifdef BSD4_4
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;
};
#endif BSD4_4
#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_ */

133
sys/netatalk/ddp.h Normal file
View File

@ -0,0 +1,133 @@
/*
* 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
*/
#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_ */

413
sys/netatalk/ddp_input.c Normal file
View File

@ -0,0 +1,413 @@
/*
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
#include <sys/types.h>
#include <sys/param.h>
#if defined( __FreeBSD__ )
#include <sys/systm.h>
#include <sys/kernel.h>
#include <net/netisr.h>
#endif __FreeBSD__
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <net/route.h>
#ifdef _IBMR2
#include <net/spl.h>
#endif _IBMR2
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include "at.h"
#include "at_var.h"
#include "endian.h"
#include "ddp.h"
#include "ddp_var.h"
#include <netatalk/at_extern.h>
int ddp_forward = 1;
int ddp_firewall = 0;
extern int ddp_cksum;
void ddp_input( struct mbuf *, struct ifnet *, struct elaphdr *, int );
/*
* Could probably merge these two code segments a little better...
*/
static void
atintr( void )
{
struct elaphdr *elhp, elh;
struct ifnet *ifp;
struct mbuf *m;
struct at_ifaddr *aa;
int s;
for (;;) {
#ifndef _IBMR2
s = splimp();
#endif _IBMR2
#ifdef BSD4_4
IF_DEQUEUE( &atintrq2, m );
#else BSD4_4
IF_DEQUEUEIF( &atintrq2, m, ifp );
#endif BSD4_4
#ifndef _IBMR2
splx( s );
#endif _IBMR2
if ( m == 0 ) { /* no more queued packets */
break;
}
#ifdef BSD4_4
ifp = m->m_pkthdr.rcvif;
#endif BSD4_4
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 (;;) {
#ifndef _IBMR2
s = splimp();
#endif _IBMR2
#ifdef BSD4_4
IF_DEQUEUE( &atintrq1, m );
#else BSD4_4
IF_DEQUEUEIF( &atintrq1, m, ifp );
#endif BSD4_4
#ifndef _IBMR2
splx( s );
#endif _IBMR2
if ( m == 0 ) { /* no more queued packets */
break;
}
#ifdef BSD4_4
ifp = m->m_pkthdr.rcvif;
#endif BSD4_4
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;
}
#if defined( __FreeBSD__ )
NETISR_SET(NETISR_ATALK, atintr);
#endif __FreeBSD__
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;
#ifndef BSD4_4
struct mbuf *mp;
#endif BSD4_4
struct ddpcb *ddp;
int dlen, mlen;
u_short 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 = ATADDR_ANYNET;
to.sat_addr.s_node = elh->el_dnode;
to.sat_port = ddps.dsh_dport;
from.sat_addr.s_net = ATADDR_ANYNET;
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 == ATADDR_ANYNET ) {
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.
*/
#ifdef BSD4_4
mlen = m->m_pkthdr.len;
#else BSD4_4
for ( mlen = 0, mp = m; mp; mp = mp->m_next ) {
mlen += mp->m_len;
}
#endif BSD4_4
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 )) {
#ifdef ultrix
rtfree( forwro.ro_rt );
#else ultrix
RTFREE( forwro.ro_rt );
#endif ultrix
forwro.ro_rt = (struct rtentry *)0;
}
if ( forwro.ro_rt == (struct rtentry *)0 ||
forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) {
#ifdef BSD4_4
forwro.ro_dst.sa_len = sizeof( struct sockaddr_at );
#endif BSD4_4
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;
}
if ( ddp_firewall &&
( forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp != ifp )) {
m_freem( m );
return;
}
ddpe.deh_hops++;
ddpe.deh_bytes = htonl( ddpe.deh_bytes );
bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); /* XXX deh? */
if ( ddp_route( m, &forwro )) {
ddpstat.ddps_cantforward++;
} else {
ddpstat.ddps_forward++;
}
return;
}
#ifdef BSD4_4
from.sat_len = sizeof( struct sockaddr_at );
#endif BSD4_4
from.sat_family = AF_APPLETALK;
if ( elh ) {
m_adj( m, sizeof( struct ddpshdr ));
} else {
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 );
}
#define BPXLEN 48
#define BPALEN 16
#include <ctype.h>
char hexdig[] = "0123456789ABCDEF";
static void
bprint( 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;
}
}
}
static void
m_printm( struct mbuf *m )
{
for (; m; m = m->m_next ) {
bprint( mtod( m, char * ), m->m_len );
}
}

298
sys/netatalk/ddp_output.c Normal file
View File

@ -0,0 +1,298 @@
/*
* 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
*/
#include <sys/types.h>
#include <sys/param.h>
#if defined( __FreeBSD__ )
#include <sys/systm.h>
#endif __FreeBSD__
#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 "at.h"
#include "at_var.h"
#include "endian.h"
#include "ddp.h"
#include "ddp_var.h"
#include <netatalk/at_extern.h>
int ddp_cksum = 1;
int
ddp_output( struct ddpcb *ddp, struct mbuf *m)
{
#ifndef BSD4_4
struct mbuf *m0;
int len;
#endif BSD4_4
struct ifnet *ifp;
struct at_ifaddr *aa = NULL;
struct ddpehdr *deh;
u_short net;
#ifdef BSD4_4
M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
#else BSD4_4
for ( len = 0, m0 = m; m; m = m->m_next ) {
len += m->m_len;
}
MGET( m, M_WAIT, MT_HEADER );
if ( m == 0 ) {
m_freem( m0 );
return( ENOBUFS );
}
m->m_next = m0;
#endif BSD4_4
#ifndef BSD4_4
# define align(a) (((a)+3)&0xfc)
m->m_off = MMINOFF + align( SZ_ELAPHDR );
m->m_len = sizeof( struct ddpehdr );
#endif BSD4_4
deh = mtod( m, struct ddpehdr *);
deh->deh_pad = 0;
deh->deh_hops = 0;
#ifdef BSD4_4
deh->deh_len = m->m_pkthdr.len;
#else BSD4_4
deh->deh_len = len + sizeof( struct ddpehdr );
#endif BSD4_4
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_short
at_cksum( struct mbuf *m, int skip)
{
u_char *data, *end;
u_long cksum = 0;
for (; m; m = m->m_next ) {
for ( data = mtod( m, u_char * ), 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_short)cksum );
}
int
ddp_route( struct mbuf *m, struct route *ro)
{
struct sockaddr_at gate;
struct elaphdr *elh;
struct mbuf *m0;
struct at_ifaddr *aa = NULL;
struct ifnet *ifp = NULL;
int mlen;
u_short net;
if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
#ifdef BSD4_4
net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
#else BSD4_4
net = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_net;
#endif BSD4_4
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 ) {
printf( "ddp_route: oops\n" );
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 defined( __FreeBSD__ )
/* XXX don't need this because we can change if_ethersubr.c */
#else
for ( mlen = 0, m0 = m; m0; m0 = m0->m_next ) {
mlen += m0->m_len;
}
#ifndef MIN
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif
if (( m = m_pullup( m, MIN( MLEN, mlen ))) == 0 ) {
printf("ddp_route: m_pullup of %d (mlen=%d) failed\n",
MIN( MLEN, mlen ), mlen);
return( ENOBUFS );
}
#endif __FreeBSD__
} else {
# ifdef notdef
#ifdef BSD4_4
M_PREPEND( m, SZ_ELAPHDR, M_DONTWAIT );
if ( m == NULL ) {
return( ENOBUFS );
}
#else BSD4_4
m->m_off -= SZ_ELAPHDR;
m->m_len += SZ_ELAPHDR;
#endif BSD4_4
# endif notdef
MGET( m0, M_WAIT, MT_HEADER );
if ( m0 == 0 ) {
m_freem( m );
printf("ddp_route: no buffers\n");
return( ENOBUFS );
}
m0->m_next = m;
#ifndef BSD4_4
m0->m_off = MMINOFF + align( sizeof( struct ether_header ));
#else
/* XXX perhaps we ought to align the header? */
#endif BSD4_4
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 {
#ifdef BSD4_4
elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
#else BSD4_4
elh->el_dnode = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_node;
#endif BSD4_4
}
}
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 {
#ifdef BSD4_4
gate = *satosat( ro->ro_rt->rt_gateway );
#else BSD4_4
gate = *satosat( &ro->ro_rt->rt_gateway );
#endif BSD4_4
}
ro->ro_rt->rt_use++;
#ifdef ultrix
/*
* SAIEW: We can't make changes to net/if_loop.c, so we don't route
* further than this: if it's going to go through the lookback,
* short-circuit to ddp_input(). Who needs queuing?
*
* Note: Passing NULL for the elaphdr is cool, since we'll only ever
* try to send long form ddp throught the loopback.
*/
if ( ifp->if_flags & IFF_LOOPBACK ) {
#ifdef notdef
m->m_off += SZ_ELAPHDR;
m->m_len -= SZ_ELAPHDR;
#endif notdef
ddp_input( m, ifp, (struct elaphdr *)NULL, 2 );
return( 0 );
}
#endif ultrix
#ifdef _IBMR2
/*
* We can't make changes to the interface routines on RS6ks, and
* they don't provide hooks for if_output, so we just resolve
* our address here, and pass the packet as a raw ethernet packet.
* This doesn't work particularly well, if we aren't *on* ethernet,
* but it's ok for the moment.
*/
if ( ! ( ifp->if_flags & IFF_LOOPBACK )) {
struct ether_header eh;
if ( !aarpresolve(( struct arpcom *)ifp, m,
&gate, eh.ether_dhost )) {
return( 0 );
}
eh.ether_type = htons( ETHERTYPE_AT );
gate.sat_family = AF_UNSPEC;
bcopy( &eh, (*(struct sockaddr *)&gate).sa_data,
sizeof( (*(struct sockaddr *)&gate).sa_data ));
}
#endif _IBMR2
return((*ifp->if_output)( ifp, m, &gate
#if defined( __FreeBSD__ )
, NULL /* XXX */
#endif __FreeBSD__
));
}

582
sys/netatalk/ddp_pcb.c Normal file
View File

@ -0,0 +1,582 @@
/*
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#if defined( __FreeBSD__ )
#include <sys/proc.h>
#endif __FreeBSD__
#ifdef ibm032
#include <sys/dir.h>
#endif ibm032
#ifndef __FreeBSD__
#include <sys/user.h>
#endif
#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 <netinet/in.h>
#include <netinet/if_ether.h>
#ifdef _IBMR2
#include <net/spl.h>
#endif _IBMR2
#include "at.h"
#include "at_var.h"
#include "ddp_var.h"
#include "aarp.h"
#include "endian.h"
#include <netatalk/at_extern.h>
static void at_pcbdisconnect( struct ddpcb *ddp );
static void at_sockaddr( struct ddpcb *ddp, struct mbuf *addr );
static int at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p);
static int at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p);
static void at_pcbdetach( struct socket *so, struct ddpcb *ddp);
static int at_pcballoc( struct socket *so );
struct ddpcb *ddp_ports[ ATPORT_LAST ];
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( struct socket *so, int req, struct mbuf *m,
struct mbuf *addr, struct mbuf *rights)
{
#if defined( __FreeBSD__ )
struct proc *p = curproc; /* XXX */
#endif __FreeBSD__
struct ddpcb *ddp;
int error = 0;
ddp = sotoddpcb( so );
if ( req == PRU_CONTROL ) {
return( at_control( (int) m, (caddr_t) addr,
(struct ifnet *) rights
#if defined( __FreeBSD__ )
, (struct proc *)p
#endif __FreeBSD__
));
}
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
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
);
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
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
);
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 = 0;
if ( addr ) {
if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
error = EISCONN;
break;
}
s = splnet();
error = at_pcbconnect( ddp, addr
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
);
if ( error ) {
splx( s );
break;
}
} else {
if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) {
error = ENOTCONN;
break;
}
}
error = ddp_output( ddp, m );
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( 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( 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 );
}
#ifdef BSD4_4
if ( sat->sat_port < ATPORT_RESERVED &&
#if defined( __FreeBSD__ )
suser( p->p_ucred, &p->p_acflag )
#else
suser( u.u_cred, &u.u_acflag )
#endif __FreeBSD__
) {
return( EACCES );
}
#else BSD4_4
if ( sat->sat_port < ATPORT_RESERVED && ( !suser())) {
return( EACCES );
}
#endif BSD4_4
}
} else {
bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at ));
#ifdef BSD4_4
lsat.sat_len = sizeof(struct sockaddr_at);
lsat.sat_addr.s_node = ATADDR_ANYNODE;
lsat.sat_addr.s_net = ATADDR_ANYNET;
#endif BSD4_4
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( 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_short 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 == ATADDR_ANYNET
&& 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 ) {
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 )) {
printf("at_pcbconnect: found ifp net=%u\n", ntohs(net));
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 )) {
printf("at_pcbconnect: freeing ro->ro_rt=0x%x\n", ro->ro_rt);
#ifdef ultrix
rtfree( ro->ro_rt );
#else ultrix
RTFREE( ro->ro_rt );
#endif ultrix
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 ) {
#ifdef BSD4_4
ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
#endif BSD4_4
ro->ro_dst.sa_family = AF_APPLETALK;
if ( hintnet ) {
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 ) {
printf("at_pcbconnect: ro->ro_rt=0x%x\n", ro->ro_rt);
if (ro->ro_rt)
printf("at_pcbconnect: ro->ro_rt->rt_ifp=0x%x", ro->ro_rt->rt_ifp);
return( ENETUNREACH );
}
ddp->ddp_fsat = *sat;
if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
return( at_pcbsetaddr( ddp, (struct mbuf *)0
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
));
}
return( 0 );
}
static void
at_pcbdisconnect( 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( 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( 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( struct sockaddr_at *from, struct sockaddr_at *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(void )
{
atintrq1.ifq_maxlen = IFQ_MAXLEN;
atintrq2.ifq_maxlen = IFQ_MAXLEN;
}
static void
ddp_clean(void )
{
struct ddpcb *ddp;
for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) {
at_pcbdetach( ddp->ddp_socket, ddp );
}
}

582
sys/netatalk/ddp_usrreq.c Normal file
View File

@ -0,0 +1,582 @@
/*
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#if defined( __FreeBSD__ )
#include <sys/proc.h>
#endif __FreeBSD__
#ifdef ibm032
#include <sys/dir.h>
#endif ibm032
#ifndef __FreeBSD__
#include <sys/user.h>
#endif
#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 <netinet/in.h>
#include <netinet/if_ether.h>
#ifdef _IBMR2
#include <net/spl.h>
#endif _IBMR2
#include "at.h"
#include "at_var.h"
#include "ddp_var.h"
#include "aarp.h"
#include "endian.h"
#include <netatalk/at_extern.h>
static void at_pcbdisconnect( struct ddpcb *ddp );
static void at_sockaddr( struct ddpcb *ddp, struct mbuf *addr );
static int at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p);
static int at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p);
static void at_pcbdetach( struct socket *so, struct ddpcb *ddp);
static int at_pcballoc( struct socket *so );
struct ddpcb *ddp_ports[ ATPORT_LAST ];
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( struct socket *so, int req, struct mbuf *m,
struct mbuf *addr, struct mbuf *rights)
{
#if defined( __FreeBSD__ )
struct proc *p = curproc; /* XXX */
#endif __FreeBSD__
struct ddpcb *ddp;
int error = 0;
ddp = sotoddpcb( so );
if ( req == PRU_CONTROL ) {
return( at_control( (int) m, (caddr_t) addr,
(struct ifnet *) rights
#if defined( __FreeBSD__ )
, (struct proc *)p
#endif __FreeBSD__
));
}
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
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
);
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
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
);
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 = 0;
if ( addr ) {
if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
error = EISCONN;
break;
}
s = splnet();
error = at_pcbconnect( ddp, addr
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
);
if ( error ) {
splx( s );
break;
}
} else {
if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) {
error = ENOTCONN;
break;
}
}
error = ddp_output( ddp, m );
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( 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( 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 );
}
#ifdef BSD4_4
if ( sat->sat_port < ATPORT_RESERVED &&
#if defined( __FreeBSD__ )
suser( p->p_ucred, &p->p_acflag )
#else
suser( u.u_cred, &u.u_acflag )
#endif __FreeBSD__
) {
return( EACCES );
}
#else BSD4_4
if ( sat->sat_port < ATPORT_RESERVED && ( !suser())) {
return( EACCES );
}
#endif BSD4_4
}
} else {
bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at ));
#ifdef BSD4_4
lsat.sat_len = sizeof(struct sockaddr_at);
lsat.sat_addr.s_node = ATADDR_ANYNODE;
lsat.sat_addr.s_net = ATADDR_ANYNET;
#endif BSD4_4
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( 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_short 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 == ATADDR_ANYNET
&& 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 ) {
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 )) {
printf("at_pcbconnect: found ifp net=%u\n", ntohs(net));
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 )) {
printf("at_pcbconnect: freeing ro->ro_rt=0x%x\n", ro->ro_rt);
#ifdef ultrix
rtfree( ro->ro_rt );
#else ultrix
RTFREE( ro->ro_rt );
#endif ultrix
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 ) {
#ifdef BSD4_4
ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
#endif BSD4_4
ro->ro_dst.sa_family = AF_APPLETALK;
if ( hintnet ) {
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 ) {
printf("at_pcbconnect: ro->ro_rt=0x%x\n", ro->ro_rt);
if (ro->ro_rt)
printf("at_pcbconnect: ro->ro_rt->rt_ifp=0x%x", ro->ro_rt->rt_ifp);
return( ENETUNREACH );
}
ddp->ddp_fsat = *sat;
if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
return( at_pcbsetaddr( ddp, (struct mbuf *)0
#if defined( __FreeBSD__ )
, p
#endif __FreeBSD__
));
}
return( 0 );
}
static void
at_pcbdisconnect( 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( 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( 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( struct sockaddr_at *from, struct sockaddr_at *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(void )
{
atintrq1.ifq_maxlen = IFQ_MAXLEN;
atintrq2.ifq_maxlen = IFQ_MAXLEN;
}
static void
ddp_clean(void )
{
struct ddpcb *ddp;
for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) {
at_pcbdetach( ddp->ddp_socket, ddp );
}
}

36
sys/netatalk/ddp_var.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
#ifndef _NETATALK_DDP_VAR_H_
#define _NETATALK_DDP_VAR_H_ 1
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 {
long ddps_short; /* short header packets received */
long ddps_long; /* long header packets received */
long ddps_nosum; /* no checksum */
long ddps_badsum; /* bad checksum */
long ddps_tooshort; /* packet too short */
long ddps_toosmall; /* not enough data */
long ddps_forward; /* packets forwarded */
long ddps_encap; /* packets encapsulated */
long ddps_cantforward; /* packets rcvd for unreachable dest */
long ddps_nosockspace; /* no space in sockbuf for packet */
};
#ifdef KERNEL
extern struct ddpcb *ddp_ports[ ];
extern struct ddpcb *ddpcb;
struct ddpstat ddpstat;
#endif
#endif /* _NETATALK_DDP_VAR_H_ */

87
sys/netatalk/endian.h Normal file
View File

@ -0,0 +1,87 @@
/*
* 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
*/
# ifndef _ATALK_ENDIAN_H_
#define _ATALK_ENDIAN_H_
#ifdef _IBMR2
#include <sys/machine.h>
#endif _IBMR2
#ifdef linux
#include <bytesex.h>
#define BYTE_ORDER __BYTE_ORDER
#endif linux
#ifdef __FreeBSD__
#include <machine/endian.h>
#endif __FreeBSD__
# ifndef BYTE_ORDER
#define LITTLE_ENDIAN 1234
#define BIG_ENDIAN 4321
#define PDP_ENDIAN 3412
#ifdef sun
#ifdef i386
#define BYTE_ORDER LITTLE_ENDIAN
#else i386
#define BYTE_ORDER BIG_ENDIAN
#endif i386
#else
#ifdef MIPSEB
#define BYTE_ORDER BIG_ENDIAN
#else
#ifdef MIPSEL
#define BYTE_ORDER LITTLE_ENDIAN
#else
Like, what is your byte order, man?
#endif MIPSEL
#endif MIPSEB
#endif sun
# endif BYTE_ORDER
# ifndef ntohl
# if defined( sun ) || defined( ultrix ) || defined( _IBMR2 )
#if BYTE_ORDER == BIG_ENDIAN
#define ntohl(x) (x)
#define ntohs(x) (x)
#define htonl(x) (x)
#define htons(x) (x)
#else
#if defined( mips ) && defined( KERNEL )
#define ntohl(x) nuxi_l(x)
#define ntohs(x) nuxi_s(x)
#define htonl(x) nuxi_l(x)
#define htons(x) nuxi_s(x)
#else mips KERNEL
unsigned short ntohs(), htons();
unsigned long ntohl(), htonl();
#endif mips KERNEL
#endif BYTE_ORDER
# endif sun ultrix _IBMR2
# endif ntohl
# endif _ATALK_ENDIAN_H_

85
sys/netatalk/phase2.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*/
# if defined( ultrix ) || defined( BSD4_4 )
#include <net/if_llc.h>
# if defined( __FreeBSD__ )
#define llc_org_code llc_un.type_snap.org_code
#define llc_ether_type llc_un.type_snap.ether_type
# endif __FreeBSD__
# else ultrix BSD4_4
#ifdef sun
#include <net/if_ieee802.h>
#endif sun
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* @(#)if_llc.h 7.2 (Berkeley) 6/28/90
*/
/*
* IEEE 802.2 Link Level Control headers, for use in conjunction with
* 802.{3,4,5} media access control methods.
*
* Headers here do not use bit fields due to shortcommings in many
* compilers.
*/
struct llc {
u_char llc_dsap;
u_char llc_ssap;
union {
struct {
u_char control;
u_char format_id;
u_char class;
u_char window_x2;
} type_u;
struct {
u_char num_snd_x2;
u_char num_rcv_x2;
} type_i;
struct {
u_char control;
u_char num_rcv_x2;
} type_s;
struct {
u_char control;
u_char org_code[3];
u_short ether_type;
} type_snap;
} llc_un;
};
#define llc_control llc_un.type_u.control
#define llc_fid llc_un.type_u.format_id
#define llc_class llc_un.type_u.class
#define llc_window llc_un.type_u.window_x2
#define llc_org_code llc_un.type_snap.org_code
#define llc_ether_type llc_un.type_snap.ether_type
#define LLC_UI 0x3
#define LLC_UI_P 0x13
#define LLC_XID 0xaf
#define LLC_XID_P 0xbf
#define LLC_TEST 0xe3
#define LLC_TEST_P 0xf3
#define LLC_ISO_LSAP 0xfe
#define LLC_SNAP_LSAP 0xaa
# endif ultrix BSD4_4
#if defined( sun ) || defined( ibm032 )
#define SIOCPHASE1 _IOW(i, 100, struct ifreq) /* AppleTalk phase 1 */
#define SIOCPHASE2 _IOW(i, 101, struct ifreq) /* AppleTalk phase 2 */
#endif sun ibm032
#if defined( ultrix ) || defined( BSD4_4 ) || defined( _IBMR2 )
#define SIOCPHASE1 _IOW('i', 100, struct ifreq) /* AppleTalk phase 1 */
#define SIOCPHASE2 _IOW('i', 101, struct ifreq) /* AppleTalk phase 2 */
#endif ultrix BSD4_4 _IBMR2