2009-04-18 18:58:02 +04:00
|
|
|
/* $NetBSD: aarp.c,v 1.33 2009/04/18 14:58:05 tsutsui Exp $ */
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2001-11-13 03:00:58 +03:00
|
|
|
#include <sys/cdefs.h>
|
2009-04-18 18:58:02 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: aarp.c,v 1.33 2009/04/18 14:58:05 tsutsui Exp $");
|
2003-06-23 15:00:59 +04:00
|
|
|
|
|
|
|
#include "opt_mbuftrace.h"
|
2001-11-13 03:00:58 +03:00
|
|
|
|
2001-11-15 12:47:59 +03:00
|
|
|
#include <sys/param.h>
|
1997-04-03 01:31:01 +04:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <sys/systm.h>
|
2000-03-23 10:01:25 +03:00
|
|
|
#include <sys/callout.h>
|
1997-04-03 01:31:01 +04:00
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
2008-04-24 15:38:36 +04:00
|
|
|
#include <sys/socketvar.h>
|
1997-04-03 01:31:01 +04:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <net/if_ether.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#undef s_net
|
|
|
|
|
|
|
|
#include <netatalk/at.h>
|
|
|
|
#include <netatalk/at_var.h>
|
|
|
|
#include <netatalk/aarp.h>
|
|
|
|
#include <netatalk/ddp_var.h>
|
|
|
|
#include <netatalk/phase2.h>
|
|
|
|
#include <netatalk/at_extern.h>
|
|
|
|
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
static struct aarptab *aarptnew(const struct at_addr *);
|
|
|
|
static void aarptfree(struct aarptab *);
|
|
|
|
static void at_aarpinput(struct ifnet *, struct mbuf *);
|
|
|
|
static void aarptimer(void *);
|
|
|
|
static void aarpwhohas(struct ifnet *, const struct sockaddr_at *);
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
#define AARPTAB_BSIZ 9
|
|
|
|
#define AARPTAB_NB 19
|
|
|
|
#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB)
|
|
|
|
struct aarptab aarptab[AARPTAB_SIZE];
|
|
|
|
|
|
|
|
#define AARPTAB_HASH(a) \
|
|
|
|
((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
|
|
|
|
|
|
|
|
#define AARPTAB_LOOK(aat,addr) { \
|
|
|
|
int n; \
|
|
|
|
aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \
|
|
|
|
for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \
|
|
|
|
if ( aat->aat_ataddr.s_net == (addr).s_net && \
|
|
|
|
aat->aat_ataddr.s_node == (addr).s_node ) \
|
|
|
|
break; \
|
|
|
|
if ( n >= AARPTAB_BSIZ ) \
|
|
|
|
aat = 0; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define AARPT_AGE (60 * 1)
|
|
|
|
#define AARPT_KILLC 20
|
|
|
|
#define AARPT_KILLI 3
|
|
|
|
|
2003-02-26 10:53:04 +03:00
|
|
|
const u_char atmulticastaddr[6] = {
|
1997-04-03 01:31:01 +04:00
|
|
|
0x09, 0x00, 0x07, 0xff, 0xff, 0xff
|
|
|
|
};
|
|
|
|
|
2003-02-26 10:53:04 +03:00
|
|
|
const u_char at_org_code[3] = {
|
1997-04-03 01:31:01 +04:00
|
|
|
0x08, 0x00, 0x07
|
|
|
|
};
|
2003-02-26 10:53:04 +03:00
|
|
|
const u_char aarp_org_code[3] = {
|
1997-04-03 01:31:01 +04:00
|
|
|
0x00, 0x00, 0x00
|
|
|
|
};
|
|
|
|
|
2000-03-23 10:01:25 +03:00
|
|
|
struct callout aarptimer_callout;
|
2003-02-26 10:53:04 +03:00
|
|
|
#ifdef MBUFTRACE
|
2006-10-11 01:49:14 +04:00
|
|
|
struct mowner aarp_mowner = MOWNER_INIT("atalk", "arp");
|
2003-02-26 10:53:04 +03:00
|
|
|
#endif
|
1997-04-03 01:31:01 +04:00
|
|
|
|
2002-10-23 01:58:33 +04:00
|
|
|
/*ARGSUSED*/
|
1997-04-03 01:31:01 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
aarptimer(void *ignored)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct aarptab *aat;
|
|
|
|
int i, s;
|
|
|
|
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_enter(softnet_lock);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&aarptimer_callout, AARPT_AGE * hz, aarptimer, NULL);
|
1997-04-03 01:31:01 +04:00
|
|
|
aat = aarptab;
|
|
|
|
for (i = 0; i < AARPTAB_SIZE; i++, aat++) {
|
|
|
|
int killtime = (aat->aat_flags & ATF_COM) ? AARPT_KILLC :
|
|
|
|
AARPT_KILLI;
|
|
|
|
if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM))
|
|
|
|
continue;
|
|
|
|
if (++aat->aat_timer < killtime)
|
|
|
|
continue;
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1997-04-03 01:31:01 +04:00
|
|
|
aarptfree(aat);
|
|
|
|
splx(s);
|
|
|
|
}
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_exit(softnet_lock);
|
1997-04-03 01:31:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* search through the network addresses to find one that includes the given
|
|
|
|
* network.. remember to take netranges into consideration.
|
|
|
|
*/
|
1997-04-03 22:38:21 +04:00
|
|
|
struct ifaddr *
|
2009-03-14 18:35:58 +03:00
|
|
|
at_ifawithnet(const struct sockaddr_at *sat, struct ifnet *ifp)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
1997-04-03 22:38:21 +04:00
|
|
|
struct ifaddr *ifa;
|
1997-04-03 01:31:01 +04:00
|
|
|
struct sockaddr_at *sat2;
|
|
|
|
struct netrange *nr;
|
|
|
|
|
2007-12-04 13:22:34 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
1997-04-03 01:31:01 +04:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_APPLETALK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
sat2 = satosat(ifa->ifa_addr);
|
|
|
|
if (sat2->sat_addr.s_net == sat->sat_addr.s_net)
|
|
|
|
break;
|
|
|
|
|
|
|
|
nr = (struct netrange *) (sat2->sat_zero);
|
|
|
|
if ((nr->nr_phase == 2)
|
2005-08-24 10:06:51 +04:00
|
|
|
&& (ntohs(nr->nr_firstnet) <= ntohs(sat->sat_addr.s_net))
|
|
|
|
&& (ntohs(nr->nr_lastnet) >= ntohs(sat->sat_addr.s_net)))
|
1997-04-03 01:31:01 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ifa;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
aarpwhohas(struct ifnet *ifp, const struct sockaddr_at *sat)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct mbuf *m;
|
|
|
|
struct ether_header *eh;
|
|
|
|
struct ether_aarp *ea;
|
|
|
|
struct at_ifaddr *aa;
|
|
|
|
struct llc *llc;
|
|
|
|
struct sockaddr sa;
|
|
|
|
|
|
|
|
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
|
|
|
|
return;
|
|
|
|
|
2003-02-26 10:53:04 +03:00
|
|
|
MCLAIM(m, &aarp_mowner);
|
1997-04-03 01:31:01 +04:00
|
|
|
m->m_len = sizeof(*ea);
|
|
|
|
m->m_pkthdr.len = sizeof(*ea);
|
|
|
|
MH_ALIGN(m, sizeof(*ea));
|
|
|
|
|
|
|
|
ea = mtod(m, struct ether_aarp *);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(ea, 0, sizeof(*ea));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
ea->aarp_hrd = htons(AARPHRD_ETHER);
|
1998-10-13 06:34:31 +04:00
|
|
|
ea->aarp_pro = htons(ETHERTYPE_ATALK);
|
1997-04-03 01:31:01 +04:00
|
|
|
ea->aarp_hln = sizeof(ea->aarp_sha);
|
|
|
|
ea->aarp_pln = sizeof(ea->aarp_spu);
|
|
|
|
ea->aarp_op = htons(AARPOP_REQUEST);
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
1997-04-03 22:38:21 +04:00
|
|
|
if ((aa = (struct at_ifaddr *) at_ifawithnet(sat, ifp)) == NULL) {
|
1997-04-03 01:31:01 +04:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eh = (struct ether_header *) sa.sa_data;
|
|
|
|
|
|
|
|
if (aa->aa_flags & AFA_PHASE2) {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(eh->ether_dhost, atmulticastaddr,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(eh->ether_dhost));
|
1999-09-22 02:18:51 +04:00
|
|
|
eh->ether_type = 0; /* if_output will treat as 802 */
|
2003-05-28 02:27:21 +04:00
|
|
|
M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
|
|
|
|
if (!m)
|
|
|
|
return;
|
|
|
|
|
1997-04-03 01:31:01 +04:00
|
|
|
llc = mtod(m, struct llc *);
|
|
|
|
llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
|
|
|
|
llc->llc_control = LLC_UI;
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code));
|
1997-04-03 01:31:01 +04:00
|
|
|
llc->llc_ether_type = htons(ETHERTYPE_AARP);
|
|
|
|
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(ea->aarp_spnet));
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_tpnet, &sat->sat_addr.s_net,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(ea->aarp_tpnet));
|
|
|
|
ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node;
|
|
|
|
ea->aarp_tpnode = sat->sat_addr.s_node;
|
|
|
|
} else {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(eh->ether_dhost, etherbroadcastaddr,
|
1997-04-03 01:31:01 +04:00
|
|
|
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 via %u.%u seaking %u.%u\n",
|
|
|
|
ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node,
|
|
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
|
|
|
|
#endif /* NETATALKDEBUG */
|
|
|
|
|
|
|
|
sa.sa_len = sizeof(struct sockaddr);
|
|
|
|
sa.sa_family = AF_UNSPEC;
|
|
|
|
(*ifp->if_output) (ifp, m, &sa, NULL); /* XXX NULL should be routing */
|
|
|
|
/* information */
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
aarpresolve(struct ifnet *ifp, struct mbuf *m,
|
|
|
|
const struct sockaddr_at *destsat, u_char *desten)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct at_ifaddr *aa;
|
|
|
|
struct aarptab *aat;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
if (at_broadcast(destsat)) {
|
1997-04-03 22:38:21 +04:00
|
|
|
aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp);
|
|
|
|
if (aa == NULL) {
|
1997-04-03 01:31:01 +04:00
|
|
|
m_freem(m);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (aa->aa_flags & AFA_PHASE2)
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(desten, atmulticastaddr,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(atmulticastaddr));
|
|
|
|
else
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(desten, etherbroadcastaddr,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(etherbroadcastaddr));
|
|
|
|
return 1;
|
|
|
|
}
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1997-04-03 01:31:01 +04:00
|
|
|
AARPTAB_LOOK(aat, destsat->sat_addr);
|
|
|
|
if (aat == 0) { /* No entry */
|
|
|
|
aat = aarptnew(&destsat->sat_addr);
|
|
|
|
if (aat == 0)
|
|
|
|
panic("aarpresolve: no free entry");
|
|
|
|
|
|
|
|
aat->aat_hold = m;
|
|
|
|
aarpwhohas(ifp, destsat);
|
|
|
|
splx(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* found an entry */
|
|
|
|
aat->aat_timer = 0;
|
|
|
|
if (aat->aat_flags & ATF_COM) { /* entry is COMplete */
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(desten, aat->aat_enaddr, sizeof(aat->aat_enaddr));
|
1997-04-03 01:31:01 +04:00
|
|
|
splx(s);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* entry has not completed */
|
|
|
|
if (aat->aat_hold)
|
|
|
|
m_freem(aat->aat_hold);
|
|
|
|
aat->aat_hold = m;
|
|
|
|
aarpwhohas(ifp, destsat);
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-03-14 18:35:58 +03:00
|
|
|
aarpinput(struct ifnet *ifp, struct mbuf *m)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct arphdr *ar;
|
|
|
|
|
|
|
|
if (ifp->if_flags & IFF_NOARP)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (m->m_len < sizeof(struct arphdr))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ar = mtod(m, struct arphdr *);
|
|
|
|
if (ntohs(ar->ar_hrd) != AARPHRD_ETHER)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
switch (ntohs(ar->ar_pro)) {
|
1998-10-13 06:34:31 +04:00
|
|
|
case ETHERTYPE_ATALK:
|
1997-04-03 01:31:01 +04:00
|
|
|
at_aarpinput(ifp, m);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
m_freem(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
at_aarpinput(struct ifnet *ifp, struct mbuf *m)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct ether_aarp *ea;
|
|
|
|
struct at_ifaddr *aa;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct ifaddr *ia;
|
1997-04-03 01:31:01 +04:00
|
|
|
struct aarptab *aat;
|
|
|
|
struct ether_header *eh;
|
|
|
|
struct llc *llc;
|
|
|
|
struct sockaddr_at sat;
|
|
|
|
struct sockaddr sa;
|
|
|
|
struct at_addr spa, tpa, ma;
|
|
|
|
int op;
|
|
|
|
u_int16_t net;
|
|
|
|
|
|
|
|
ea = mtod(m, struct ether_aarp *);
|
|
|
|
|
|
|
|
/* Check to see if from my hardware address */
|
2009-03-18 18:14:29 +03:00
|
|
|
if (!memcmp(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha))) {
|
1997-04-03 01:31:01 +04:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
op = ntohs(ea->aarp_op);
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&net, ea->aarp_tpnet, sizeof(net));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
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;
|
1997-04-03 22:38:21 +04:00
|
|
|
aa = (struct at_ifaddr *) at_ifawithnet(&sat, ifp);
|
|
|
|
if (aa == NULL) {
|
1997-04-03 01:31:01 +04:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&spa.s_net, ea->aarp_spnet, sizeof(spa.s_net));
|
|
|
|
memcpy(&tpa.s_net, ea->aarp_tpnet, sizeof(tpa.s_net));
|
1997-04-03 01:31:01 +04:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Since we don't know the net, we just look for the first
|
|
|
|
* phase 1 address on the interface.
|
|
|
|
*/
|
2007-12-04 13:22:34 +03:00
|
|
|
IFADDR_FOREACH(ia, ifp) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
aa = (struct at_ifaddr *)ia;
|
1997-04-03 01:31:01 +04:00
|
|
|
if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
|
|
|
|
(aa->aa_flags & AFA_PHASE2) == 0)
|
|
|
|
break;
|
|
|
|
}
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
if (ia == NULL) {
|
1997-04-03 01:31:01 +04:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net;
|
|
|
|
}
|
|
|
|
|
|
|
|
spa.s_node = ea->aarp_spnode;
|
|
|
|
tpa.s_node = ea->aarp_tpnode;
|
|
|
|
ma.s_net = AA_SAT(aa)->sat_addr.s_net;
|
|
|
|
ma.s_node = AA_SAT(aa)->sat_addr.s_node;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This looks like it's from us.
|
|
|
|
*/
|
|
|
|
if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) {
|
|
|
|
if (aa->aa_flags & AFA_PROBING) {
|
|
|
|
/*
|
|
|
|
* We're probing, someone either responded to our
|
|
|
|
* probe, or probed for the same address we'd like
|
|
|
|
* to use. Change the address we're probing for.
|
|
|
|
*/
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&aa->aa_probe_ch);
|
1997-04-03 01:31:01 +04:00
|
|
|
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!! %s\n",
|
|
|
|
ether_sprintf(ea->aarp_sha));
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AARPTAB_LOOK(aat, spa);
|
|
|
|
if (aat) {
|
|
|
|
if (op == AARPOP_PROBE) {
|
|
|
|
/*
|
2003-01-29 01:26:33 +03:00
|
|
|
* Someone's probing for spa, deallocate the one we've
|
1997-04-03 01:31:01 +04:00
|
|
|
* got, so that if the prober keeps the address, we'll
|
|
|
|
* be able to arp for him.
|
|
|
|
*/
|
|
|
|
aarptfree(aat);
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(aat->aat_enaddr, ea->aarp_sha, sizeof(ea->aarp_sha));
|
1997-04-03 01:31:01 +04:00
|
|
|
aat->aat_flags |= ATF_COM;
|
|
|
|
if (aat->aat_hold) {
|
|
|
|
sat.sat_len = sizeof(struct sockaddr_at);
|
|
|
|
sat.sat_family = AF_APPLETALK;
|
|
|
|
sat.sat_addr = spa;
|
|
|
|
(*ifp->if_output)(ifp, aat->aat_hold,
|
|
|
|
(struct sockaddr *) & sat, NULL); /* XXX */
|
|
|
|
aat->aat_hold = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node
|
|
|
|
&& op != AARPOP_PROBE) {
|
|
|
|
if ((aat = aarptnew(&spa)) != NULL) {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(aat->aat_enaddr, ea->aarp_sha,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(ea->aarp_sha));
|
|
|
|
aat->aat_flags |= ATF_COM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Don't respond to responses, and never respond if we're
|
|
|
|
* still probing.
|
|
|
|
*/
|
|
|
|
if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
|
|
|
|
op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) {
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_tha, ea->aarp_sha, sizeof(ea->aarp_sha));
|
|
|
|
memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
eh = (struct ether_header *) sa.sa_data;
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(eh->ether_dhost, ea->aarp_tha, sizeof(eh->ether_dhost));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
if (aa->aa_flags & AFA_PHASE2) {
|
|
|
|
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;
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code));
|
1997-04-03 01:31:01 +04:00
|
|
|
llc->llc_ether_type = htons(ETHERTYPE_AARP);
|
|
|
|
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_tpnet, ea->aarp_spnet, sizeof(ea->aarp_tpnet));
|
|
|
|
memcpy(ea->aarp_spnet, &ma.s_net, sizeof(ea->aarp_spnet));
|
1999-09-22 02:18:51 +04:00
|
|
|
eh->ether_type = 0; /* if_output will treat as 802 */
|
1997-04-03 01:31:01 +04:00
|
|
|
} 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;
|
|
|
|
(*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-03-14 18:35:58 +03:00
|
|
|
aarptfree(struct aarptab *aat)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
if (aat->aat_hold)
|
|
|
|
m_freem(aat->aat_hold);
|
|
|
|
aat->aat_hold = 0;
|
|
|
|
aat->aat_timer = aat->aat_flags = 0;
|
|
|
|
aat->aat_ataddr.s_net = 0;
|
|
|
|
aat->aat_ataddr.s_node = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct aarptab *
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
aarptnew(const struct at_addr *addr)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
int oldest = -1;
|
|
|
|
struct aarptab *aat, *aato = NULL;
|
|
|
|
static int first = 1;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
first = 0;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&aarptimer_callout, 0);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&aarptimer_callout, hz, aarptimer, NULL);
|
2003-02-26 10:53:04 +03:00
|
|
|
MOWNER_ATTACH(&aarp_mowner);
|
1997-04-03 01:31:01 +04:00
|
|
|
}
|
|
|
|
aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ];
|
|
|
|
for (n = 0; n < AARPTAB_BSIZ; n++, aat++) {
|
|
|
|
if (aat->aat_flags == 0)
|
|
|
|
goto out;
|
|
|
|
if (aat->aat_flags & ATF_PERM)
|
|
|
|
continue;
|
|
|
|
if ((int) aat->aat_timer > oldest) {
|
|
|
|
oldest = aat->aat_timer;
|
|
|
|
aato = aat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aato == NULL)
|
|
|
|
return (NULL);
|
|
|
|
aat = aato;
|
|
|
|
aarptfree(aat);
|
|
|
|
out:
|
|
|
|
aat->aat_ataddr = *addr;
|
|
|
|
aat->aat_flags = ATF_INUSE;
|
|
|
|
return (aat);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2009-03-14 18:35:58 +03:00
|
|
|
aarpprobe(void *arp)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct mbuf *m;
|
|
|
|
struct ether_header *eh;
|
|
|
|
struct ether_aarp *ea;
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct ifaddr *ia;
|
1997-04-03 01:31:01 +04:00
|
|
|
struct at_ifaddr *aa;
|
|
|
|
struct llc *llc;
|
|
|
|
struct sockaddr sa;
|
|
|
|
struct ifnet *ifp = arp;
|
|
|
|
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_enter(softnet_lock);
|
|
|
|
|
1997-04-03 01:31:01 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2007-12-04 13:22:34 +03:00
|
|
|
IFADDR_FOREACH(ia, ifp) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
aa = (struct at_ifaddr *)ia;
|
1997-04-03 01:31:01 +04:00
|
|
|
if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
|
|
|
|
(aa->aa_flags & AFA_PROBING))
|
|
|
|
break;
|
|
|
|
}
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
if (ia == NULL) { /* serious error XXX */
|
1997-04-03 01:31:01 +04:00
|
|
|
printf("aarpprobe why did this happen?!\n");
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_exit(softnet_lock);
|
1997-04-03 01:31:01 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (aa->aa_probcnt <= 0) {
|
|
|
|
aa->aa_flags &= ~AFA_PROBING;
|
|
|
|
wakeup(aa);
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_exit(softnet_lock);
|
1997-04-03 01:31:01 +04:00
|
|
|
return;
|
|
|
|
} else {
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&aa->aa_probe_ch, hz / 5, aarpprobe, arp);
|
1997-04-03 01:31:01 +04:00
|
|
|
}
|
|
|
|
|
2008-04-24 15:38:36 +04:00
|
|
|
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) {
|
|
|
|
mutex_exit(softnet_lock);
|
1997-04-03 01:31:01 +04:00
|
|
|
return;
|
2008-04-24 15:38:36 +04:00
|
|
|
}
|
2003-02-26 10:53:04 +03:00
|
|
|
|
|
|
|
MCLAIM(m, &aarp_mowner);
|
1997-04-03 01:31:01 +04:00
|
|
|
m->m_len = sizeof(*ea);
|
|
|
|
m->m_pkthdr.len = sizeof(*ea);
|
|
|
|
MH_ALIGN(m, sizeof(*ea));
|
|
|
|
|
|
|
|
ea = mtod(m, struct ether_aarp *);
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(ea, 0, sizeof(*ea));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
ea->aarp_hrd = htons(AARPHRD_ETHER);
|
1998-10-13 06:34:31 +04:00
|
|
|
ea->aarp_pro = htons(ETHERTYPE_ATALK);
|
1997-04-03 01:31:01 +04:00
|
|
|
ea->aarp_hln = sizeof(ea->aarp_sha);
|
|
|
|
ea->aarp_pln = sizeof(ea->aarp_spu);
|
|
|
|
ea->aarp_op = htons(AARPOP_PROBE);
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha));
|
1997-04-03 01:31:01 +04:00
|
|
|
|
|
|
|
eh = (struct ether_header *) sa.sa_data;
|
|
|
|
|
|
|
|
if (aa->aa_flags & AFA_PHASE2) {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(eh->ether_dhost, atmulticastaddr,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(eh->ether_dhost));
|
1999-09-22 02:18:51 +04:00
|
|
|
eh->ether_type = 0; /* if_output will treat as 802 */
|
2003-05-28 02:27:21 +04:00
|
|
|
M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
|
2008-04-24 15:38:36 +04:00
|
|
|
if (!m) {
|
|
|
|
mutex_exit(softnet_lock);
|
2003-05-28 02:27:21 +04:00
|
|
|
return;
|
2008-04-24 15:38:36 +04:00
|
|
|
}
|
2003-05-28 02:27:21 +04:00
|
|
|
|
1997-04-03 01:31:01 +04:00
|
|
|
llc = mtod(m, struct llc *);
|
|
|
|
llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
|
|
|
|
llc->llc_control = LLC_UI;
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code));
|
1997-04-03 01:31:01 +04:00
|
|
|
llc->llc_ether_type = htons(ETHERTYPE_AARP);
|
|
|
|
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(ea->aarp_spnet));
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ea->aarp_tpnet, &AA_SAT(aa)->sat_addr.s_net,
|
1997-04-03 01:31:01 +04:00
|
|
|
sizeof(ea->aarp_tpnet));
|
|
|
|
ea->aarp_spnode = ea->aarp_tpnode =
|
|
|
|
AA_SAT(aa)->sat_addr.s_node;
|
|
|
|
} else {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(eh->ether_dhost, etherbroadcastaddr,
|
1997-04-03 01:31:01 +04:00
|
|
|
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);
|
|
|
|
#endif /* NETATALKDEBUG */
|
|
|
|
|
|
|
|
sa.sa_len = sizeof(struct sockaddr);
|
|
|
|
sa.sa_family = AF_UNSPEC;
|
|
|
|
(*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */
|
|
|
|
aa->aa_probcnt--;
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_exit(softnet_lock);
|
1997-04-03 01:31:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-03-16 00:23:31 +03:00
|
|
|
aarp_clean(void)
|
1997-04-03 01:31:01 +04:00
|
|
|
{
|
|
|
|
struct aarptab *aat;
|
|
|
|
int i;
|
|
|
|
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&aarptimer_callout);
|
1997-04-03 01:31:01 +04:00
|
|
|
for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++)
|
|
|
|
if (aat->aat_hold)
|
|
|
|
m_freem(aat->aat_hold);
|
|
|
|
}
|