Index: at_extern.h =================================================================== --- at_extern.h (.../stable/4/sys/netatalk) (revision 196046) +++ at_extern.h (.../head/sys/netatalk) (revision 196046) @@ -1,44 +1,67 @@ -struct mbuf; -struct sockaddr_at; +/*- + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ -#ifdef _NET_IF_ARP_H_ -extern timeout_t aarpprobe; -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 +#ifndef _NETATALK_AT_EXTERN_H_ +#define _NETATALK_AT_EXTERN_H_ -#ifdef _NETATALK_AARP_H_ -extern void aarptfree __P((struct aarptab *)); -#endif +extern struct mtx aarptab_mtx; +#define AARPTAB_LOCK() mtx_lock(&aarptab_mtx) +#define AARPTAB_UNLOCK() mtx_unlock(&aarptab_mtx) +#define AARPTAB_LOCK_ASSERT() mtx_assert(&aarptab_mtx, MA_OWNED) +#define AARPTAB_UNLOCK_ASSERT() mtx_assert(&aarptab_mtx, MA_NOTOWNED) + +struct at_ifaddr; struct ifnet; -struct proc; +struct mbuf; +struct route; +struct thread; +struct sockaddr_at; struct socket; +void aarpintr(struct mbuf *); +void aarpprobe(void *arg); +int aarpresolve(struct ifnet *, struct mbuf *, + struct sockaddr_at *, u_char *); +void aarp_clean(void); +void at1intr(struct mbuf *); +void at2intr(struct mbuf *); +int at_broadcast(struct sockaddr_at *); +u_short at_cksum(struct mbuf *m, int skip); +int at_control(struct socket *so, u_long cmd, caddr_t data, + struct ifnet *ifp, struct thread *td); +struct at_ifaddr *at_ifawithnet(struct sockaddr_at *); +struct at_ifaddr *at_ifawithnet_locked(struct sockaddr_at *sat); -extern void aarp_clean __P((void)); -extern int at_control __P(( struct socket *so, - u_long cmd, - caddr_t data, - struct ifnet *ifp, - struct proc *p )); -extern u_short at_cksum __P(( struct mbuf *m, int skip)); -extern void ddp_init __P((void )); -extern struct at_ifaddr *at_ifawithnet __P((struct sockaddr_at *)); -#ifdef _NETATALK_DDP_VAR_H_ -extern int ddp_output __P((struct mbuf *m, struct socket *so)); +int at_inithead(void**, int); +void ddp_init(void); +int ddp_output(struct mbuf *m, struct socket *so); +int ddp_route(struct mbuf *m, struct route *ro); +struct ddpcb *ddp_search(struct sockaddr_at *, struct sockaddr_at *, + struct at_ifaddr *); -#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 - - +#endif /* !_NETATALK_AT_EXTERN_H_ */ Index: ddp_pcb.h =================================================================== --- ddp_pcb.h (.../stable/4/sys/netatalk) (revision 0) +++ ddp_pcb.h (.../head/sys/netatalk) (revision 196046) @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2004 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_DDP_PCB_H_ +#define _NETATALK_DDP_PCB_H_ + +int at_pcballoc(struct socket *so); +int at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, + struct thread *td); +void at_pcbdetach(struct socket *so, struct ddpcb *ddp); +void at_pcbdisconnect(struct ddpcb *ddp); +int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, + struct thread *td); +void at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr); + +/* Lock macros for per-pcb locks. */ +#define DDP_LOCK_INIT(ddp) mtx_init(&(ddp)->ddp_mtx, "ddp_mtx", \ + NULL, MTX_DEF) +#define DDP_LOCK_DESTROY(ddp) mtx_destroy(&(ddp)->ddp_mtx) +#define DDP_LOCK(ddp) mtx_lock(&(ddp)->ddp_mtx) +#define DDP_UNLOCK(ddp) mtx_unlock(&(ddp)->ddp_mtx) +#define DDP_LOCK_ASSERT(ddp) mtx_assert(&(ddp)->ddp_mtx, MA_OWNED) + +/* Lock macros for global pcb list lock. */ +#define DDP_LIST_LOCK_INIT() mtx_init(&ddp_list_mtx, "ddp_list_mtx", \ + NULL, MTX_DEF) +#define DDP_LIST_LOCK_DESTROY() mtx_destroy(&ddp_list_mtx) +#define DDP_LIST_XLOCK() mtx_lock(&ddp_list_mtx) +#define DDP_LIST_XUNLOCK() mtx_unlock(&ddp_list_mtx) +#define DDP_LIST_XLOCK_ASSERT() mtx_assert(&ddp_list_mtx, MA_OWNED) +#define DDP_LIST_SLOCK() mtx_lock(&ddp_list_mtx) +#define DDP_LIST_SUNLOCK() mtx_unlock(&ddp_list_mtx) +#define DDP_LIST_SLOCK_ASSERT() mtx_assert(&ddp_list_mtx, MA_OWNED) + +#endif /* !_NETATALK_DDP_PCB_H_ */ Property changes on: ddp_pcb.h ___________________________________________________________________ Added: svn:keywords + FreeBSD=%H Index: endian.h =================================================================== --- endian.h (.../stable/4/sys/netatalk) (revision 196046) +++ endian.h (.../head/sys/netatalk) (revision 196046) @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. * @@ -19,6 +19,8 @@ * Ann Arbor, Michigan * +1-313-763-0525 * netatalk@itd.umich.edu + * + * $FreeBSD$ */ #ifndef _ATALK_ENDIAN_H_ Index: at_control.c =================================================================== --- at_control.c (.../stable/4/sys/netatalk) (revision 196046) +++ at_control.c (.../head/sys/netatalk) (revision 196046) @@ -1,14 +1,41 @@ -/* +/*- * Copyright (c) 1990,1991 Regents of The University of Michigan. + * Copyright (c) 2009 Robert N. M. Watson * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu */ +#include +__FBSDID("$FreeBSD$"); + #include #include -#include #include +#include #include #include +#include +#include #include #include #include @@ -20,311 +47,344 @@ #include #include -struct at_ifaddr *at_ifaddr; +struct rwlock at_ifaddr_rw; +struct at_ifaddrhead at_ifaddrhead; -static int aa_dorangeroute(struct ifaddr *ifa, - u_int first, u_int last, int cmd); -static int aa_addsingleroute(struct ifaddr *ifa, - struct at_addr *addr, struct at_addr *mask); -static int aa_delsingleroute(struct ifaddr *ifa, - struct at_addr *addr, struct at_addr *mask); +RW_SYSINIT(at_ifaddr_rw, &at_ifaddr_rw, "at_ifaddr_rw"); + +static int aa_dorangeroute(struct ifaddr *ifa, u_int first, u_int last, + int cmd); +static int aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask); +static int aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask); static int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *addr, - struct at_addr *mask, int cmd, int flags); -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 ); + struct at_addr *mask, int cmd, int flags); +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); static int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw); -# 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 ) +#define sateqaddr(a,b) \ + ((a)->sat_len == (b)->sat_len && \ + (a)->sat_family == (b)->sat_family && \ + (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ + (a)->sat_addr.s_node == (b)->sat_addr.s_node) int -at_control(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp, struct proc *p ) +at_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, + struct thread *td) { - struct ifreq *ifr = (struct ifreq *)data; - struct sockaddr_at *sat; - struct netrange *nr; - struct at_aliasreq *ifra = (struct at_aliasreq *)data; - struct at_ifaddr *aa0; - struct at_ifaddr *aa = 0; - struct ifaddr *ifa, *ifa0; + struct ifreq *ifr = (struct ifreq *)data; + struct sockaddr_at *sat; + struct netrange *nr; + struct at_aliasreq *ifra = (struct at_aliasreq *)data; + struct at_ifaddr *aa; + struct ifaddr *ifa; + int error; - /* - * If we have an ifp, then find the matching at_ifaddr if it exists - */ - if ( ifp ) { - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp ) break; - } - } - - /* - * In this first switch table we are basically getting ready for - * the second one, by getting the atalk-specific things set up - * so that they start to look more similar to other protocols etc. - */ - - switch ( cmd ) { - case SIOCAIFADDR: - case SIOCDIFADDR: /* - * If we have an appletalk sockaddr, scan forward of where - * we are now on the at_ifaddr list to find one with a matching - * address on this interface. - * This may leave aa pointing to the first address on the - * NEXT interface! + * If we have an ifp, then find the matching at_ifaddr if it exists */ - 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; + aa = NULL; + AT_IFADDR_RLOCK(); + if (ifp != NULL) { + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (aa->aa_ifp == ifp) + break; } - } } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + /* - * If we a retrying to delete an addres but didn't find such, - * then rewurn with an error + * In this first switch table we are basically getting ready for + * the second one, by getting the atalk-specific things set up + * so that they start to look more similar to other protocols etc. */ - if ( cmd == SIOCDIFADDR && aa == 0 ) { - return( EADDRNOTAVAIL ); - } - /*FALLTHROUGH*/ + error = 0; + switch (cmd) { + case SIOCAIFADDR: + case SIOCDIFADDR: + /* + * If we have an appletalk sockaddr, scan forward of where we + * are now on the at_ifaddr list to find one with a matching + * address on this interface. This may leave aa pointing to + * the first address on the NEXT interface! + */ + if (ifra->ifra_addr.sat_family == AF_APPLETALK) { + struct at_ifaddr *oaa; - case SIOCSIFADDR: - /* - * If we are not superuser, then we don't get to do these ops. - */ - if ( suser(p) ) { - return( EPERM ); - } + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && + sateqaddr(&aa->aa_addr, &ifra->ifra_addr)) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } + /* + * If we a retrying to delete an addres but didn't find such, + * then rewurn with an error + */ + if (cmd == SIOCDIFADDR && aa == NULL) { + error = EADDRNOTAVAIL; + goto out; + } + /*FALLTHROUGH*/ - sat = satosat( &ifr->ifr_addr ); - nr = (struct netrange *)sat->sat_zero; - if ( nr->nr_phase == 1 ) { - /* - * Look for a phase 1 address on this interface. - * This may leave aa pointing to the first address on the - * NEXT interface! - */ - for ( ; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && - ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { - break; + case SIOCSIFADDR: + /* + * If we are not superuser, then we don't get to do these ops. + * + * XXXRW: Layering? + */ + if (priv_check(td, PRIV_NET_ADDIFADDR)) { + error = EPERM; + goto out; } - } - } else { /* default to phase 2 */ - /* - * Look for a phase 2 address on this interface. - * This may leave aa pointing to the first address on the - * NEXT interface! - */ - for ( ; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { - break; + + sat = satosat(&ifr->ifr_addr); + nr = (struct netrange *)sat->sat_zero; + if (nr->nr_phase == 1) { + struct at_ifaddr *oaa; + + /* + * Look for a phase 1 address on this interface. + * This may leave aa pointing to the first address on + * the NEXT interface! + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && + (aa->aa_flags & AFA_PHASE2) == 0) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } else { /* default to phase 2 */ + struct at_ifaddr *oaa; + + /* + * Look for a phase 2 address on this interface. + * This may leave aa pointing to the first address on + * the NEXT interface! + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && (aa->aa_flags & + AFA_PHASE2)) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); } - } - } - if ( ifp == 0 ) - panic( "at_control" ); + if (ifp == NULL) + panic("at_control"); - /* - * If we failed to find an existing at_ifaddr entry, then we - * allocate a fresh one. - */ - if ( aa == (struct at_ifaddr *) 0 ) { - aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, M_WAITOK); - bzero(aa0, sizeof(struct at_ifaddr)); - if (( aa = at_ifaddr ) != NULL ) { /* - * Don't let the loopback be first, since the first - * address is the machine's default address for - * binding. - * If it is, stick ourself in front, otherwise - * go to the back of the list. + * If we failed to find an existing at_ifaddr entry, then we + * allocate a fresh one. */ - if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) { - aa = aa0; - aa->aa_next = at_ifaddr; - at_ifaddr = aa; - } else { - for ( ; aa->aa_next; aa = aa->aa_next ) - ; - aa->aa_next = aa0; - } - } else { - at_ifaddr = aa0; - } - /* - * Don't Add a reference for the aa itself! - * I fell into this trap. IFAFREE tests for <=0 - * not <= 1 like RTFREE - */ - /* aa->aa_ifa.ifa_refcnt++; DON'T DO THIS!! */ - aa = aa0; + if (aa == NULL) { + aa = malloc(sizeof(struct at_ifaddr), M_IFADDR, + M_NOWAIT | M_ZERO); + if (aa == NULL) { + error = ENOBUFS; + goto out; + } + callout_init(&aa->aa_callout, CALLOUT_MPSAFE); - /* - * Find the end of the interface's addresses - * and link our new one on the end - */ - ifa = (struct ifaddr *)aa; - TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); + ifa = (struct ifaddr *)aa; + ifa_init(ifa); - /* - * Add a reference for the linking into the ifp_if_addrlist. - */ - ifa->ifa_refcnt++; + /* + * As the at_ifaddr contains the actual sockaddrs, + * and the ifaddr itself, link them all together + * correctly. + */ + ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr; + ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; + ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask; - /* - * As the at_ifaddr contains the actual sockaddrs, - * and the ifaddr itself, link them al together correctly. - */ - ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr; - ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; - ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask; + /* + * Set/clear the phase 2 bit. + */ + if (nr->nr_phase == 1) + aa->aa_flags &= ~AFA_PHASE2; + else + aa->aa_flags |= AFA_PHASE2; - /* - * Set/clear the phase 2 bit. - */ - if ( nr->nr_phase == 1 ) { - aa->aa_flags &= ~AFA_PHASE2; - } else { - aa->aa_flags |= AFA_PHASE2; - } + ifa_ref(&aa->aa_ifa); /* at_ifaddrhead */ + AT_IFADDR_WLOCK(); + if (!TAILQ_EMPTY(&at_ifaddrhead)) { + /* + * Don't let the loopback be first, since the + * first address is the machine's default + * address for binding. If it is, stick + * ourself in front, otherwise go to the back + * of the list. + */ + if (TAILQ_FIRST(&at_ifaddrhead)->aa_ifp-> + if_flags & IFF_LOOPBACK) + TAILQ_INSERT_HEAD(&at_ifaddrhead, aa, + aa_link); + else + TAILQ_INSERT_TAIL(&at_ifaddrhead, aa, + aa_link); + } else + TAILQ_INSERT_HEAD(&at_ifaddrhead, aa, + aa_link); + AT_IFADDR_WUNLOCK(); - /* - * and link it all together - */ - aa->aa_ifp = ifp; - } else { - /* - * If we DID find one then we clobber any routes dependent on it.. - */ - at_scrub( ifp, aa ); - } - break; + /* + * and link it all together + */ + aa->aa_ifp = ifp; + ifa_ref(&aa->aa_ifa); /* if_addrhead */ + IF_ADDR_LOCK(ifp); + TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); + IF_ADDR_UNLOCK(ifp); + } else { + /* + * If we DID find one then we clobber any routes + * dependent on it.. + */ + at_scrub(ifp, aa); + } + break; - case SIOCGIFADDR : - sat = satosat( &ifr->ifr_addr ); - nr = (struct netrange *)sat->sat_zero; - if ( nr->nr_phase == 1 ) { - /* - * If the request is specifying phase 1, then - * only look at a phase one address - */ - for ( ; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && - ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { - break; + case SIOCGIFADDR : + sat = satosat(&ifr->ifr_addr); + nr = (struct netrange *)sat->sat_zero; + if (nr->nr_phase == 1) { + struct at_ifaddr *oaa; + + /* + * If the request is specifying phase 1, then + * only look at a phase one address + */ + AT_IFADDR_RUNLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && + (aa->aa_flags & AFA_PHASE2) == 0) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RLOCK(); + } else { + struct at_ifaddr *oaa; + + /* + * default to phase 2 + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && (aa->aa_flags & + AFA_PHASE2)) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); } - } - } else { - /* - * default to phase 2 - */ - for ( ; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { - break; + + if (aa == NULL) { + error = EADDRNOTAVAIL; + goto out; } - } + break; } - if ( aa == (struct at_ifaddr *) 0 ) - return( EADDRNOTAVAIL ); - break; - } - - /* - * By the time this switch is run we should be able to assume that - * the "aa" pointer is valid when needed. - */ - switch ( cmd ) { - case SIOCGIFADDR: - /* - * copy the contents of the sockaddr blindly. + * By the time this switch is run we should be able to assume that + * the "aa" pointer is valid when needed. */ - sat = (struct sockaddr_at *)&ifr->ifr_addr; - *sat = aa->aa_addr; + switch (cmd) { + case SIOCGIFADDR: - /* - * and do some cleanups - */ - ((struct netrange *)&sat->sat_zero)->nr_phase - = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; - ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet; - ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet; - break; + /* + * copy the contents of the sockaddr blindly. + */ + sat = (struct sockaddr_at *)&ifr->ifr_addr; + *sat = aa->aa_addr; - case SIOCSIFADDR: - return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); + /* + * and do some cleanups + */ + ((struct netrange *)&sat->sat_zero)->nr_phase + = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; + ((struct netrange *)&sat->sat_zero)->nr_firstnet = + aa->aa_firstnet; + ((struct netrange *)&sat->sat_zero)->nr_lastnet = + aa->aa_lastnet; + break; - case SIOCAIFADDR: - if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) { - return( 0 ); - } - return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); + case SIOCSIFADDR: + error = at_ifinit(ifp, aa, + (struct sockaddr_at *)&ifr->ifr_addr); + goto out; - case SIOCDIFADDR: - /* - * scrub all routes.. didn't we just DO this? XXX yes, del it - */ - at_scrub( ifp, aa ); + case SIOCAIFADDR: + if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) { + error = 0; + goto out; + } + error = at_ifinit(ifp, aa, + (struct sockaddr_at *)&ifr->ifr_addr); + goto out; - /* - * remove the ifaddr from the interface - */ - ifa0 = (struct ifaddr *)aa; - TAILQ_REMOVE(&ifp->if_addrhead, ifa0, ifa_link); + case SIOCDIFADDR: - /* - * refs goes from 1->0 if no external refs. note.. - * This will not free it ... looks for -1. - */ - IFAFREE(ifa0); + /* + * remove the ifaddr from the interface + */ + ifa = (struct ifaddr *)aa; + IF_ADDR_LOCK(ifp); + TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + IF_ADDR_UNLOCK(ifp); + ifa_free(ifa); /* if_addrhead */ - /* - * Now remove the at_ifaddr from the parallel structure - * as well, or we'd be in deep trouble - */ - 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; - } + /* + * Now remove the at_ifaddr from the parallel structure + * as well, or we'd be in deep trouble + */ - /* - * if we found it, remove it, otherwise we screwed up. - */ - if ( aa->aa_next ) { - aa->aa_next = aa0->aa_next; - } else { - panic( "at_control" ); - } + AT_IFADDR_WLOCK(); + TAILQ_REMOVE(&at_ifaddrhead, aa, aa_link); + AT_IFADDR_WUNLOCK(); + ifa_free(ifa); /* at_ifaddrhead */ + break; + + default: + if (ifp == NULL || ifp->if_ioctl == NULL) { + error = EOPNOTSUPP; + goto out; + } + error = ((*ifp->if_ioctl)(ifp, cmd, data)); } - /* - * Now dump the memory we were using. - * Decrement the reference count. - * This should probably be the last reference - * as the count will go from 0 to -1. - * (unless there is still a route referencing this) - */ - IFAFREE(ifa0); - break; - - default: - if ( ifp == 0 || ifp->if_ioctl == 0 ) - return( EOPNOTSUPP ); - return( (*ifp->if_ioctl)( ifp, cmd, data )); - } - return( 0 ); +out: + if (aa != NULL) + ifa_free(&aa->aa_ifa); + return (error); } /* @@ -334,32 +394,29 @@ * as aa->at_ifaddr.ifa_ifp should be the same. */ static int -at_scrub( ifp, aa ) - struct ifnet *ifp; - struct at_ifaddr *aa; +at_scrub(struct ifnet *ifp, struct at_ifaddr *aa) { - int error; + int error; - if ( aa->aa_flags & AFA_ROUTE ) { - if (ifp->if_flags & IFF_LOOPBACK) { - if ((error = aa_delsingleroute(&aa->aa_ifa, - &aa->aa_addr.sat_addr, - &aa->aa_netmask.sat_addr)) != 0) { - return( error ); + if (aa->aa_flags & AFA_ROUTE) { + if (ifp->if_flags & IFF_LOOPBACK) { + if ((error = aa_delsingleroute(&aa->aa_ifa, + &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr)) + != 0) + return (error); + } else if (ifp->if_flags & IFF_POINTOPOINT) { + if ((error = rtinit(&aa->aa_ifa, RTM_DELETE, + RTF_HOST)) != 0) + return (error); + } else if (ifp->if_flags & IFF_BROADCAST) { + error = aa_dorangeroute(&aa->aa_ifa, + ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), + RTM_DELETE); } - } else if (ifp->if_flags & IFF_POINTOPOINT) { - if ((error = rtinit( &aa->aa_ifa, RTM_DELETE, RTF_HOST)) != 0) - return( error ); - } else if (ifp->if_flags & IFF_BROADCAST) { - error = aa_dorangeroute(&aa->aa_ifa, - ntohs(aa->aa_firstnet), - ntohs(aa->aa_lastnet), - RTM_DELETE ); + aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; + aa->aa_flags &= ~AFA_ROUTE; } - aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; - aa->aa_flags &= ~AFA_ROUTE; - } - return( 0 ); + return (0); } /* @@ -367,336 +424,331 @@ * bang them all together at high speed and see what happens */ static int -at_ifinit( ifp, aa, sat ) - struct ifnet *ifp; - struct at_ifaddr *aa; - struct sockaddr_at *sat; +at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, struct sockaddr_at *sat) { - struct netrange nr, onr; - struct sockaddr_at oldaddr; - int s = splimp(), error = 0, i, j; - int netinc, nodeinc, nnets; - u_short net; + struct netrange nr, onr; + struct sockaddr_at oldaddr; + int error = 0, i, j; + int netinc, nodeinc, nnets; + u_short net; - /* - * save the old addresses in the at_ifaddr just in case we need them. - */ - oldaddr = aa->aa_addr; - onr.nr_firstnet = aa->aa_firstnet; - onr.nr_lastnet = aa->aa_lastnet; + /* + * save the old addresses in the at_ifaddr just in case we need them. + */ + oldaddr = aa->aa_addr; + onr.nr_firstnet = aa->aa_firstnet; + onr.nr_lastnet = aa->aa_lastnet; - /* - * take the address supplied as an argument, and add it to the - * at_ifnet (also given). Remember ing to update - * those parts of the at_ifaddr that need special processing - */ - bzero( AA_SAT( aa ), sizeof( struct sockaddr_at )); - bcopy( sat->sat_zero, &nr, sizeof( struct netrange )); - bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange )); - nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1; - aa->aa_firstnet = nr.nr_firstnet; - aa->aa_lastnet = nr.nr_lastnet; + /* + * take the address supplied as an argument, and add it to the + * at_ifnet (also given). Remember ing to update + * those parts of the at_ifaddr that need special processing + */ + bzero(AA_SAT(aa), sizeof(struct sockaddr_at)); + bcopy(sat->sat_zero, &nr, sizeof(struct netrange)); + bcopy(sat->sat_zero, AA_SAT(aa)->sat_zero, sizeof(struct netrange)); + nnets = ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet) + 1; + aa->aa_firstnet = nr.nr_firstnet; + aa->aa_lastnet = nr.nr_lastnet; /* XXX ALC */ #if 0 - printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", - ifp->if_name, - ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, - ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), - (aa->aa_flags & AFA_PHASE2) ? 2 : 1); + printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", + ifp->if_name, + ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, + ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), + (aa->aa_flags & AFA_PHASE2) ? 2 : 1); #endif - /* - * We could eliminate the need for a second phase 1 probe (post - * autoconf) if we check whether we're resetting the node. Note - * that phase 1 probes use only nodes, not net.node pairs. Under - * phase 2, both the net and node must be the same. - */ - if ( ifp->if_flags & IFF_LOOPBACK ) { - AA_SAT( aa )->sat_len = sat->sat_len; - AA_SAT( aa )->sat_family = AF_APPLETALK; - AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net; - AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; -#if 0 - } else if ( fp->if_flags & IFF_POINTOPOINT) { - /* unimplemented */ /* - * we'd have to copy the dstaddr field over from the sat - * but it's not clear that it would contain the right info.. + * We could eliminate the need for a second phase 1 probe (post + * autoconf) if we check whether we're resetting the node. Note + * that phase 1 probes use only nodes, not net.node pairs. Under + * phase 2, both the net and node must be the same. */ + if (ifp->if_flags & IFF_LOOPBACK) { + AA_SAT(aa)->sat_len = sat->sat_len; + AA_SAT(aa)->sat_family = AF_APPLETALK; + AA_SAT(aa)->sat_addr.s_net = sat->sat_addr.s_net; + AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; +#if 0 + } else if (fp->if_flags & IFF_POINTOPOINT) { + /* unimplemented */ + /* + * we'd have to copy the dstaddr field over from the sat + * but it's not clear that it would contain the right info.. + */ #endif - } else { - /* - * We are a normal (probably ethernet) interface. - * apply the new address to the interface structures etc. - * We will probe this address on the net first, before - * applying it to ensure that it is free.. If it is not, then - * we will try a number of other randomly generated addresses - * in this net and then increment the net. etc.etc. until - * we find an unused address. - */ - aa->aa_flags |= AFA_PROBING; /* if not loopback we Must probe? */ - AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at); - AA_SAT( aa )->sat_family = AF_APPLETALK; - if ( aa->aa_flags & AFA_PHASE2 ) { - if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { + } else { /* - * If we are phase 2, and the net was not specified - * then we select a random net within the supplied netrange. - * XXX use /dev/random? + * We are a normal (probably ethernet) interface. + * apply the new address to the interface structures etc. + * We will probe this address on the net first, before + * applying it to ensure that it is free.. If it is not, then + * we will try a number of other randomly generated addresses + * in this net and then increment the net. etc.etc. until + * we find an unused address. */ - if ( nnets != 1 ) { - net = ntohs( nr.nr_firstnet ) + time_second % ( nnets - 1 ); + aa->aa_flags |= AFA_PROBING; /* not loopback we Must probe? */ + AA_SAT(aa)->sat_len = sizeof(struct sockaddr_at); + AA_SAT(aa)->sat_family = AF_APPLETALK; + if (aa->aa_flags & AFA_PHASE2) { + if (sat->sat_addr.s_net == ATADDR_ANYNET) { + /* + * If we are phase 2, and the net was not + * specified then we select a random net + * within the supplied netrange. + * XXX use /dev/random? + */ + if (nnets != 1) + net = ntohs(nr.nr_firstnet) + + time_second % (nnets - 1); + else + net = ntohs(nr.nr_firstnet); + } else { + /* + * if a net was supplied, then check that it + * is within the netrange. If it is not then + * replace the old values and return an error + */ + 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); + } + /* + * otherwise just use the new net number.. + */ + net = ntohs(sat->sat_addr.s_net); + } } else { - net = ntohs( nr.nr_firstnet ); + /* + * we must be phase one, so just use whatever we were + * given. I guess it really isn't going to be + * used... RIGHT? + */ + net = ntohs(sat->sat_addr.s_net); } - } else { - /* - * if a net was supplied, then check that it is within - * the netrange. If it is not then replace the old values - * and return an error + + /* + * set the node part of the address into the ifaddr. + * If it's not specified, be random about it... + * XXX use /dev/random? */ - if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) || - ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) { - aa->aa_addr = oldaddr; - aa->aa_firstnet = onr.nr_firstnet; - aa->aa_lastnet = onr.nr_lastnet; - splx(s); - return( EINVAL ); + if (sat->sat_addr.s_node == ATADDR_ANYNODE) + AA_SAT(aa)->sat_addr.s_node = time_second; + else + AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; + + /* + * Copy the phase. + */ + AA_SAT(aa)->sat_range.r_netrange.nr_phase = + ((aa->aa_flags & AFA_PHASE2) ? 2:1); + + /* + * step through the nets in the range + * starting at the (possibly random) start point. + */ + 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); + + /* + * using a rather strange stepping method, + * stagger through the possible node addresses + * Once again, starting at the (possibly random) + * initial node address. + */ + for (j = 0, nodeinc = time_second | 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; + + /* + * start off the probes as an asynchronous + * activity. though why wait 200mSec? + */ + AARPTAB_LOCK(); + callout_reset(&aa->aa_callout, hz / 5, + aarpprobe, ifp); + if (msleep(aa, &aarptab_mtx, PPAUSE|PCATCH, + "at_ifinit", 0)) { + AARPTAB_UNLOCK(); + /* + * theoretically we shouldn't time + * out here so if we returned with an + * error.. + */ + 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); + } + AARPTAB_UNLOCK(); + + /* + * The async activity should have woken us + * up. We need to see if it was successful + * in finding a free spot, or if we need to + * iterate to the next address to try. + */ + if ((aa->aa_flags & AFA_PROBING) == 0) + break; + } + + /* + * of course we need to break out through two loops... + */ + if ((aa->aa_flags & AFA_PROBING) == 0) + break; + /* reset node for next network */ + AA_SAT(aa)->sat_addr.s_node = time_second; } + /* - * otherwise just use the new net number.. + * if we are still trying to probe, then we have finished all + * the possible addresses, so we need to give up */ - net = ntohs( sat->sat_addr.s_net ); - } - } else { - /* - * we must be phase one, so just use whatever we were given. - * I guess it really isn't going to be used... RIGHT? - */ - net = ntohs( sat->sat_addr.s_net ); + if (aa->aa_flags & AFA_PROBING) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (EADDRINUSE); + } } /* - * set the node part of the address into the ifaddr. - * If it's not specified, be random about it... - * XXX use /dev/random? + * Now that we have selected an address, we need to tell the interface + * about it, just in case it needs to adjust something. */ - if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) { - AA_SAT( aa )->sat_addr.s_node = time_second; - } else { - AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; + if (ifp->if_ioctl != NULL && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)aa))) { + /* + * of course this could mean that it objects violently + * so if it does, we back out again.. + */ + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (error); } /* - * Copy the phase. + * set up the netmask part of the at_ifaddr + * and point the appropriate pointer in the ifaddr to it. + * probably pointless, but what the heck.. XXX */ - AA_SAT( aa )->sat_range.r_netrange.nr_phase - = ((aa->aa_flags & AFA_PHASE2) ? 2:1); + bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); + aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); + aa->aa_netmask.sat_family = AF_APPLETALK; + aa->aa_netmask.sat_addr.s_net = 0xffff; + aa->aa_netmask.sat_addr.s_node = 0; + aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ - /* - * step through the nets in the range - * starting at the (possibly random) start point. + /* + * Initialize broadcast (or remote p2p) address */ - 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 ); + bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); + aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); + aa->aa_broadaddr.sat_family = AF_APPLETALK; - /* - * using a rather strange stepping method, - * stagger through the possible node addresses - * Once again, starting at the (possibly random) - * initial node address. - */ - for ( j = 0, nodeinc = time_second | 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; + aa->aa_ifa.ifa_metric = ifp->if_metric; + if (ifp->if_flags & IFF_BROADCAST) { + aa->aa_broadaddr.sat_addr.s_net = htons(0); + aa->aa_broadaddr.sat_addr.s_node = 0xff; + aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) + &aa->aa_broadaddr; + /* add the range of routes needed */ + error = aa_dorangeroute(&aa->aa_ifa, ntohs(aa->aa_firstnet), + ntohs(aa->aa_lastnet), RTM_ADD); + } else if (ifp->if_flags & IFF_POINTOPOINT) { + struct at_addr rtaddr, rtmask; - /* - * start off the probes as an asynchronous activity. - * though why wait 200mSec? - */ - aa->aa_ch = timeout( aarpprobe, (caddr_t)ifp, hz / 5 ); - if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) { - /* - * theoretically we shouldn't time out here - * so if we returned with an error.. - */ - printf( "at_ifinit: why did this happen?!\n" ); - aa->aa_addr = oldaddr; - aa->aa_firstnet = onr.nr_firstnet; - aa->aa_lastnet = onr.nr_lastnet; - splx( s ); - return( EINTR ); - } + bzero(&rtaddr, sizeof(rtaddr)); + bzero(&rtmask, sizeof(rtmask)); + /* fill in the far end if we know it here XXX */ + aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; + error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); + } else if (ifp->if_flags & IFF_LOOPBACK) { + struct at_addr rtaddr, rtmask; - /* - * The async activity should have woken us up. - * We need to see if it was successful in finding - * a free spot, or if we need to iterate to the next - * address to try. - */ - if (( aa->aa_flags & AFA_PROBING ) == 0 ) { - break; - } - } - - /* - * of course we need to break out through two loops... - */ - if (( aa->aa_flags & AFA_PROBING ) == 0 ) { - break; - } - /* reset node for next network */ - AA_SAT( aa )->sat_addr.s_node = time_second; + bzero(&rtaddr, sizeof(rtaddr)); + bzero(&rtmask, sizeof(rtmask)); + rtaddr.s_net = AA_SAT(aa)->sat_addr.s_net; + rtaddr.s_node = AA_SAT(aa)->sat_addr.s_node; + rtmask.s_net = 0xffff; + /* XXX should not be so.. should be HOST route */ + rtmask.s_node = 0x0; + error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); } /* - * if we are still trying to probe, then we have finished all - * the possible addresses, so we need to give up + * set the address of our "check if this addr is ours" routine. */ + aa->aa_ifa.ifa_claim_addr = aa_claim_addr; - 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 ); + /* + * of course if we can't add these routes we back out, but it's + * getting risky by now XXX + */ + if (error) { + at_scrub(ifp, aa); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (error); } - } - /* - * Now that we have selected an address, we need to tell the interface - * about it, just in case it needs to adjust something. - */ - if ( ifp->if_ioctl && - ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t)aa ))) { /* - * of course this could mean that it objects violently - * so if it does, we back out again.. + * note that the address has a route associated with it.... */ - aa->aa_addr = oldaddr; - aa->aa_firstnet = onr.nr_firstnet; - aa->aa_lastnet = onr.nr_lastnet; - splx( s ); - return( error ); - } - - /* - * set up the netmask part of the at_ifaddr - * and point the appropriate pointer in the ifaddr to it. - * probably pointless, but what the heck.. XXX - */ - bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); - aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); - aa->aa_netmask.sat_family = AF_APPLETALK; - aa->aa_netmask.sat_addr.s_net = 0xffff; - aa->aa_netmask.sat_addr.s_node = 0; - aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ - - /* - * Initialize broadcast (or remote p2p) address - */ - bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); - aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); - aa->aa_broadaddr.sat_family = AF_APPLETALK; - - aa->aa_ifa.ifa_metric = ifp->if_metric; - if (ifp->if_flags & IFF_BROADCAST) { - aa->aa_broadaddr.sat_addr.s_net = htons(0); - aa->aa_broadaddr.sat_addr.s_node = 0xff; - aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr; - /* add the range of routes needed */ - error = aa_dorangeroute(&aa->aa_ifa, - ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD ); - } - else if (ifp->if_flags & IFF_POINTOPOINT) { - struct at_addr rtaddr, rtmask; - - bzero(&rtaddr, sizeof(rtaddr)); - bzero(&rtmask, sizeof(rtmask)); - /* fill in the far end if we know it here XXX */ - aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; - error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); - } - else if ( ifp->if_flags & IFF_LOOPBACK ) { - struct at_addr rtaddr, rtmask; - - bzero(&rtaddr, sizeof(rtaddr)); - bzero(&rtmask, sizeof(rtmask)); - rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net; - rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node; - rtmask.s_net = 0xffff; - rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */ - error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); - } - - - /* - * set the address of our "check if this addr is ours" routine. - */ - aa->aa_ifa.ifa_claim_addr = aa_claim_addr; - - /* - * of course if we can't add these routes we back out, but it's getting - * risky by now XXX - */ - if ( error ) { - at_scrub( ifp, aa ); - aa->aa_addr = oldaddr; - aa->aa_firstnet = onr.nr_firstnet; - aa->aa_lastnet = onr.nr_lastnet; - splx( s ); - return( error ); - } - - /* - * note that the address has a route associated with it.... - */ - aa->aa_ifa.ifa_flags |= IFA_ROUTE; - aa->aa_flags |= AFA_ROUTE; - splx( s ); - return( 0 ); + aa->aa_ifa.ifa_flags |= IFA_ROUTE; + aa->aa_flags |= AFA_ROUTE; + return (0); } /* * check whether a given address is a broadcast address for us.. */ int -at_broadcast( sat ) - struct sockaddr_at *sat; +at_broadcast(struct sockaddr_at *sat) { - struct at_ifaddr *aa; + struct at_ifaddr *aa; - /* - * If the node is not right, it can't be a broadcast - */ - if ( sat->sat_addr.s_node != ATADDR_BCAST ) { - return( 0 ); - } + AT_IFADDR_LOCK_ASSERT(); - /* - * If the node was right then if the net is right, it's a broadcast - */ - if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { - return( 1 ); - } + /* + * If the node is not right, it can't be a broadcast + */ + if (sat->sat_addr.s_node != ATADDR_BCAST) + return (0); - /* - * failing that, if the net is one we have, it's a broadcast as well. - */ - 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 ); + /* + * If the node was right then if the net is right, it's a broadcast + */ + if (sat->sat_addr.s_net == ATADDR_ANYNET) + return (1); + + /* + * failing that, if the net is one we have, it's a broadcast as well. + */ + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + 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 ); + return (0); } /* @@ -736,112 +788,71 @@ while (bot <= top) { mask1 = 1; - while ((( bot & ~mask1) >= bot) - && (( bot | mask1) <= top)) { + while (((bot & ~mask1) >= bot) && ((bot | mask1) <= top)) { mask1 <<= 1; mask1 |= 1; } mask1 >>= 1; mask.s_net = htons(~mask1); addr.s_net = htons(bot); - if(cmd == RTM_ADD) { - error = aa_addsingleroute(ifa,&addr,&mask); + if (cmd == RTM_ADD) { + error = aa_addsingleroute(ifa,&addr,&mask); if (error) { /* XXX clean up? */ return (error); } - } else { + } else error = aa_delsingleroute(ifa,&addr,&mask); - } bot = (bot | mask1) + 1; } - return 0; + return (0); } static int -aa_addsingleroute(struct ifaddr *ifa, - struct at_addr *addr, struct at_addr *mask) +aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask) { - int error; #if 0 - printf("aa_addsingleroute: %x.%x mask %x.%x ...\n", - ntohs(addr->s_net), addr->s_node, - ntohs(mask->s_net), mask->s_node); + printf("aa_addsingleroute: %x.%x mask %x.%x ...\n", + ntohs(addr->s_net), addr->s_node, ntohs(mask->s_net), + mask->s_node); #endif - error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP); - if (error) - printf("aa_addsingleroute: error %d\n", error); - return(error); + return (aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP)); } static int -aa_delsingleroute(struct ifaddr *ifa, - struct at_addr *addr, struct at_addr *mask) +aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask) { - int error; - error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0); - if (error) - printf("aa_delsingleroute: error %d\n", error); - return(error); + return (aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0)); } static int -aa_dosingleroute(struct ifaddr *ifa, - struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags) +aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, + struct at_addr *at_mask, int cmd, int flags) { - struct sockaddr_at addr, mask; + struct sockaddr_at addr, mask; - bzero(&addr, sizeof(addr)); - bzero(&mask, sizeof(mask)); - addr.sat_family = AF_APPLETALK; - addr.sat_len = sizeof(struct sockaddr_at); - addr.sat_addr.s_net = at_addr->s_net; - addr.sat_addr.s_node = at_addr->s_node; - mask.sat_family = AF_APPLETALK; - mask.sat_len = sizeof(struct sockaddr_at); - mask.sat_addr.s_net = at_mask->s_net; - mask.sat_addr.s_node = at_mask->s_node; - if (at_mask->s_node) - flags |= RTF_HOST; - return(rtrequest(cmd, (struct sockaddr *) &addr, - (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), - (struct sockaddr *) &mask, flags, NULL)); + bzero(&addr, sizeof(addr)); + bzero(&mask, sizeof(mask)); + addr.sat_family = AF_APPLETALK; + addr.sat_len = sizeof(struct sockaddr_at); + addr.sat_addr.s_net = at_addr->s_net; + addr.sat_addr.s_node = at_addr->s_node; + mask.sat_family = AF_APPLETALK; + mask.sat_len = sizeof(struct sockaddr_at); + mask.sat_addr.s_net = at_mask->s_net; + mask.sat_addr.s_node = at_mask->s_node; + if (at_mask->s_node) + flags |= RTF_HOST; + return (rtrequest(cmd, (struct sockaddr *) &addr, + (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), + (struct sockaddr *) &mask, flags, NULL)); } -#if 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" ); - } - } - } -} - -#endif - static int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw0) { @@ -851,7 +862,8 @@ switch (gw->sat_range.r_netrange.nr_phase) { case 1: if(addr->sat_range.r_netrange.nr_phase == 1) - return 1; + return (1); + case 0: case 2: /* @@ -860,16 +872,15 @@ * then it's ours. */ if ((addr->sat_addr.s_net == gw->sat_addr.s_net) - || ((addr->sat_range.r_netrange.nr_lastnet) - && (ntohs(gw->sat_addr.s_net) - >= ntohs(addr->sat_range.r_netrange.nr_firstnet )) - && (ntohs(gw->sat_addr.s_net) - <= ntohs(addr->sat_range.r_netrange.nr_lastnet )))) { - return 1; - } + || ((addr->sat_range.r_netrange.nr_lastnet) + && (ntohs(gw->sat_addr.s_net) >= + ntohs(addr->sat_range.r_netrange.nr_firstnet)) + && (ntohs(gw->sat_addr.s_net) <= + ntohs(addr->sat_range.r_netrange.nr_lastnet)))) + return (1); break; default: printf("atalk: bad phase\n"); } - return 0; + return (0); } Index: ddp_usrreq.c =================================================================== --- ddp_usrreq.c (.../stable/4/sys/netatalk) (revision 196046) +++ ddp_usrreq.c (.../head/sys/netatalk) (revision 196046) @@ -1,11 +1,57 @@ -/* - * Copyright (c) 1990,1994 Regents of The University of Michigan. - * All Rights Reserved. See COPYRIGHT. +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ */ #include #include -#include #include #include #include @@ -13,573 +59,273 @@ #include #include #include +#include #include #include #include +#include #include -static void at_pcbdisconnect( struct ddpcb *ddp ); -static void at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr); -static int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, - struct proc *p); -static int at_pcbconnect(struct ddpcb *ddp, struct sockaddr *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; static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ -static u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at )); +static u_long ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at)); +static const struct netisr_handler atalk1_nh = { + .nh_name = "atalk1", + .nh_handler = at1intr, + .nh_proto = NETISR_ATALK1, + .nh_policy = NETISR_POLICY_SOURCE, +}; +static const struct netisr_handler atalk2_nh = { + .nh_name = "atalk2", + .nh_handler = at2intr, + .nh_proto = NETISR_ATALK2, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static const struct netisr_handler aarp_nh = { + .nh_name = "aarp", + .nh_handler = aarpintr, + .nh_proto = NETISR_AARP, + .nh_policy = NETISR_POLICY_SOURCE, +}; + static int -ddp_attach(struct socket *so, int proto, struct proc *p) +ddp_attach(struct socket *so, int proto, struct thread *td) { - struct ddpcb *ddp; - int error = 0; - int s; + int error = 0; + KASSERT(sotoddpcb(so) == NULL, ("ddp_attach: ddp != NULL")); - ddp = sotoddpcb( so ); - if ( ddp != NULL ) { - return( EINVAL); - } + /* + * Allocate socket buffer space first so that it's present + * before first use. + */ + error = soreserve(so, ddp_sendspace, ddp_recvspace); + if (error) + return (error); - s = splnet(); - error = at_pcballoc( so ); - splx(s); - if (error) { - return (error); - } - return (soreserve( so, ddp_sendspace, ddp_recvspace )); + DDP_LIST_XLOCK(); + error = at_pcballoc(so); + DDP_LIST_XUNLOCK(); + return (error); } -static int +static void ddp_detach(struct socket *so) { - struct ddpcb *ddp; - int s; + struct ddpcb *ddp; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return( EINVAL); - } - s = splnet(); - at_pcbdetach( so, ddp ); - splx(s); - return(0); + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + at_pcbdetach(so, ddp); + DDP_LIST_XUNLOCK(); } static int -ddp_bind(struct socket *so, struct sockaddr *nam, struct proc *p) +ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) { - struct ddpcb *ddp; - int error = 0; - int s; + struct ddpcb *ddp; + int error = 0; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return( EINVAL); - } - s = splnet(); - error = at_pcbsetaddr(ddp, nam, p); - splx(s); + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + error = at_pcbsetaddr(ddp, nam, td); + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); return (error); } static int -ddp_connect(struct socket *so, struct sockaddr *nam, struct proc *p) +ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { - struct ddpcb *ddp; - int error = 0; - int s; + struct ddpcb *ddp; + int error = 0; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return( EINVAL); - } + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); - if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { - return(EISCONN); + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + return (EISCONN); } - s = splnet(); - error = at_pcbconnect( ddp, nam, p ); - splx(s); - if ( error == 0 ) - soisconnected( so ); - return(error); + error = at_pcbconnect( ddp, nam, td ); + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + if (error == 0) + soisconnected(so); + return (error); } static int ddp_disconnect(struct socket *so) { - - struct ddpcb *ddp; - int s; + struct ddpcb *ddp; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return( EINVAL); + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); + + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { + DDP_UNLOCK(ddp); + return (ENOTCONN); } - if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) { - return(ENOTCONN); - } - s = splnet(); - at_pcbdisconnect( ddp ); + at_pcbdisconnect(ddp); ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; - splx(s); - soisdisconnected( so ); - return(0); + DDP_UNLOCK(ddp); + soisdisconnected(so); + return (0); } static int ddp_shutdown(struct socket *so) { - struct ddpcb *ddp; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return( EINVAL); - } - socantsendmore( so ); - return(0); + KASSERT(sotoddpcb(so) != NULL, ("ddp_shutdown: ddp == NULL")); + + socantsendmore(so); + return (0); } static int ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct proc *p) + struct mbuf *control, struct thread *td) { - struct ddpcb *ddp; - int error = 0; - int s; + struct ddpcb *ddp; + int error = 0; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return(EINVAL); - } + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); - if ( control && control->m_len ) { - return(EINVAL); - } + if (control && control->m_len) + return (EINVAL); - if ( addr ) { - if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { - return(EISCONN); + if (addr != NULL) { + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { + error = EISCONN; + goto out; } - s = splnet(); - error = at_pcbconnect(ddp, addr, p); - splx( s ); - if ( error ) { - return(error); + error = at_pcbconnect(ddp, addr, td); + if (error == 0) { + error = ddp_output(m, so); + at_pcbdisconnect(ddp); } +out: + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); } else { - if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) { - return(ENOTCONN); - } + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) + error = ENOTCONN; + else + error = ddp_output(m, so); + DDP_UNLOCK(ddp); } - - s = splnet(); - error = ddp_output( m, so ); - if ( addr ) { - at_pcbdisconnect( ddp ); - } - splx(s); - return(error); + return (error); } -static int +/* + * XXXRW: This is never called because we only invoke abort on stream + * protocols. + */ +static void ddp_abort(struct socket *so) { struct ddpcb *ddp; - int s; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return(EINVAL); - } - soisdisconnected( so ); - s = splnet(); - at_pcbdetach( so, ddp ); - splx(s); - return(0); + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); + + DDP_LOCK(ddp); + at_pcbdisconnect(ddp); + DDP_UNLOCK(ddp); + soisdisconnected(so); } - static void -at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr) +ddp_close(struct socket *so) { - *addr = dup_sockaddr((struct sockaddr *)&ddp->ddp_lsat, 0); -} + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_close: ddp == NULL")); -static int -at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *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 = (struct sockaddr_at *)addr; - if (sat->sat_family != AF_APPLETALK) { - return(EAFNOSUPPORT); - } - - if ( sat->sat_addr.s_node != ATADDR_ANYNODE || - sat->sat_addr.s_net != ATADDR_ANYNET ) { - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && - ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { - break; - } - } - if ( !aa ) { - return( EADDRNOTAVAIL ); - } - } - - if ( sat->sat_port != ATADDR_ANYPORT ) { - if ( sat->sat_port < ATPORT_FIRST || - sat->sat_port >= ATPORT_LAST ) { - return( EINVAL ); - } - if ( sat->sat_port < ATPORT_RESERVED && - suser(p) ) { - return( EACCES ); - } - } - } else { - bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); - lsat.sat_len = sizeof(struct sockaddr_at); - lsat.sat_addr.s_node = ATADDR_ANYNODE; - lsat.sat_addr.s_net = ATADDR_ANYNET; - 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 ); + DDP_LOCK(ddp); + at_pcbdisconnect(ddp); + DDP_UNLOCK(ddp); + soisdisconnected(so); } -static int -at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p) +void +ddp_init(void) { - struct sockaddr_at *sat = (struct sockaddr_at *)addr; - struct route *ro; - struct at_ifaddr *aa = 0; - struct ifnet *ifp; - u_short hintnet = 0, net; - 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) != NULL) { - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && - ntohs( net ) >= ntohs( aa->aa_firstnet ) && - ntohs( net ) <= ntohs( aa->aa_lastnet )) { - break; - } - } - } - if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net != - ( hintnet ? hintnet : sat->sat_addr.s_net ) || - satosat( &ro->ro_dst )->sat_addr.s_node != - sat->sat_addr.s_node )) { - RTFREE( ro->ro_rt ); - ro->ro_rt = (struct rtentry *)0; - } - } - - /* - * If we've got no route for this interface, try to find one. - */ - if ( ro->ro_rt == (struct rtentry *)0 || - ro->ro_rt->rt_ifp == (struct ifnet *)0 ) { - ro->ro_dst.sa_len = sizeof( struct sockaddr_at ); - ro->ro_dst.sa_family = AF_APPLETALK; - if ( hintnet ) { - satosat( &ro->ro_dst )->sat_addr.s_net = hintnet; - } else { - satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net; - } - satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node; - rtalloc( ro ); - } - - /* - * Make sure any route that we have has a valid interface. - */ - aa = 0; - if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp ) { - break; - } - } - } - if ( aa == 0 ) { - return( ENETUNREACH ); - } - - ddp->ddp_fsat = *sat; - if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { - return(at_pcbsetaddr(ddp, (struct sockaddr *)0, p)); - } - return( 0 ); + DDP_LIST_LOCK_INIT(); + TAILQ_INIT(&at_ifaddrhead); + netisr_register(&atalk1_nh); + netisr_register(&atalk2_nh); + netisr_register(&aarp_nh); } +#if 0 static void -at_pcbdisconnect( struct ddpcb *ddp ) +ddp_clean(void) { - 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; + struct ddpcp *ddp; + + for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) + at_pcbdetach(ddp->ddp_socket, ddp); + DDP_LIST_LOCK_DESTROY(); } +#endif static int -at_pcballoc( struct socket *so ) +at_getpeeraddr(struct socket *so, struct sockaddr **nam) { - struct ddpcb *ddp; - MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_WAITOK); - bzero(ddp, sizeof *ddp); - 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); + return (EOPNOTSUPP); } -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; - } - FREE(ddp, M_PCB); -} - -/* - * 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 ); -} static int -at_setpeeraddr(struct socket *so, struct sockaddr **nam) +at_getsockaddr(struct socket *so, struct sockaddr **nam) { - return(EOPNOTSUPP); -} - -static int -at_setsockaddr(struct socket *so, struct sockaddr **nam) -{ struct ddpcb *ddp; - ddp = sotoddpcb( so ); - if ( ddp == NULL ) { - return( EINVAL); - } - at_sockaddr( ddp, nam ); - return(0); -} + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("at_getsockaddr: ddp == NULL")); - -void -ddp_init(void ) -{ - atintrq1.ifq_maxlen = IFQ_MAXLEN; - atintrq2.ifq_maxlen = IFQ_MAXLEN; + DDP_LOCK(ddp); + at_sockaddr(ddp, nam); + DDP_UNLOCK(ddp); + return (0); } -#if 0 -static void -ddp_clean(void ) -{ - struct ddpcb *ddp; - - for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) { - at_pcbdetach( ddp->ddp_socket, ddp ); - } -} -#endif - struct pr_usrreqs ddp_usrreqs = { - ddp_abort, - pru_accept_notsupp, - ddp_attach, - ddp_bind, - ddp_connect, - pru_connect2_notsupp, - at_control, - ddp_detach, - ddp_disconnect, - pru_listen_notsupp, - at_setpeeraddr, - pru_rcvd_notsupp, - pru_rcvoob_notsupp, - ddp_send, - pru_sense_null, - ddp_shutdown, - at_setsockaddr, - sosend, - soreceive, - sopoll + .pru_abort = ddp_abort, + .pru_attach = ddp_attach, + .pru_bind = ddp_bind, + .pru_connect = ddp_connect, + .pru_control = at_control, + .pru_detach = ddp_detach, + .pru_disconnect = ddp_disconnect, + .pru_peeraddr = at_getpeeraddr, + .pru_send = ddp_send, + .pru_shutdown = ddp_shutdown, + .pru_sockaddr = at_getsockaddr, + .pru_close = ddp_close, }; Index: at.h =================================================================== --- at.h (.../stable/4/sys/netatalk) (revision 196046) +++ at.h (.../head/sys/netatalk) (revision 196046) @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. * @@ -23,64 +23,64 @@ * $FreeBSD$ */ -#ifndef __AT_HEADER__ -#define __AT_HEADER__ +#ifndef _NETATALK_AT_H_ +#define _NETATALK_AT_H_ + /* * Supported protocols */ -#define ATPROTO_DDP 0 -#define ATPROTO_AARP 254 +#define ATPROTO_DDP 0 +#define ATPROTO_AARP 254 -#define DDP_MAXSZ 587 +#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 + * If ATPORT_FIRST <= Port < ATPORT_RESERVED, the port was created by a * privileged process. + * + * If ATPORT_RESERVED <= Port < ATPORT_LAST, the port was not necessarily + * created by a privileged process. */ -#define ATPORT_FIRST 1 -#define ATPORT_RESERVED 128 -#define ATPORT_LAST 255 +#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; + u_short s_net; + u_char s_node; }; -#define ATADDR_ANYNET (u_short)0x0000 -#define ATADDR_ANYNODE (u_char)0x00 -#define ATADDR_ANYPORT (u_char)0x00 -#define ATADDR_BCAST (u_char)0xff /* There is no BCAST for NET */ +#define ATADDR_ANYNET (u_short)0x0000 +#define ATADDR_ANYNODE (u_char)0x00 +#define ATADDR_ANYPORT (u_char)0x00 +#define ATADDR_BCAST (u_char)0xff /* There is no BCAST for NET. */ struct netrange { - u_char nr_phase; - u_short nr_firstnet; - u_short nr_lastnet; + u_char nr_phase; + u_short nr_firstnet; + u_short nr_lastnet; }; /* - * Socket address, AppleTalk style. We keep magic information in the - * zero bytes. There are three types, NONE, CONFIG which has the phase - * and a net range, and IFACE which has the network address of an - * interface. IFACE may be filled in by the client, and is filled in - * by the kernel. + * Socket address, AppleTalk style. We keep magic information in the zero + * bytes. There are three types, NONE, CONFIG which has the phase and a net + * range, and IFACE which has the network address of an interface. IFACE may + * be filled in by the client, and is filled in by the kernel. */ struct sockaddr_at { - u_char sat_len; - u_char sat_family; - u_char sat_port; - struct at_addr sat_addr; - union { - struct netrange r_netrange; - char r_zero[ 8 ]; /* Hide a struct netrange in here */ - } sat_range; + u_char sat_len; + u_char sat_family; + u_char sat_port; + struct at_addr sat_addr; + union { + struct netrange r_netrange; + char r_zero[8]; /* Hide struct netrange here. */ + } sat_range; }; -#define sat_zero sat_range.r_zero +#define sat_zero sat_range.r_zero -#endif /* !__AT_HEADER__ */ +#endif /* !_NETATALK_AT_H_ */ Index: ddp.h =================================================================== --- ddp.h (.../stable/4/sys/netatalk) (revision 196046) +++ ddp.h (.../head/sys/netatalk) (revision 196046) @@ -1,5 +1,5 @@ -/* - * Copyright (c) 1990,1991 Regents of The University of Michigan. +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and @@ -19,11 +19,14 @@ * Ann Arbor, Michigan * +1-313-763-0525 * netatalk@itd.umich.edu + * + * $FreeBSD$ */ + #ifndef _NETATALK_DDP_H_ -#define _NETATALK_DDP_H_ 1 +#define _NETATALK_DDP_H_ -/* +/*- * <-1byte(8bits) -> * +---------------+ * | 0 | hopc |len| @@ -51,83 +54,84 @@ * | 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. + * 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; -}; + u_char el_dnode; + u_char el_snode; + u_char el_type; +} __packed; #define SZ_ELAPHDR 3 -#define ELAP_DDPSHORT 0x01 -#define ELAP_DDPEXTEND 0x02 +#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 { + union { + struct { #if BYTE_ORDER == BIG_ENDIAN - unsigned dub_pad:2; - unsigned dub_hops:4; - unsigned dub_len:10; - unsigned dub_sum:16; + 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; + 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; -}; + } __packed du_bits; + unsigned du_bytes; + } deh_u; + u_short deh_dnet; + u_short deh_snet; + u_char deh_dnode; + u_char deh_snode; + u_char deh_dport; + u_char deh_sport; +} __packed; +#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 -#define DDP_MAXHOPS 15 +#define DDP_MAXHOPS 15 struct ddpshdr { - union { - struct { + union { + struct { #if BYTE_ORDER == BIG_ENDIAN - unsigned dub_pad:6; - unsigned dub_len:10; - unsigned dub_dport:8; - unsigned dub_sport:8; + 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; + 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 -}; + } __packed du_bits; + unsigned du_bytes; + } dsh_u; +} __packed; +#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_ */ Index: at_var.h =================================================================== --- at_var.h (.../stable/4/sys/netatalk) (revision 196046) +++ at_var.h (.../head/sys/netatalk) (revision 196046) @@ -1,5 +1,5 @@ -/* - * Copyright (c) 1990,1991 Regents of The University of Michigan. +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and @@ -24,44 +24,54 @@ */ #ifndef _NETATALK_AT_VAR_H_ -#define _NETATALK_AT_VAR_H_ 1 +#define _NETATALK_AT_VAR_H_ + /* - * For phase2, we need to keep not only our address on an interface, - * but also the legal networks on the interface. + * For phase2, we need to keep not only our address on an interface, but also + * the legal networks on the interface. */ struct at_ifaddr { - struct ifaddr aa_ifa; -# define aa_ifp aa_ifa.ifa_ifp - struct sockaddr_at aa_addr; - struct sockaddr_at aa_broadaddr; -# define aa_dstaddr aa_broadaddr; - struct sockaddr_at aa_netmask; - int aa_flags; - u_short aa_firstnet, aa_lastnet; - int aa_probcnt; - struct callout_handle aa_ch; - struct at_ifaddr *aa_next; + struct ifaddr aa_ifa; + struct sockaddr_at aa_addr; + struct sockaddr_at aa_broadaddr; + struct sockaddr_at aa_netmask; + int aa_flags; + u_short aa_firstnet; + u_short aa_lastnet; + int aa_probcnt; + struct callout aa_callout; + TAILQ_ENTRY(at_ifaddr) aa_link; }; +#define aa_ifp aa_ifa.ifa_ifp +#define aa_dstaddr aa_broadaddr; +TAILQ_HEAD(at_ifaddrhead, at_ifaddr); + 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; + char ifra_name[IFNAMSIZ]; + struct sockaddr_at ifra_addr; + struct sockaddr_at ifra_broadaddr; + struct sockaddr_at ifra_mask; }; +#define ifra_dstaddr ifra_broadaddr -#define AA_SAT(aa) \ - (&(aa->aa_addr)) -#define satosat(sa) ((struct sockaddr_at *)(sa)) +#define AA_SAT(aa) (&(aa->aa_addr)) +#define satosat(sa) ((struct sockaddr_at *)(sa)) -#define AFA_ROUTE 0x0001 -#define AFA_PROBING 0x0002 -#define AFA_PHASE2 0x0004 +#define AFA_ROUTE 0x0001 +#define AFA_PROBING 0x0002 +#define AFA_PHASE2 0x0004 #ifdef _KERNEL -extern struct at_ifaddr *at_ifaddr; -extern struct ifqueue atintrq1, atintrq2; +extern struct rwlock at_ifaddr_rw; +extern struct at_ifaddrhead at_ifaddrhead; + +#define AT_IFADDR_LOCK_INIT() rw_init(&at_ifaddr_rw, "at_ifaddr_rw") +#define AT_IFADDR_LOCK_ASSERT() rw_assert(&at_ifaddr_rw, RA_LOCKED) +#define AT_IFADDR_RLOCK() rw_rlock(&at_ifaddr_rw) +#define AT_IFADDR_RUNLOCK() rw_runlock(&at_ifaddr_rw) +#define AT_IFADDR_WLOCK() rw_wlock(&at_ifaddr_rw) +#define AT_IFADDR_WUNLOCK() rw_wunlock(&at_ifaddr_rw) #endif #endif /* _NETATALK_AT_VAR_H_ */ Index: aarp.c =================================================================== --- aarp.c (.../stable/4/sys/netatalk) (revision 196046) +++ aarp.c (.../head/sys/netatalk) (revision 196046) @@ -1,7 +1,52 @@ -/* - * Copyright (c) 1990,1991 Regents of The University of Michigan. +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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. + * + * Copyright (c) 1990,1991,1994 Regents of The University of Michigan. * All Rights Reserved. * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * * $FreeBSD$ */ @@ -15,6 +60,7 @@ #include #include +#include #include #undef s_net @@ -26,593 +72,653 @@ #include #include -static void aarptfree( struct aarptab *aat); -static void at_aarpinput( struct arpcom *ac, struct mbuf *m); +#include -#define AARPTAB_BSIZ 9 -#define AARPTAB_NB 19 -#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) +static void aarptfree(struct aarptab *aat); +static void at_aarpinput(struct ifnet *ifp, struct mbuf *m); + +#define AARPTAB_BSIZ 9 +#define AARPTAB_NB 19 +#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) static struct aarptab aarptab[AARPTAB_SIZE]; -#define AARPTAB_HASH(a) \ - ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB ) +struct mtx aarptab_mtx; +MTX_SYSINIT(aarptab_mtx, &aarptab_mtx, "aarptab_mtx", MTX_DEF); -#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 AARPTAB_HASH(a) ((((a).s_net << 8) + (a).s_node) % AARPTAB_NB) -#define AARPT_AGE (60 * 1) -#define AARPT_KILLC 20 -#define AARPT_KILLI 3 +#define AARPTAB_LOOK(aat, addr) do { \ + int n; \ + \ + AARPTAB_LOCK_ASSERT(); \ + 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 = NULL; \ +} while (0) -# if !defined( __FreeBSD__ ) -extern u_char etherbroadcastaddr[6]; -# endif __FreeBSD__ +#define AARPT_AGE (60 * 1) +#define AARPT_KILLC 20 +#define AARPT_KILLI 3 -static u_char atmulticastaddr[ 6 ] = { - 0x09, 0x00, 0x07, 0xff, 0xff, 0xff, +static const u_char atmulticastaddr[6] = { + 0x09, 0x00, 0x07, 0xff, 0xff, 0xff, }; -u_char at_org_code[ 3 ] = { - 0x08, 0x00, 0x07, +u_char at_org_code[3] = { + 0x08, 0x00, 0x07, }; -u_char aarp_org_code[ 3 ] = { - 0x00, 0x00, 0x00, +const u_char aarp_org_code[3] = { + 0x00, 0x00, 0x00, }; -static struct callout_handle aarptimer_ch = +static struct callout_handle aarptimer_ch = CALLOUT_HANDLE_INITIALIZER(&aarptimer_ch); static void aarptimer(void *ignored) { - struct aarptab *aat; - int i, s; + struct aarptab *aat; + int i; - aarptimer_ch = 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 ); - } + aarptimer_ch = timeout(aarptimer, NULL, AARPT_AGE * hz); + aat = aarptab; + AARPTAB_LOCK(); + 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; + aarptfree(aat); + } + AARPTAB_UNLOCK(); } /* - * search through the network addresses to find one that includes - * the given network.. remember to take netranges into - * consideration. + * Search through the network addresses to find one that includes the given + * network. Remember to take netranges into consideration. + * + * The _locked variant relies on the caller holding the at_ifaddr lock; the + * unlocked variant returns a reference that the caller must dispose of. */ struct at_ifaddr * -at_ifawithnet(struct sockaddr_at *sat ) +at_ifawithnet_locked(struct sockaddr_at *sat) { - struct at_ifaddr *aa; - struct sockaddr_at *sat2; + struct at_ifaddr *aa; + struct sockaddr_at *sat2; - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + AT_IFADDR_LOCK_ASSERT(); + + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { sat2 = &(aa->aa_addr); - if ( sat2->sat_addr.s_net == sat->sat_addr.s_net ) { - break; - } - if( (aa->aa_flags & AFA_PHASE2 ) - && (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net)) - && (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net))) { + if (sat2->sat_addr.s_net == sat->sat_addr.s_net) break; - } + if ((aa->aa_flags & AFA_PHASE2) && + (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net)) && + (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net))) + break; } - return( aa ); + return (aa); } -static void -aarpwhohas( struct arpcom *ac, struct sockaddr_at *sat ) +struct at_ifaddr * +at_ifawithnet(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; + struct at_ifaddr *aa; - 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 )); + AT_IFADDR_RLOCK(); + aa = at_ifawithnet_locked(sat); + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + return (aa); +} - ea = mtod( m, struct ether_aarp *); - bzero((caddr_t)ea, sizeof( *ea )); +static void +aarpwhohas(struct ifnet *ifp, 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; - ea->aarp_hrd = htons( AARPHRD_ETHER ); - ea->aarp_pro = htons( ETHERTYPE_AT ); - ea->aarp_hln = sizeof( ea->aarp_sha ); - ea->aarp_pln = sizeof( ea->aarp_spu ); - ea->aarp_op = htons( AARPOP_REQUEST ); - bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, - sizeof( ea->aarp_sha )); + AARPTAB_UNLOCK_ASSERT(); + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) + return; +#ifdef MAC + mac_netatalk_aarp_send(ifp, m); +#endif + m->m_len = sizeof(*ea); + m->m_pkthdr.len = sizeof(*ea); + MH_ALIGN(m, sizeof(*ea)); - /* - * 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 = at_ifawithnet( sat )) == NULL) { - m_freem( m ); - return; - } + ea = mtod(m, struct ether_aarp *); + bzero((caddr_t)ea, sizeof(*ea)); - eh = (struct ether_header *)sa.sa_data; + ea->aarp_hrd = htons(AARPHRD_ETHER); + ea->aarp_pro = htons(ETHERTYPE_AT); + ea->aarp_hln = sizeof(ea->aarp_sha); + ea->aarp_pln = sizeof(ea->aarp_spu); + ea->aarp_op = htons(AARPOP_REQUEST); + bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha)); - if ( aa->aa_flags & AFA_PHASE2 ) { - bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, - sizeof( eh->ether_dhost )); - eh->ether_type = htons(sizeof(struct llc) + sizeof(struct ether_aarp)); - M_PREPEND( m, sizeof( struct llc ), M_WAIT ); - llc = mtod( m, struct llc *); - llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; - llc->llc_control = LLC_UI; - bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); - llc->llc_ether_type = htons( ETHERTYPE_AARP ); + /* + * 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. + */ + aa = at_ifawithnet(sat); + if (aa == NULL) { + m_freem(m); + return; + } - 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 { - bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, - sizeof( eh->ether_dhost )); - eh->ether_type = htons( ETHERTYPE_AARP ); + eh = (struct ether_header *)sa.sa_data; - ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node; - ea->aarp_tpa = sat->sat_addr.s_node; - } + if (aa->aa_flags & AFA_PHASE2) { + bcopy(atmulticastaddr, eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(sizeof(struct llc) + + sizeof(struct ether_aarp)); + M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); + if (m == NULL) { + ifa_free(&aa->aa_ifa); + return; + } + llc = mtod(m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy(aarp_org_code, llc->llc_org_code, + sizeof(aarp_org_code)); + llc->llc_ether_type = htons(ETHERTYPE_AARP); + bcopy(&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 { + bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_AARP); + ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node; + ea->aarp_tpa = sat->sat_addr.s_node; + } #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); + 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 */ + ifa_free(&aa->aa_ifa); - sa.sa_len = sizeof( struct sockaddr ); - sa.sa_family = AF_UNSPEC; - (*ac->ac_if.if_output)(&ac->ac_if, - m, &sa, NULL); /* XXX NULL should be routing information */ + sa.sa_len = sizeof(struct sockaddr); + sa.sa_family = AF_UNSPEC; + ifp->if_output(ifp, m, &sa, NULL); } int -aarpresolve( ac, m, destsat, desten ) - struct arpcom *ac; - struct mbuf *m; - struct sockaddr_at *destsat; - u_char *desten; +aarpresolve(struct ifnet *ifp, struct mbuf *m, struct sockaddr_at *destsat, + u_char *desten) { - struct at_ifaddr *aa; - struct aarptab *aat; - int s; + struct at_ifaddr *aa; + struct aarptab *aat; - if ( at_broadcast( destsat )) { - m->m_flags |= M_BCAST; - if ((aa = at_ifawithnet( destsat )) == NULL) { - m_freem( m ); - return( 0 ); + AT_IFADDR_RLOCK(); + if (at_broadcast(destsat)) { + m->m_flags |= M_BCAST; + if ((aa = at_ifawithnet_locked(destsat)) == NULL) { + AT_IFADDR_RUNLOCK(); + m_freem(m); + return (0); + } + if (aa->aa_flags & AFA_PHASE2) + bcopy(atmulticastaddr, (caddr_t)desten, + sizeof(atmulticastaddr)); + else + bcopy(ifp->if_broadcastaddr, (caddr_t)desten, + sizeof(ifp->if_addrlen)); + AT_IFADDR_RUNLOCK(); + return (1); } - if ( aa->aa_flags & AFA_PHASE2 ) { - bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten, - sizeof( atmulticastaddr )); - } else { - bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten, - sizeof( etherbroadcastaddr )); + AT_IFADDR_RUNLOCK(); + + AARPTAB_LOCK(); + AARPTAB_LOOK(aat, destsat->sat_addr); + if (aat == NULL) { + /* No entry. */ + aat = aarptnew(&destsat->sat_addr); + + /* We should fail more gracefully. */ + if (aat == NULL) + panic("aarpresolve: no free entry"); + goto done; } - 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" ); + /* 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)); + AARPTAB_UNLOCK(); + return (1); } + + /* Entry has not completed. */ + if (aat->aat_hold) + m_freem(aat->aat_hold); +done: 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 ); + AARPTAB_UNLOCK(); + aarpwhohas(ifp, destsat); + return (0); } void -aarpinput( ac, m ) - struct arpcom *ac; - struct mbuf *m; +aarpintr(struct mbuf *m) { - struct arphdr *ar; + struct arphdr *ar; + struct ifnet *ifp; - if ( ac->ac_if.if_flags & IFF_NOARP ) - goto out; + ifp = m->m_pkthdr.rcvif; + if (ifp->if_flags & IFF_NOARP) + goto out; - if ( m->m_len < sizeof( struct arphdr )) { - goto out; - } + if (m->m_len < sizeof(struct arphdr)) + goto out; - ar = mtod( m, struct arphdr *); - if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) { - goto out; - } - - if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln + - 2 * ar->ar_pln ) { - goto out; - } - - switch( ntohs( ar->ar_pro )) { - case ETHERTYPE_AT : - at_aarpinput( ac, m ); - return; + 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(ifp, m); + return; + default: + break; + } - default: - break; - } - out: - m_freem( m ); + m_freem(m); } static void -at_aarpinput( struct arpcom *ac, struct mbuf *m) +at_aarpinput(struct ifnet *ifp, struct mbuf *m) { - struct ether_aarp *ea; - struct at_ifaddr *aa; - struct aarptab *aat; - struct ether_header *eh; - struct llc *llc; - struct sockaddr_at sat; - struct sockaddr sa; - struct at_addr spa, tpa, ma; - int op; - u_short net; + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct aarptab *aat; + struct ether_header *eh; + struct llc *llc; + struct sockaddr_at sat; + struct sockaddr sa; + struct at_addr spa, tpa, ma; + int op; + u_short net; - ea = mtod( m, struct ether_aarp *); + ea = mtod(m, struct ether_aarp *); - /* Check to see if from my hardware address */ - if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr, - sizeof( ac->ac_enaddr ))) { - m_freem( m ); - return; - } + /* Check to see if from my hardware address. */ + if (!bcmp((caddr_t)ea->aarp_sha, IF_LLADDR(ifp), ETHER_ADDR_LEN)) { + m_freem(m); + return; + } - op = ntohs( ea->aarp_op ); - bcopy( ea->aarp_tpnet, &net, sizeof( net )); + /* Don't accept requests from broadcast address. */ + if (!bcmp(ea->aarp_sha, ifp->if_broadcastaddr, ifp->if_addrlen)) { + log(LOG_ERR, "aarp: source link address is broadcast\n"); + m_freem(m); + return; + } - if ( net != 0 ) { /* should be ATADDR_ANYNET? */ - sat.sat_len = sizeof(struct sockaddr_at); - sat.sat_family = AF_APPLETALK; - sat.sat_addr.s_net = net; - if ((aa = at_ifawithnet( &sat )) == NULL) { - m_freem( m ); - return; + op = ntohs(ea->aarp_op); + bcopy(ea->aarp_tpnet, &net, sizeof(net)); + + if (net != 0) { + /* Should be ATADDR_ANYNET? */ + sat.sat_len = sizeof(struct sockaddr_at); + sat.sat_family = AF_APPLETALK; + sat.sat_addr.s_net = net; + aa = at_ifawithnet(&sat); + if (aa == 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. + */ + IF_ADDR_LOCK(ifp); + for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead); + aa; + aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) { + if (AA_SAT(aa)->sat_family == AF_APPLETALK && + (aa->aa_flags & AFA_PHASE2) == 0) { + break; + } + } + if (aa == NULL) { + IF_ADDR_UNLOCK(ifp); + m_freem(m); + return; + } + ifa_ref(&aa->aa_ifa); + IF_ADDR_UNLOCK(ifp); + tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net; } - bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net )); - bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net )); - } else { + + 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; + /* - * Since we don't know the net, we just look for the first - * phase 1 address on the interface. + * This looks like it's from us. */ - for (aa = (struct at_ifaddr *)ac->ac_if.if_addrhead.tqh_first; aa; - aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) { - if ( AA_SAT( aa )->sat_family == AF_APPLETALK && - ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { - break; - } + 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. + */ + callout_stop(&aa->aa_callout); + wakeup(aa); + ifa_free(&aa->aa_ifa); + 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. + */ + ifa_free(&aa->aa_ifa); + log(LOG_ERR, + "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n", + ea->aarp_sha[0], ea->aarp_sha[1], + ea->aarp_sha[2], ea->aarp_sha[3], + ea->aarp_sha[4], ea->aarp_sha[5]); + m_freem(m); + return; + } } - 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; + AARPTAB_LOCK(); + AARPTAB_LOOK(aat, spa); + if (aat != NULL) { + 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); + AARPTAB_UNLOCK(); + ifa_free(&aa->aa_ifa); + m_freem(m); + return; + } - /* - * This looks like it's from us. - */ - if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) { - if ( aa->aa_flags & AFA_PROBING ) { - /* - * We're probing, someone either responded to our probe, or - * probed for the same address we'd like to use. Change the - * address we're probing for. - */ - untimeout( aarpprobe, ac, aa->aa_ch ); - 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... - */ - log( LOG_ERR, - "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n", - ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ], - ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]); - m_freem( m ); - return; - } - } + bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr, + sizeof(ea->aarp_sha)); + aat->aat_flags |= ATF_COM; + if (aat->aat_hold) { + struct mbuf *mhold = aat->aat_hold; + aat->aat_hold = NULL; + AARPTAB_UNLOCK(); + sat.sat_len = sizeof(struct sockaddr_at); + sat.sat_family = AF_APPLETALK; + sat.sat_addr = spa; + (*ifp->if_output)(ifp, mhold, + (struct sockaddr *)&sat, NULL); /* XXX */ + } else + AARPTAB_UNLOCK(); + } else if ((tpa.s_net == ma.s_net) && (tpa.s_node == ma.s_node) + && (op != AARPOP_PROBE) && ((aat = aarptnew(&spa)) != NULL)) { + bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr, + sizeof(ea->aarp_sha)); + aat->aat_flags |= ATF_COM; + AARPTAB_UNLOCK(); + } else + AARPTAB_UNLOCK(); - 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; + /* + * 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)) { + ifa_free(&aa->aa_ifa); + 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 ) { - struct mbuf *mhold = aat->aat_hold; - aat->aat_hold = NULL; - sat.sat_len = sizeof(struct sockaddr_at); - sat.sat_family = AF_APPLETALK; - sat.sat_addr = spa; - (*ac->ac_if.if_output)( &ac->ac_if, mhold, - (struct sockaddr *)&sat, NULL); /* XXX */ - } - } else if ((tpa.s_net == ma.s_net) - && (tpa.s_node == ma.s_node) - && (op != AARPOP_PROBE) - && ((aat = aarptnew( &spa )) != NULL)) { - bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr, - sizeof( ea->aarp_sha )); - aat->aat_flags |= ATF_COM; - } + bcopy((caddr_t)ea->aarp_sha, (caddr_t)ea->aarp_tha, + sizeof(ea->aarp_sha)); + bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha)); - /* - * 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; - } + /* XXX */ + eh = (struct ether_header *)sa.sa_data; + bcopy((caddr_t)ea->aarp_tha, (caddr_t)eh->ether_dhost, + sizeof(eh->ether_dhost)); - bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha, - sizeof( ea->aarp_sha )); - bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha, - sizeof( ea->aarp_sha )); + if (aa->aa_flags & AFA_PHASE2) { + eh->ether_type = htons(sizeof(struct llc) + + sizeof(struct ether_aarp)); + M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); + if (m == NULL) { + ifa_free(&aa->aa_ifa); + return; + } + llc = mtod(m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy(aarp_org_code, llc->llc_org_code, + sizeof(aarp_org_code)); + llc->llc_ether_type = htons(ETHERTYPE_AARP); - /* XXX */ - eh = (struct ether_header *)sa.sa_data; - bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost, - sizeof( eh->ether_dhost )); + bcopy(ea->aarp_spnet, ea->aarp_tpnet, + sizeof(ea->aarp_tpnet)); + bcopy(&ma.s_net, ea->aarp_spnet, sizeof(ea->aarp_spnet)); + } else + eh->ether_type = htons(ETHERTYPE_AARP); + ifa_free(&aa->aa_ifa); - if ( aa->aa_flags & AFA_PHASE2 ) { - eh->ether_type = htons( sizeof( struct llc ) + - sizeof( struct ether_aarp )); - M_PREPEND( m, sizeof( struct llc ), M_DONTWAIT ); - if ( m == NULL ) { - return; - } - llc = mtod( m, struct llc *); - llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; - llc->llc_control = LLC_UI; - bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); - llc->llc_ether_type = htons( ETHERTYPE_AARP ); + ea->aarp_tpnode = ea->aarp_spnode; + ea->aarp_spnode = ma.s_node; + ea->aarp_op = htons(AARPOP_RESPONSE); - bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); - bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet )); - } else { - eh->ether_type = htons( ETHERTYPE_AARP ); - } - - ea->aarp_tpnode = ea->aarp_spnode; - ea->aarp_spnode = ma.s_node; - ea->aarp_op = htons( AARPOP_RESPONSE ); - - sa.sa_len = sizeof( struct sockaddr ); - sa.sa_family = AF_UNSPEC; - (*ac->ac_if.if_output)( &ac->ac_if, m, &sa, NULL); /* XXX */ - return; + sa.sa_len = sizeof(struct sockaddr); + sa.sa_family = AF_UNSPEC; + (*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */ + return; } static void -aarptfree( struct aarptab *aat) +aarptfree(struct aarptab *aat) { - if ( aat->aat_hold ) - m_freem( aat->aat_hold ); - aat->aat_hold = NULL; - aat->aat_timer = aat->aat_flags = 0; - aat->aat_ataddr.s_net = 0; - aat->aat_ataddr.s_node = 0; + AARPTAB_LOCK_ASSERT(); + if (aat->aat_hold) + m_freem(aat->aat_hold); + aat->aat_hold = NULL; + 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; +struct aarptab * +aarptnew(struct at_addr *addr) { - int n; - int oldest = -1; - struct aarptab *aat, *aato = NULL; - static int first = 1; + int n; + int oldest = -1; + struct aarptab *aat, *aato = NULL; + static int first = 1; - if ( first ) { - first = 0; - aarptimer_ch = 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; + AARPTAB_LOCK_ASSERT(); + if (first) { + first = 0; + aarptimer_ch = timeout(aarptimer, (caddr_t)0, hz); } - } - if ( aato == NULL ) - return( NULL ); - aat = aato; - aarptfree( aat ); + 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 ); + aat->aat_ataddr = *addr; + aat->aat_flags = ATF_INUSE; + return (aat); } void -aarpprobe( void *arg ) +aarpprobe(void *arg) { - struct arpcom *ac = arg; - struct mbuf *m; - struct ether_header *eh; - struct ether_aarp *ea; - struct at_ifaddr *aa; - struct llc *llc; - struct sockaddr sa; + struct ifnet *ifp = arg; + struct mbuf *m; + struct ether_header *eh; + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct llc *llc; + struct sockaddr sa; - /* - * We need to check whether the output ethernet type should - * be phase 1 or 2. We have the interface that we'll be sending - * the aarp out. We need to find an AppleTalk network on that - * interface with the same address as we're looking for. If the - * net is phase 2, generate an 802.2 and SNAP header. - */ - for (aa = (struct at_ifaddr *)ac->ac_if.if_addrhead.tqh_first; aa; + /* + * 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. + */ + AARPTAB_LOCK(); + for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead); aa; aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) { - if ( AA_SAT( aa )->sat_family == AF_APPLETALK && - ( aa->aa_flags & AFA_PROBING )) { - break; + 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 == NULL) { + /* Serious error XXX. */ + AARPTAB_UNLOCK(); + printf("aarpprobe why did this happen?!\n"); + return; + } - if ( aa->aa_probcnt <= 0 ) { - aa->aa_flags &= ~AFA_PROBING; - wakeup( aa ); - return; - } else { - aa->aa_ch = timeout( aarpprobe, (caddr_t)ac, hz / 5 ); - } + if (aa->aa_probcnt <= 0) { + aa->aa_flags &= ~AFA_PROBING; + wakeup(aa); + AARPTAB_UNLOCK(); + return; + } else + callout_reset(&aa->aa_callout, hz / 5, aarpprobe, ifp); + ifa_ref(&aa->aa_ifa); + AARPTAB_UNLOCK(); - 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 )); + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) { + ifa_free(&aa->aa_ifa); + return; + } +#ifdef MAC + mac_netatalk_aarp_send(ifp, m); +#endif + m->m_len = sizeof(*ea); + m->m_pkthdr.len = sizeof(*ea); + MH_ALIGN(m, sizeof(*ea)); - ea = mtod( m, struct ether_aarp *); - bzero((caddr_t)ea, sizeof( *ea )); + ea = mtod(m, struct ether_aarp *); + bzero((caddr_t)ea, sizeof(*ea)); - ea->aarp_hrd = htons( AARPHRD_ETHER ); - ea->aarp_pro = htons( ETHERTYPE_AT ); - ea->aarp_hln = sizeof( ea->aarp_sha ); - ea->aarp_pln = sizeof( ea->aarp_spu ); - ea->aarp_op = htons( AARPOP_PROBE ); - bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, - sizeof( ea->aarp_sha )); + ea->aarp_hrd = htons(AARPHRD_ETHER); + ea->aarp_pro = htons(ETHERTYPE_AT); + ea->aarp_hln = sizeof(ea->aarp_sha); + ea->aarp_pln = sizeof(ea->aarp_spu); + ea->aarp_op = htons(AARPOP_PROBE); + bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, + sizeof(ea->aarp_sha)); - eh = (struct ether_header *)sa.sa_data; + eh = (struct ether_header *)sa.sa_data; - if ( aa->aa_flags & AFA_PHASE2 ) { - bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, - sizeof( eh->ether_dhost )); - eh->ether_type = htons( sizeof( struct llc ) + - sizeof( struct ether_aarp )); - M_PREPEND( m, sizeof( struct llc ), M_WAIT ); - llc = mtod( m, struct llc *); - llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; - llc->llc_control = LLC_UI; - bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); - llc->llc_ether_type = htons( ETHERTYPE_AARP ); + if (aa->aa_flags & AFA_PHASE2) { + bcopy(atmulticastaddr, eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(sizeof(struct llc) + + sizeof(struct ether_aarp)); + M_PREPEND(m, sizeof(struct llc), M_WAIT); + llc = mtod(m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy(aarp_org_code, llc->llc_org_code, + sizeof(aarp_org_code)); + llc->llc_ether_type = htons(ETHERTYPE_AARP); - bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet, - sizeof( ea->aarp_spnet )); - bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet, - sizeof( ea->aarp_tpnet )); - ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node; - } else { - bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, - sizeof( eh->ether_dhost )); - eh->ether_type = htons( ETHERTYPE_AARP ); - ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node; - } + bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, + sizeof(ea->aarp_spnet)); + bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet, + sizeof(ea->aarp_tpnet)); + ea->aarp_spnode = ea->aarp_tpnode = + AA_SAT(aa)->sat_addr.s_node; + } else { + bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_AARP); + ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node; + } #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); + 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 */ + ifa_free(&aa->aa_ifa); - sa.sa_len = sizeof( struct sockaddr ); - sa.sa_family = AF_UNSPEC; - (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, NULL); /* XXX */ - aa->aa_probcnt--; + sa.sa_len = sizeof(struct sockaddr); + sa.sa_family = AF_UNSPEC; + (*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */ + aa->aa_probcnt--; } void aarp_clean(void) { - struct aarptab *aat; - int i; + struct aarptab *aat; + int i; - untimeout( aarptimer, 0, aarptimer_ch ); - for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) { - if ( aat->aat_hold ) { - m_freem( aat->aat_hold ); - aat->aat_hold = NULL; + untimeout(aarptimer, 0, aarptimer_ch); + AARPTAB_LOCK(); + for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) { + if (aat->aat_hold) { + m_freem(aat->aat_hold); + aat->aat_hold = NULL; + } } - } + AARPTAB_UNLOCK(); } Index: ddp_var.h =================================================================== --- ddp_var.h (.../stable/4/sys/netatalk) (revision 196046) +++ ddp_var.h (.../head/sys/netatalk) (revision 196046) @@ -1,39 +1,63 @@ -/* - * Copyright (c) 1990,1994 Regents of The University of Michigan. - * All Rights Reserved. See COPYRIGHT. +/*- + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * * $FreeBSD$ */ #ifndef _NETATALK_DDP_VAR_H_ -#define _NETATALK_DDP_VAR_H_ 1 +#define _NETATALK_DDP_VAR_H_ + struct ddpcb { - struct sockaddr_at ddp_fsat, ddp_lsat; - struct route ddp_route; - struct socket *ddp_socket; - struct ddpcb *ddp_prev, *ddp_next; - struct ddpcb *ddp_pprev, *ddp_pnext; + 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; + struct mtx ddp_mtx; }; -#define sotoddpcb(so) ((struct ddpcb *)(so)->so_pcb) +#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 */ + 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 int ddp_cksum; -extern struct ddpcb *ddp_ports[ ]; -extern struct ddpcb *ddpcb; -extern struct pr_usrreqs ddp_usrreqs; +extern int ddp_cksum; +extern struct ddpcb *ddpcb_list; +extern struct pr_usrreqs ddp_usrreqs; +extern struct mtx ddp_list_mtx; #endif + #endif /* _NETATALK_DDP_VAR_H_ */ Index: ddp_input.c =================================================================== --- ddp_input.c (.../stable/4/sys/netatalk) (revision 196046) +++ ddp_input.c (.../head/sys/netatalk) (revision 196046) @@ -1,474 +1,440 @@ -/* - * Copyright (c) 1990,1994 Regents of The University of Michigan. - * All Rights Reserved. See COPYRIGHT. +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * * $FreeBSD$ */ #include -#include #include -#include +#include #include +#include #include #include +#include +#include #include #include -#include #include #include #include #include +#include #include +#include + static volatile int ddp_forward = 1; static volatile int ddp_firewall = 0; static struct ddpstat ddpstat; + static struct route forwro; -const int atintrq1_present = 1, atintrq2_present = 1; - static void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int); /* * Could probably merge these two code segments a little better... */ -static void -atintr( void ) +void +at2intr(struct mbuf *m) { - struct elaphdr *elhp, elh; - struct ifnet *ifp; - struct mbuf *m; - int s; - /* - * First pull off all the phase 2 packets. - */ - for (;;) { - s = splimp(); - - IF_DEQUEUE( &atintrq2, m ); - - splx( s ); - - if ( m == 0 ) { /* no more queued packets */ - break; - } - - ifp = m->m_pkthdr.rcvif; - ddp_input( m, ifp, (struct elaphdr *)NULL, 2 ); - } - - /* - * Then pull off all the phase 1 packets. - */ - for (;;) { - s = splimp(); - - IF_DEQUEUE( &atintrq1, m ); - - splx( s ); - - if ( m == 0 ) { /* no more queued packets */ - break; - } - - ifp = m->m_pkthdr.rcvif; - - if ( m->m_len < SZ_ELAPHDR && - (( m = m_pullup( m, SZ_ELAPHDR )) == 0 )) { - ddpstat.ddps_tooshort++; - continue; - } - /* - * this seems a little dubios, but I don't know phase 1 so leave it. + * Phase 2 packet handling . */ - 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; + ddp_input(m, m->m_pkthdr.rcvif, NULL, 2); } -static void -netisr_atalk_setup(void *dummy __unused) +void +at1intr(struct mbuf *m) { - - register_netisr(NETISR_ATALK, atintr); -} -SYSINIT(atalk_setup, SI_SUB_CPU, SI_ORDER_ANY, netisr_atalk_setup, NULL); + struct elaphdr *elhp, elh; -static 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 = NULL, ddpe; - struct ddpcb *ddp; - int dlen, mlen; - u_short cksum = 0; - - bzero( (caddr_t)&from, sizeof( struct sockaddr_at )); - bzero( (caddr_t)&to, sizeof( struct sockaddr_at )); - if ( elh ) { /* - * Extract the information in the short header. - * netowrk information is defaulted to ATADDR_ANYNET - * and node information comes from the elh info. - * We must be phase 1. + * Phase 1 packet handling */ - ddpstat.ddps_short++; - - if ( m->m_len < sizeof( struct ddpshdr ) && - (( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) { - ddpstat.ddps_tooshort++; - return; + if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == + NULL)) { + 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; - - /* - * Make sure that we point to the phase1 ifaddr info - * and that it's valid for this packet. - */ - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( (aa->aa_ifp == ifp) - && ( (aa->aa_flags & AFA_PHASE2) == 0) - && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node) - || (to.sat_addr.s_node == ATADDR_BCAST))) { - break; - } - } - /* - * maybe we got a broadcast not meant for us.. ditch it. - */ - if ( aa == NULL ) { - m_freem( m ); - return; - } - } else { /* - * There was no 'elh' passed on. This could still be - * either phase1 or phase2. - * We have a long header, but we may be running on a phase 1 net. - * Extract out all the info regarding this packet's src & dst. + * This seems a little dubious, but I don't know phase 1 so leave it. */ - ddpstat.ddps_long++; + elhp = mtod(m, struct elaphdr *); + m_adj(m, SZ_ELAPHDR); - if ( m->m_len < sizeof( struct ddpehdr ) && - (( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) { - ddpstat.ddps_tooshort++; - return; - } + if (elhp->el_type != ELAP_DDPEXTEND) { + bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR); + ddp_input(m, m->m_pkthdr.rcvif, &elh, 1); + } else + ddp_input(m, m->m_pkthdr.rcvif, NULL, 1); +} - 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; +static void +ddp_input(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 = NULL, ddpe; + struct ddpcb *ddp; + int dlen, mlen; + u_short cksum = 0; - if (( cksum = ddpe.deh_sum ) == 0 ) { - ddpstat.ddps_nosum++; - } + bzero((caddr_t)&from, sizeof(struct sockaddr_at)); + bzero((caddr_t)&to, sizeof(struct sockaddr_at)); + if (elh != NULL) { + /* + * Extract the information in the short header. Network + * information is defaulted to ATADDR_ANYNET and node + * information comes from the elh info. We must be phase 1. + */ + ddpstat.ddps_short++; - 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 ) { - /* - * The TO address doesn't specify a net, - * So by definition it's for this net. - * Try find ifaddr info with the right phase, - * the right interface, and either to our node, a broadcast, - * or looped back (though that SHOULD be covered in the other - * cases). - * - * XXX If we have multiple interfaces, then the first with - * this node number will match (which may NOT be what we want, - * but it's probably safe in 99.999% of cases. - */ - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) { - continue; + if (m->m_len < sizeof(struct ddpshdr) && + ((m = m_pullup(m, sizeof(struct ddpshdr))) == NULL)) { + ddpstat.ddps_tooshort++; + return; } - if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { - continue; - } - if ( (aa->aa_ifp == ifp) - && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node) - || (to.sat_addr.s_node == ATADDR_BCAST) - || (ifp->if_flags & IFF_LOOPBACK))) { - break; - } - } - } else { - /* - * A destination network was given. We just try to find - * which ifaddr info matches it. - */ - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - /* - * This is a kludge. Accept packets that are - * for any router on a local netrange. + + 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; + + /* + * Make sure that we point to the phase1 ifaddr info and that + * it's valid for this packet. */ - if ( to.sat_addr.s_net == aa->aa_firstnet && - to.sat_addr.s_node == 0 ) { - break; + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if ((aa->aa_ifp == ifp) + && ((aa->aa_flags & AFA_PHASE2) == 0) + && ((to.sat_addr.s_node == + AA_SAT(aa)->sat_addr.s_node) || + (to.sat_addr.s_node == ATADDR_BCAST))) + break; } - /* - * Don't use ifaddr info for which we are totally outside the - * netrange, and it's not a startup packet. - * Startup packets are always implicitly allowed on to - * the next test. + /* + * maybe we got a broadcast not meant for us.. ditch it. */ - 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 ) < 0xff00) - || (ntohs( to.sat_addr.s_net ) > 0xfffe ))) { - continue; + if (aa == NULL) { + AT_IFADDR_RUNLOCK(); + m_freem(m); + return; } - + } else { /* - * Don't record a match either if we just don't have a match - * in the node address. This can have if the interface - * is in promiscuous mode for example. + * There was no 'elh' passed on. This could still be either + * phase1 or phase2. We have a long header, but we may be + * running on a phase 1 net. Extract out all the info + * regarding this packet's src & dst. */ - if (( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node) - && (to.sat_addr.s_node != ATADDR_BCAST) ) { - continue; + ddpstat.ddps_long++; + + if (m->m_len < sizeof(struct ddpehdr) && + ((m = m_pullup(m, sizeof(struct ddpehdr))) == NULL)) { + AT_IFADDR_RUNLOCK(); + ddpstat.ddps_tooshort++; + return; } - break; - } - } - } - /* - * Adjust the length, removing any padding that may have been added - * at a link layer. We do this before we attempt to forward a packet, - * possibly on a different media. - */ - mlen = m->m_pkthdr.len; - if ( mlen < dlen ) { - ddpstat.ddps_toosmall++; - m_freem( m ); - return; - } - if ( mlen > dlen ) { - m_adj( m, dlen - mlen ); - } + 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 it aint for a net on any of our interfaces, - * or it IS for a net on a different interface than it came in on, - * (and it is not looped back) then consider if we should forward it. - * As we are not really a router this is a bit cheeky, but it may be - * useful some day. - */ - if ( (aa == NULL) - || ( (to.sat_addr.s_node == ATADDR_BCAST) - && (aa->aa_ifp != ifp) - && (( ifp->if_flags & IFF_LOOPBACK ) == 0 ))) { - /* - * If we've explicitly disabled it, don't route anything - */ - if ( ddp_forward == 0 ) { - m_freem( m ); - return; - } - /* - * If the cached forwarding route is still valid, use it. - */ - if ( forwro.ro_rt - && ( satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net - || satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node )) { - RTFREE( forwro.ro_rt ); - forwro.ro_rt = (struct rtentry *)0; - } + if ((cksum = ddpe.deh_sum) == 0) + ddpstat.ddps_nosum++; - /* - * If we don't have a cached one (any more) or it's useless, - * Then get a new route. - * XXX this could cause a 'route leak'. check this! - */ - if ( forwro.ro_rt == (struct rtentry *)0 - || forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) { - forwro.ro_dst.sa_len = sizeof( struct sockaddr_at ); - forwro.ro_dst.sa_family = AF_APPLETALK; - satosat(&forwro.ro_dst)->sat_addr.s_net = to.sat_addr.s_net; - satosat(&forwro.ro_dst)->sat_addr.s_node = to.sat_addr.s_node; - rtalloc(&forwro); - } + 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 it's not going to get there on this hop, and it's - * already done too many hops, then throw it away. - */ - if ( (to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net) - && (ddpe.deh_hops == DDP_MAXHOPS) ) { - m_freem( m ); - return; + AT_IFADDR_RLOCK(); + if (to.sat_addr.s_net == ATADDR_ANYNET) { + /* + * The TO address doesn't specify a net, so by + * definition it's for this net. Try find ifaddr + * info with the right phase, the right interface, + * and either to our node, a broadcast, or looped + * back (though that SHOULD be covered in the other + * cases). + * + * XXX If we have multiple interfaces, then the first + * with this node number will match (which may NOT be + * what we want, but it's probably safe in 99.999% of + * cases. + */ + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (phase == 1 && (aa->aa_flags & + AFA_PHASE2)) + continue; + if (phase == 2 && (aa->aa_flags & + AFA_PHASE2) == 0) + continue; + if ((aa->aa_ifp == ifp) && + ((to.sat_addr.s_node == + AA_SAT(aa)->sat_addr.s_node) || + (to.sat_addr.s_node == ATADDR_BCAST) || + (ifp->if_flags & IFF_LOOPBACK))) + break; + } + } else { + /* + * A destination network was given. We just try to + * find which ifaddr info matches it. + */ + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + /* + * This is a kludge. Accept packets that are + * for any router on a local netrange. + */ + if (to.sat_addr.s_net == aa->aa_firstnet && + to.sat_addr.s_node == 0) + break; + /* + * Don't use ifaddr info for which we are + * totally outside the netrange, and it's not + * a startup packet. Startup packets are + * always implicitly allowed on to the next + * test. + */ + 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) < 0xff00) || + (ntohs(to.sat_addr.s_net) > 0xfffe))) + continue; + + /* + * Don't record a match either if we just + * don't have a match in the node address. + * This can have if the interface is in + * promiscuous mode for example. + */ + if ((to.sat_addr.s_node != + AA_SAT(aa)->sat_addr.s_node) && + (to.sat_addr.s_node != ATADDR_BCAST)) + continue; + break; + } + } } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); /* - * A ddp router might use the same interface - * to forward the packet, which this would not effect. - * Don't allow packets to cross from one interface to another however. + * 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. */ - if ( ddp_firewall - && ( (forwro.ro_rt == NULL) - || (forwro.ro_rt->rt_ifp != ifp))) { - m_freem( m ); - return; + mlen = m->m_pkthdr.len; + if (mlen < dlen) { + ddpstat.ddps_toosmall++; + goto out; } + if (mlen > dlen) + m_adj(m, dlen - mlen); /* - * Adjust the header. - * If it was a short header then it would have not gotten here, - * so we can assume there is room to drop the header in. - * XXX what about promiscuous mode, etc... + * If it isn't for a net on any of our interfaces, or it IS for a net + * on a different interface than it came in on, (and it is not looped + * back) then consider if we should forward it. As we are not really + * a router this is a bit cheeky, but it may be useful some day. */ - 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; - } + if ((aa == NULL) || ((to.sat_addr.s_node == ATADDR_BCAST) && + (aa->aa_ifp != ifp) && ((ifp->if_flags & IFF_LOOPBACK) == 0))) { + /* + * If we've explicitly disabled it, don't route anything. + */ + if (ddp_forward == 0) + goto out; - /* - * It was for us, and we have an ifaddr to use with it. - */ - from.sat_len = sizeof( struct sockaddr_at ); - from.sat_family = AF_APPLETALK; + /* + * If the cached forwarding route is still valid, use it. + * + * XXXRW: Access to the cached route may not be properly + * synchronized for parallel input handling. + */ + if (forwro.ro_rt && + (satosat(&forwro.ro_dst)->sat_addr.s_net != + to.sat_addr.s_net || + satosat(&forwro.ro_dst)->sat_addr.s_node != + to.sat_addr.s_node)) { + RTFREE(forwro.ro_rt); + forwro.ro_rt = NULL; + } - /* - * We are no longer interested in the link layer. - * so cut it off. - */ - 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 we don't have a cached one (any more) or it's useless, + * then get a new route. + * + * XXX this could cause a 'route leak'. Check this! + */ + if (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp == NULL) { + forwro.ro_dst.sa_len = sizeof(struct sockaddr_at); + forwro.ro_dst.sa_family = AF_APPLETALK; + satosat(&forwro.ro_dst)->sat_addr.s_net = + to.sat_addr.s_net; + satosat(&forwro.ro_dst)->sat_addr.s_node = + to.sat_addr.s_node; + rtalloc(&forwro); + } - /* - * Search for ddp protocol control blocks that match these - * addresses. - */ - if (( ddp = ddp_search( &from, &to, aa )) == NULL ) { - m_freem( m ); - return; - } + /* + * If it's not going to get there on this hop, and it's + * already done too many hops, then throw it away. + */ + if ((to.sat_addr.s_net != + satosat(&forwro.ro_dst)->sat_addr.s_net) && + (ddpe.deh_hops == DDP_MAXHOPS)) + goto out; - /* - * If we found one, deliver th epacket to the socket - */ - if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from, - m, (struct mbuf *)0 ) == 0 ) { - /* - * If the socket is full (or similar error) dump the packet. - */ - ddpstat.ddps_nosockspace++; - m_freem( m ); - return; - } - /* - * And wake up whatever might be waiting for it - */ - sorwakeup( ddp->ddp_socket ); -} + /* + * A ddp router might use the same interface to forward the + * packet, which this would not effect. Don't allow packets + * to cross from one interface to another however. + */ + if (ddp_firewall && ((forwro.ro_rt == NULL) || + (forwro.ro_rt->rt_ifp != ifp))) + goto out; -#if 0 -/* As if we haven't got enough of this sort of think floating -around the kernel :) */ - -#define BPXLEN 48 -#define BPALEN 16 -#include -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; + /* + * Adjust the header. If it was a short header then it would + * have not gotten here, so we can assume there is room to + * drop the header in. + * + * XXX what about promiscuous mode, etc... + */ + ddpe.deh_hops++; + ddpe.deh_bytes = htonl(ddpe.deh_bytes); + /* XXX deh? */ + bcopy((caddr_t)&ddpe, (caddr_t)deh, sizeof(u_short)); + if (ddp_route(m, &forwro)) + ddpstat.ddps_cantforward++; + else + ddpstat.ddps_forward++; + if (aa != NULL) + ifa_free(&aa->aa_ifa); + return; } - xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ]; - xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ]; + /* + * It was for us, and we have an ifaddr to use with it. + */ + from.sat_len = sizeof(struct sockaddr_at); + from.sat_family = AF_APPLETALK; - if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) { - aout[ i ] = *data; - } else { - aout[ i ] = '.'; - } + /* + * We are no longer interested in the link layer so cut it off. + */ + if (elh == NULL) { + if (ddp_cksum && cksum && cksum != + at_cksum(m, sizeof(int))) { + ddpstat.ddps_badsum++; + goto out; + } + m_adj(m, sizeof(struct ddpehdr)); + } else + m_adj(m, sizeof(struct ddpshdr)); - xout[ (i*3) + 2 ] = ' '; + /* + * Search for ddp protocol control blocks that match these addresses. + */ + DDP_LIST_SLOCK(); + if ((ddp = ddp_search(&from, &to, aa)) == NULL) + goto out_unlock; - i++; - len--; - data++; +#ifdef MAC + if (mac_socket_check_deliver(ddp->ddp_socket, m) != 0) + goto out_unlock; +#endif - if ( i > BPALEN - 2 ) { - printf( "%s\t%s\n", xout, aout ); - bzero( xout, BPXLEN ); - bzero( aout, BPALEN ); - i = 0; - continue; + /* + * If we found one, deliver the packet to the socket + */ + SOCKBUF_LOCK(&ddp->ddp_socket->so_rcv); + if (sbappendaddr_locked(&ddp->ddp_socket->so_rcv, + (struct sockaddr *)&from, m, NULL) == 0) { + SOCKBUF_UNLOCK(&ddp->ddp_socket->so_rcv); + /* + * If the socket is full (or similar error) dump the packet. + */ + ddpstat.ddps_nosockspace++; + goto out_unlock; } - } -} -static void -m_printm( struct mbuf *m ) -{ - for (; m; m = m->m_next ) { - bprint( mtod( m, char * ), m->m_len ); - } + /* + * And wake up whatever might be waiting for it + */ + sorwakeup_locked(ddp->ddp_socket); + m = NULL; +out_unlock: + DDP_LIST_SUNLOCK(); +out: + if (aa != NULL) + ifa_free(&aa->aa_ifa); + if (m != NULL) + m_freem(m); } -#endif Index: phase2.h =================================================================== --- phase2.h (.../stable/4/sys/netatalk) (revision 196046) +++ phase2.h (.../head/sys/netatalk) (revision 196046) @@ -1,6 +1,28 @@ -/* +/*- * 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. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * $FreeBSD$ */ #include Index: COPYRIGHT =================================================================== --- COPYRIGHT (.../stable/4/sys/netatalk) (revision 196046) +++ COPYRIGHT (.../head/sys/netatalk) (revision 196046) @@ -1,4 +1,28 @@ -/* +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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. + * * Copyright (c) 1990,1994 Regents of The University of Michigan. * All Rights Reserved. * @@ -22,4 +46,5 @@ * Ann Arbor, Michigan * +1-313-764-2278 * netatalk@umich.edu + * $FreeBSD$ */ Index: at_proto.c =================================================================== --- at_proto.c (.../stable/4/sys/netatalk) (revision 196046) +++ at_proto.c (.../head/sys/netatalk) (revision 196046) @@ -1,5 +1,5 @@ -/* - * Copyright (c) 1990,1991 Regents of The University of Michigan. +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and @@ -19,6 +19,8 @@ * Ann Arbor, Michigan * +1-313-763-0525 * netatalk@itd.umich.edu + * + * $FreeBSD$ */ #include @@ -34,36 +36,29 @@ #include #include -extern struct domain atalkdomain; +static struct domain atalkdomain; static 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. deprecated */ - NULL, - /* utility routines. */ - ddp_init, 0, 0, 0, - &ddp_usrreqs - }, + { + /* Identifiers */ + .pr_type = SOCK_DGRAM, + .pr_domain = &atalkdomain, + .pr_protocol = ATPROTO_DDP, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_output = ddp_output, + .pr_init = ddp_init, + .pr_usrreqs = &ddp_usrreqs, + }, }; static struct domain atalkdomain = { - AF_APPLETALK, "appletalk", 0, 0, 0, - atalksw, &atalksw[sizeof(atalksw)/sizeof(atalksw[0])], - 0, rn_inithead, - 8 * (u_long) &((struct sockaddr_at *) 0)->sat_addr, - sizeof(struct sockaddr_at) + .dom_family = AF_APPLETALK, + .dom_name = "appletalk", + .dom_protosw = atalksw, + .dom_protoswNPROTOSW = &atalksw[sizeof(atalksw)/sizeof(atalksw[0])], + .dom_rtattach = at_inithead, + .dom_rtoffset = offsetof(struct sockaddr_at, sat_addr) << 3, + .dom_maxrtkey = sizeof(struct sockaddr_at), }; DOMAIN_SET(atalk); - Index: ddp_output.c =================================================================== --- ddp_output.c (.../stable/4/sys/netatalk) (revision 196046) +++ ddp_output.c (.../head/sys/netatalk) (revision 196046) @@ -1,5 +1,5 @@ -/* - * Copyright (c) 1990,1991 Regents of The University of Michigan. +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and @@ -40,191 +40,208 @@ #include #include +#include + int ddp_cksum = 1; int -ddp_output( struct mbuf *m, struct socket *so) +ddp_output(struct mbuf *m, struct socket *so) { - struct ddpehdr *deh; - struct ddpcb *ddp = sotoddpcb( so ); + struct ddpehdr *deh; + struct ddpcb *ddp = sotoddpcb(so); - M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT ); +#ifdef MAC + mac_socket_create_mbuf(so, m); +#endif - deh = mtod( m, struct ddpehdr *); - deh->deh_pad = 0; - deh->deh_hops = 0; + M_PREPEND(m, sizeof(struct ddpehdr), M_DONTWAIT); + if (m == NULL) + return (ENOBUFS); - deh->deh_len = m->m_pkthdr.len; + deh = mtod(m, struct ddpehdr *); + deh->deh_pad = 0; + deh->deh_hops = 0; - 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; + deh->deh_len = m->m_pkthdr.len; - /* - * 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 ); + 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); + #ifdef NETATALK_DEBUG - printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n", + printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n", ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport, ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport); #endif - return( ddp_route( m, &ddp->ddp_route )); + return (ddp_route(m, &ddp->ddp_route)); } u_short -at_cksum( struct mbuf *m, int skip) +at_cksum(struct mbuf *m, int skip) { - u_char *data, *end; - u_long cksum = 0; + 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; + 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 ); + if (cksum == 0) + cksum = 0x0000ffff; + return ((u_short)cksum); } int -ddp_route( struct mbuf *m, struct route *ro) +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; - u_short net; + struct sockaddr_at gate; + struct elaphdr *elh; + struct mbuf *m0; + struct at_ifaddr *aa = NULL; + struct ifnet *ifp = NULL; + u_short net; #if 0 - /* Check for net zero, node zero ("myself") */ - if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET - && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) { - /* Find the loopback interface */ - } + /* Check for net zero, node zero ("myself") */ + if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET + && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) { + /* Find the loopback interface */ + } #endif - /* - * if we have a route, find the ifa that refers to this route. - * I.e The ifa used to get to the gateway. - */ - if ( (ro->ro_rt == NULL) - || ( ro->ro_rt->rt_ifa == NULL ) - || ( (ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL )) { - rtalloc(ro); - } - if ( (ro->ro_rt != NULL) - && ( ro->ro_rt->rt_ifa ) - && ( ifp = ro->ro_rt->rt_ifa->ifa_ifp )) { - net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if (((net == 0) || (aa->aa_ifp == ifp)) && - net >= ntohs( aa->aa_firstnet ) && - net <= ntohs( aa->aa_lastnet )) { - break; - } - } - } else { - m_freem( m ); + /* + * If we have a route, find the ifa that refers to this route. I.e + * the ifa used to get to the gateway. + */ + if ((ro->ro_rt == NULL) || (ro->ro_rt->rt_ifa == NULL) || + ((ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL)) + rtalloc(ro); + if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) && + (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) { + net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (((net == 0) || (aa->aa_ifp == ifp)) && + net >= ntohs(aa->aa_firstnet) && + net <= ntohs(aa->aa_lastnet)) + break; + } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } else { + m_freem(m); #ifdef NETATALK_DEBUG - if (ro->ro_rt == NULL) - printf ("ddp_route: no ro_rt.\n"); - else if (ro->ro_rt->rt_ifa == NULL) - printf ("ddp_route: no ro_rt->rt_ifa\n"); - else - printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n"); + if (ro->ro_rt == NULL) + printf ("ddp_route: no ro_rt.\n"); + else if (ro->ro_rt->rt_ifa == NULL) + printf ("ddp_route: no ro_rt->rt_ifa\n"); + else + printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n"); #endif - return( ENETUNREACH ); - } + return (ENETUNREACH); + } - if ( aa == NULL ) { + if (aa == NULL) { #ifdef NETATALK_DEBUG - printf( "ddp_route: no atalk address found for %s%d\n", - ifp->if_name, ifp->if_unit); + printf("ddp_route: no atalk address found for %s\n", + ifp->if_xname); #endif - m_freem( m ); - return( ENETUNREACH ); - } + m_freem(m); + return (ENETUNREACH); + } - /* - * if the destination address is on a directly attached node use that, - * else use the official gateway. - */ - if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= - ntohs( aa->aa_firstnet ) && - ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= - ntohs( aa->aa_lastnet )) { - gate = *satosat( &ro->ro_dst ); - } else { - gate = *satosat( ro->ro_rt->rt_gateway ); - } + /* + * If the destination address is on a directly attached node use + * that, else use the official gateway. + */ + if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= + ntohs(aa->aa_firstnet) && + ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= + ntohs(aa->aa_lastnet)) + gate = *satosat(&ro->ro_dst); + else + gate = *satosat(ro->ro_rt->rt_gateway); - /* - * 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) ) { - MGET( m0, M_WAIT, MT_HEADER ); - if ( m0 == 0 ) { - m_freem( m ); - printf("ddp_route: no buffers\n"); - return( ENOBUFS ); + /* + * 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. + * + * XXXRW: kern/4184 suggests that an m_pullup() of (m) should take + * place here to address possible alignment issues. + * + * XXXRW: This appears not to handle M_PKTHDR properly, as it doesn't + * move the existing header from the old packet to the new one. + * Posibly should call M_MOVE_PKTHDR()? This would also allow + * removing mac_mbuf_copy(). + */ + if (!(aa->aa_flags & AFA_PHASE2)) { + MGET(m0, M_DONTWAIT, MT_DATA); + if (m0 == NULL) { + ifa_free(&aa->aa_ifa); + m_freem(m); + printf("ddp_route: no buffers\n"); + return (ENOBUFS); + } +#ifdef MAC + mac_mbuf_copy(m, m0); +#endif + m0->m_next = m; + /* XXX perhaps we ought to align the header? */ + 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; + elh->el_dnode = gate.sat_addr.s_node; } - m0->m_next = m; - /* XXX perhaps we ought to align the header? */ - m0->m_len = SZ_ELAPHDR; - m = m0; + ro->ro_rt->rt_use++; - elh = mtod( m, struct elaphdr *); - elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node; - elh->el_type = ELAP_DDPEXTEND; - elh->el_dnode = gate.sat_addr.s_node; - } - ro->ro_rt->rt_use++; - #ifdef NETATALK_DEBUG - printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s%d)\n", - ntohs(satosat(&aa->aa_addr)->sat_addr.s_net), - satosat(&aa->aa_addr)->sat_addr.s_node, - ntohs(satosat(&ro->ro_dst)->sat_addr.s_net), - satosat(&ro->ro_dst)->sat_addr.s_node, - ntohs(gate.sat_addr.s_net), - gate.sat_addr.s_node, - ifp->if_name, ifp->if_unit); + printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s)\n", + ntohs(satosat(&aa->aa_addr)->sat_addr.s_net), + satosat(&aa->aa_addr)->sat_addr.s_node, + ntohs(satosat(&ro->ro_dst)->sat_addr.s_net), + satosat(&ro->ro_dst)->sat_addr.s_node, + ntohs(gate.sat_addr.s_net), gate.sat_addr.s_node, ifp->if_xname); #endif - /* short-circuit the output if we're sending this to ourself */ - if ((satosat(&aa->aa_addr)->sat_addr.s_net == satosat(&ro->ro_dst)->sat_addr.s_net) && - (satosat(&aa->aa_addr)->sat_addr.s_node == satosat(&ro->ro_dst)->sat_addr.s_node)) - { - return (if_simloop(ifp, m, gate.sat_family, 0)); - } + /* Short-circuit the output if we're sending this to ourself. */ + if ((satosat(&aa->aa_addr)->sat_addr.s_net == + satosat(&ro->ro_dst)->sat_addr.s_net) && + (satosat(&aa->aa_addr)->sat_addr.s_node == + satosat(&ro->ro_dst)->sat_addr.s_node)) { + ifa_free(&aa->aa_ifa); + return (if_simloop(ifp, m, gate.sat_family, 0)); + } + ifa_free(&aa->aa_ifa); - return((*ifp->if_output)( ifp, - m, (struct sockaddr *)&gate, NULL)); /* XXX */ + /* XXX */ + return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL)); } Index: aarp.h =================================================================== --- aarp.h (.../stable/4/sys/netatalk) (revision 196046) +++ aarp.h (.../head/sys/netatalk) (revision 196046) @@ -1,11 +1,34 @@ -/* +/*- * 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. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * * $FreeBSD$ */ #ifndef _NETATALK_AARP_H_ +#define _NETATALK_AARP_H_ + /* * This structure is used for both phase 1 and 2. Under phase 1 * the net is not filled in. It is in phase 2. In both cases, the @@ -14,46 +37,47 @@ * 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; + u_char ap_pa[4]; + struct ap_node { + u_char an_zero; + u_char an_net[2]; + u_char an_node; + } __packed 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 arphdr eaa_hdr; + u_char aarp_sha[6]; + union aapa aarp_spu; + u_char aarp_tha[6]; + union aapa aarp_tpu; +} __packed; +#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; + 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 AARPHRD_ETHER 0x0001 -#define AARPOP_REQUEST 0x01 -#define AARPOP_RESPONSE 0x02 -#define AARPOP_PROBE 0x03 +#define AARPOP_REQUEST 0x01 +#define AARPOP_RESPONSE 0x02 +#define AARPOP_PROBE 0x03 #ifdef _KERNEL struct aarptab *aarptnew(struct at_addr *); Index: at_rmx.c =================================================================== --- at_rmx.c (.../stable/4/sys/netatalk) (revision 196046) +++ at_rmx.c (.../head/sys/netatalk) (revision 196046) @@ -1,4 +1,4 @@ -/* +/*- * Copyright 1994, 1995 Massachusetts Institute of Technology * * Permission to use, copy, modify, and distribute this software and @@ -27,9 +27,10 @@ * SUCH DAMAGE. * * at_rmx.c,v 1.13 1995/05/30 08:09:31 rgrimes Exp + * $FreeBSD$ */ -/* This code generates debugging traces to the radix code */ +/* This code generates debugging traces to the radix code. */ #include #include @@ -37,98 +38,63 @@ #include -int at_inithead(void **head, int off); +int at_inithead(void **head, int off); -static char hexbuf[256]; +#if 0 +#define HEXBUF_LEN 256 -static char * -prsockaddr(void *v) +static const char * +prsockaddr(void *v, char *hexbuf) { char *bp = &hexbuf[0]; u_char *cp = v; - if (v) { + if (v != NULL) { int len = *cp; u_char *cplim = cp + len; /* return: "(len) hexdump" */ bp += sprintf(bp, "(%d)", len); - for (cp++; cp < cplim && bp < hexbuf+252; cp++) { + for (cp++; cp < cplim && bp < hexbuf + (HEXBUF_LEN - 4); + cp++) { *bp++ = "0123456789abcdef"[*cp / 16]; *bp++ = "0123456789abcdef"[*cp % 16]; } - } else { + } else bp+= sprintf(bp, "null"); - } *bp = '\0'; - - return &hexbuf[0]; + return (hexbuf); } +#endif 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; - printf("at_addroute: v=%s\n", prsockaddr(v_arg)); - printf("at_addroute: n=%s\n", prsockaddr(n_arg)); - printf("at_addroute: head=%p treenodes=%p\n", - (void *)head, (void *)treenodes); - - rn = rn_addroute(v_arg, n_arg, head, treenodes); - - printf("at_addroute: returns rn=%p\n", (void *)rn); - - return rn; + return (rn_addroute(v_arg, n_arg, head, treenodes)); } static struct radix_node * at_matroute(void *v_arg, struct radix_node_head *head) { - struct radix_node *rn; - printf("at_matroute: v=%s\n", prsockaddr(v_arg)); - printf("at_matroute: head=%p\n", (void *)head); - - rn = rn_match(v_arg, head); - - printf("at_matroute: returnr rn=%p\n", (void *)rn); - - return rn; + return (rn_match(v_arg, head)); } 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=%p\n", (void *)head); - - rn = rn_lookup(v_arg, m_arg, head); - - printf("at_lookup: returns rn=%p\n", (void *)rn); - - return rn; + return (rn_lookup(v_arg, m_arg, head)); } -static struct radix_node * +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=%p\n", (void *)head); - - rn = rn_delete(v_arg, netmask_arg, head); - - printf("at_delroute: returns rn=%p\n", (void *)rn); - - return rn; + return (rn_delete(v_arg, netmask_arg, head)); } /* @@ -139,13 +105,13 @@ { struct radix_node_head *rnh; - if(!rn_inithead(head, off)) - return 0; + 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; + return (1); } Index: ddp_pcb.c =================================================================== --- ddp_pcb.c (.../stable/4/sys/netatalk) (revision 0) +++ ddp_pcb.c (.../head/sys/netatalk) (revision 196046) @@ -0,0 +1,416 @@ +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct mtx ddp_list_mtx; +static struct ddpcb *ddp_ports[ATPORT_LAST]; +struct ddpcb *ddpcb_list = NULL; + +void +at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr) +{ + + /* + * Prevent modification of ddp during copy of addr. + */ + DDP_LOCK_ASSERT(ddp); + *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT); +} + +int +at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) +{ + struct sockaddr_at lsat, *sat; + struct at_ifaddr *aa; + struct ddpcb *ddpp; + + /* + * We read and write both the ddp passed in, and also ddp_ports. + */ + DDP_LIST_XLOCK_ASSERT(); + DDP_LOCK_ASSERT(ddp); + + /* + * Shouldn't be bound. + */ + if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) + return (EINVAL); + + /* + * Validate passed address. + */ + aa = NULL; + if (addr != NULL) { + sat = (struct sockaddr_at *)addr; + if (sat->sat_family != AF_APPLETALK) + return (EAFNOSUPPORT); + + if (sat->sat_addr.s_node != ATADDR_ANYNODE || + sat->sat_addr.s_net != ATADDR_ANYNET) { + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + 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; + } + AT_IFADDR_RUNLOCK(); + if (aa == NULL) + return (EADDRNOTAVAIL); + } + + if (sat->sat_port != ATADDR_ANYPORT) { + if (sat->sat_port < ATPORT_FIRST || + sat->sat_port >= ATPORT_LAST) + return (EINVAL); + if (sat->sat_port < ATPORT_RESERVED && + priv_check(td, PRIV_NETATALK_RESERVEDPORT)) + return (EACCES); + } + } else { + bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); + lsat.sat_len = sizeof(struct sockaddr_at); + lsat.sat_addr.s_node = ATADDR_ANYNODE; + lsat.sat_addr.s_net = ATADDR_ANYNET; + lsat.sat_family = AF_APPLETALK; + sat = &lsat; + } + + if (sat->sat_addr.s_node == ATADDR_ANYNODE && + sat->sat_addr.s_net == ATADDR_ANYNET) { + AT_IFADDR_RLOCK(); + if (TAILQ_EMPTY(&at_ifaddrhead)) { + AT_IFADDR_RUNLOCK(); + return (EADDRNOTAVAIL); + } + sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddrhead))->sat_addr; + AT_IFADDR_RUNLOCK(); + } + 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] == NULL) + 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 != NULL) + ddp->ddp_pnext->ddp_pprev = ddp; + } + + return (0); +} + +int +at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) +{ + struct sockaddr_at *sat = (struct sockaddr_at *)addr; + struct route *ro; + struct at_ifaddr *aa = NULL; + struct ifnet *ifp; + u_short hintnet = 0, net; + + DDP_LIST_XLOCK_ASSERT(); + DDP_LOCK_ASSERT(ddp); + + 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 = NULL; + AT_IFADDR_RLOCK(); + if ((ifp = ro->ro_rt->rt_ifp) != NULL) { + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (aa->aa_ifp == ifp && + ntohs(net) >= ntohs(aa->aa_firstnet) && + ntohs(net) <= ntohs(aa->aa_lastnet)) + break; + } + } + if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != + (hintnet ? hintnet : sat->sat_addr.s_net) || + satosat(&ro->ro_dst)->sat_addr.s_node != + sat->sat_addr.s_node)) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } + AT_IFADDR_RUNLOCK(); + } + + /* + * If we've got no route for this interface, try to find one. + */ + if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { + ro->ro_dst.sa_len = sizeof(struct sockaddr_at); + 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 = NULL; + if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (aa->aa_ifp == ifp) + break; + } + AT_IFADDR_RUNLOCK(); + } + if (aa == NULL) + return (ENETUNREACH); + + ddp->ddp_fsat = *sat; + if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) + return (at_pcbsetaddr(ddp, NULL, td)); + return (0); +} + +void +at_pcbdisconnect(struct ddpcb *ddp) +{ + + DDP_LOCK_ASSERT(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; +} + +int +at_pcballoc(struct socket *so) +{ + struct ddpcb *ddp; + + DDP_LIST_XLOCK_ASSERT(); + + ddp = malloc(sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); + if (ddp == NULL) + return (ENOBUFS); + DDP_LOCK_INIT(ddp); + ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; + + ddp->ddp_socket = so; + so->so_pcb = (caddr_t)ddp; + + ddp->ddp_next = ddpcb_list; + ddp->ddp_prev = NULL; + ddp->ddp_pprev = NULL; + ddp->ddp_pnext = NULL; + if (ddpcb_list != NULL) + ddpcb_list->ddp_prev = ddp; + ddpcb_list = ddp; + return(0); +} + +void +at_pcbdetach(struct socket *so, struct ddpcb *ddp) +{ + + /* + * We modify ddp, ddp_ports, and the global list. + */ + DDP_LIST_XLOCK_ASSERT(); + DDP_LOCK_ASSERT(ddp); + KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); + + so->so_pcb = NULL; + + /* 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_list = ddp->ddp_next; + if (ddp->ddp_next) + ddp->ddp_next->ddp_prev = ddp->ddp_prev; + DDP_UNLOCK(ddp); + DDP_LOCK_DESTROY(ddp); + free(ddp, M_PCB); +} + +/* + * 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; + + DDP_LIST_SLOCK_ASSERT(); + + /* + * 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) { + DDP_LOCK(ddp); + /* 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) { + DDP_UNLOCK(ddp); + 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) { + DDP_UNLOCK(ddp); + 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)) { + DDP_UNLOCK(ddp); + break; + } + DDP_UNLOCK(ddp); + } + return (ddp); +} Property changes on: ddp_pcb.c ___________________________________________________________________ Added: svn:keywords + FreeBSD=%H