Reorganize and extract arplookup1() for code-sharing. Share

null_sdl.  Introduce arp_setgate() for initializing a link-layer
nexthop, and use it to fulfill RTM_SETGATE requests.
This commit is contained in:
dyoung 2007-08-27 01:13:09 +00:00
parent ae7a571b06
commit 7caec74f02
1 changed files with 91 additions and 63 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_arp.c,v 1.125 2007/07/19 20:48:53 dyoung Exp $ */ /* $NetBSD: if_arp.c,v 1.126 2007/08/27 01:13:09 dyoung Exp $ */
/*- /*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@ -75,7 +75,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.125 2007/07/19 20:48:53 dyoung Exp $"); __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.126 2007/08/27 01:13:09 dyoung Exp $");
#include "opt_ddb.h" #include "opt_ddb.h"
#include "opt_inet.h" #include "opt_inet.h"
@ -130,7 +130,6 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.125 2007/07/19 20:48:53 dyoung Exp $");
#endif #endif
#define SIN(s) ((struct sockaddr_in *)s) #define SIN(s) ((struct sockaddr_in *)s)
#define SDL(s) ((struct sockaddr_dl *)s)
#define SRP(s) ((struct sockaddr_inarp *)s) #define SRP(s) ((struct sockaddr_inarp *)s)
/* /*
@ -147,8 +146,12 @@ int arpt_refresh = (5*60); /* time left before refreshing */
#define rt_expire rt_rmx.rmx_expire #define rt_expire rt_rmx.rmx_expire
#define rt_pksent rt_rmx.rmx_pksent #define rt_pksent rt_rmx.rmx_pksent
static struct sockaddr *arp_setgate(struct rtentry *, struct sockaddr *,
const struct sockaddr *);
static void arptfree(struct llinfo_arp *); static void arptfree(struct llinfo_arp *);
static void arptimer(void *); static void arptimer(void *);
static struct llinfo_arp *arplookup1(struct mbuf *, const struct in_addr *,
int, int, struct rtentry *);
static struct llinfo_arp *arplookup(struct mbuf *, const struct in_addr *, static struct llinfo_arp *arplookup(struct mbuf *, const struct in_addr *,
int, int); int, int);
static void in_arpinput(struct mbuf *); static void in_arpinput(struct mbuf *);
@ -169,6 +172,9 @@ int arpinit_done = 0;
struct arpstat arpstat; struct arpstat arpstat;
struct callout arptimer_ch; struct callout arptimer_ch;
/* Prototype for RTF_CLONING routes. */
static const struct sockaddr_dl null_sdl = { .sdl_len = sizeof(null_sdl),
.sdl_family = AF_LINK};
/* revarp state */ /* revarp state */
struct in_addr myip, srv_ip; struct in_addr myip, srv_ip;
@ -381,6 +387,35 @@ arptimer(void *arg)
splx(s); splx(s);
} }
/*
* We set the gateway for RTF_CLONING routes to a "prototype"
* link-layer sockaddr whose interface type (if_type) and interface
* index (if_index) fields are prepared.
*/
static struct sockaddr *
arp_setgate(struct rtentry *rt, struct sockaddr *gate,
const struct sockaddr *netmask)
{
/*
* XXX: If this is a manually added route to interface
* such as older version of routed or gated might provide,
* restore cloning bit.
*/
if ((rt->rt_flags & RTF_HOST) == 0 && netmask != NULL &&
satocsin(netmask)->sin_addr.s_addr != 0xffffffff)
rt->rt_flags |= RTF_CLONING;
if (rt->rt_flags & RTF_CLONING) {
/*
* Case 1: This route should come from a route to iface.
*/
rt_setgate(rt, (const struct sockaddr *)&null_sdl);
gate = rt->rt_gateway;
satosdl(gate)->sdl_type = rt->rt_ifp->if_type;
satosdl(gate)->sdl_index = rt->rt_ifp->if_index;
}
return gate;
}
/* /*
* Parallel to llc_rtrequest. * Parallel to llc_rtrequest.
*/ */
@ -389,10 +424,6 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
{ {
struct sockaddr *gate = rt->rt_gateway; struct sockaddr *gate = rt->rt_gateway;
struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
static const struct sockaddr_dl null_sdl = {
.sdl_len = sizeof(null_sdl),
.sdl_family = AF_LINK,
};
size_t allocsize; size_t allocsize;
struct mbuf *mold; struct mbuf *mold;
int s; int s;
@ -455,23 +486,12 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
switch (req) { switch (req) {
case RTM_SETGATE:
gate = arp_setgate(rt, gate, info->rti_info[RTAX_NETMASK]);
break;
case RTM_ADD: case RTM_ADD:
/* gate = arp_setgate(rt, gate, info->rti_info[RTAX_NETMASK]);
* XXX: If this is a manually added route to interface
* such as older version of routed or gated might provide,
* restore cloning bit.
*/
if ((rt->rt_flags & RTF_HOST) == 0 &&
satocsin(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
rt->rt_flags |= RTF_CLONING;
if (rt->rt_flags & RTF_CLONING) { if (rt->rt_flags & RTF_CLONING) {
/*
* Case 1: This route should come from a route to iface.
*/
rt_setgate(rt, (const struct sockaddr *)&null_sdl);
gate = rt->rt_gateway;
SDL(gate)->sdl_type = rt->rt_ifp->if_type;
SDL(gate)->sdl_index = rt->rt_ifp->if_index;
/* /*
* Give this route an expiration time, even though * Give this route an expiration time, even though
* it's a "permanent" route, so that routes cloned * it's a "permanent" route, so that routes cloned
@ -516,7 +536,7 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
arprequest(rt->rt_ifp, arprequest(rt->rt_ifp,
&satocsin(rt_getkey(rt))->sin_addr, &satocsin(rt_getkey(rt))->sin_addr,
&satocsin(rt_getkey(rt))->sin_addr, &satocsin(rt_getkey(rt))->sin_addr,
(u_char *)LLADDR(SDL(gate))); CLLADDR(satocsdl(gate)));
/*FALLTHROUGH*/ /*FALLTHROUGH*/
case RTM_RESOLVE: case RTM_RESOLVE:
if (gate->sa_family != AF_LINK || if (gate->sa_family != AF_LINK ||
@ -524,15 +544,15 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
break; break;
} }
SDL(gate)->sdl_type = rt->rt_ifp->if_type; satosdl(gate)->sdl_type = rt->rt_ifp->if_type;
SDL(gate)->sdl_index = rt->rt_ifp->if_index; satosdl(gate)->sdl_index = rt->rt_ifp->if_index;
if (la != 0) if (la != 0)
break; /* This happens on a route change */ break; /* This happens on a route change */
/* /*
* Case 2: This route may come from cloning, or a manual route * Case 2: This route may come from cloning, or a manual route
* add with a LL address. * add with a LL address.
*/ */
switch (SDL(gate)->sdl_type) { switch (satocsdl(gate)->sdl_type) {
#if NTOKEN > 0 #if NTOKEN > 0
case IFT_ISO88025: case IFT_ISO88025:
allocsize = sizeof(*la) + sizeof(struct token_rif); allocsize = sizeof(*la) + sizeof(struct token_rif);
@ -575,9 +595,9 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
* interface. * interface.
*/ */
rt->rt_expire = 0; rt->rt_expire = 0;
Bcopy(LLADDR(rt->rt_ifp->if_sadl), (void)sockaddr_dl_setaddr(satosdl(gate),
LLADDR(SDL(gate)), CLLADDR(rt->rt_ifp->if_sadl),
SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen); rt->rt_ifp->if_addrlen);
if (useloopback) if (useloopback)
rt->rt_ifp = lo0ifp; rt->rt_ifp = lo0ifp;
/* /*
@ -683,16 +703,13 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m,
const struct sockaddr *dst, u_char *desten) const struct sockaddr *dst, u_char *desten)
{ {
struct llinfo_arp *la; struct llinfo_arp *la;
struct sockaddr_dl *sdl; const struct sockaddr_dl *sdl;
struct mbuf *mold; struct mbuf *mold;
int s; int s;
if (rt) if ((la = arplookup1(m, &satocsin(dst)->sin_addr, 1, 0, rt)) != NULL)
la = (struct llinfo_arp *)rt->rt_llinfo; rt = la->la_rt;
else {
if ((la = arplookup(m, &satocsin(dst)->sin_addr, 1, 0)) != NULL)
rt = la->la_rt;
}
if (la == 0 || rt == 0) { if (la == 0 || rt == 0) {
arpstat.as_allocfail++; arpstat.as_allocfail++;
log(LOG_DEBUG, log(LOG_DEBUG,
@ -701,14 +718,14 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m,
m_freem(m); m_freem(m);
return (0); return (0);
} }
sdl = SDL(rt->rt_gateway); sdl = satocsdl(rt->rt_gateway);
/* /*
* Check the address family and length is valid, the address * Check the address family and length is valid, the address
* is resolved; otherwise, try to resolve. * is resolved; otherwise, try to resolve.
*/ */
if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && if ((rt->rt_expire == 0 || rt->rt_expire > time_second) &&
sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
bcopy(LLADDR(sdl), desten, bcopy(CLLADDR(sdl), desten,
min(sdl->sdl_alen, ifp->if_addrlen)); min(sdl->sdl_alen, ifp->if_addrlen));
rt->rt_pksent = time_second; /* Time for last pkt sent */ rt->rt_pksent = time_second; /* Time for last pkt sent */
return 1; return 1;
@ -970,8 +987,7 @@ in_arpinput(struct mbuf *m)
myaddr = ia->ia_addr.sin_addr; myaddr = ia->ia_addr.sin_addr;
/* XXX checks for bridge case? */ /* XXX checks for bridge case? */
if (!memcmp(ar_sha(ah), LLADDR(ifp->if_sadl), if (!memcmp(ar_sha(ah), CLLADDR(ifp->if_sadl), ifp->if_addrlen)) {
ifp->if_addrlen)) {
arpstat.as_rcvlocalsha++; arpstat.as_rcvlocalsha++;
goto out; /* it's from me, ignore it. */ goto out; /* it's from me, ignore it. */
} }
@ -994,9 +1010,9 @@ in_arpinput(struct mbuf *m)
goto reply; goto reply;
} }
la = arplookup(m, &isaddr, in_hosteq(itaddr, myaddr), 0); la = arplookup(m, &isaddr, in_hosteq(itaddr, myaddr), 0);
if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { if (la && (rt = la->la_rt) && (sdl = satosdl(rt->rt_gateway))) {
if (sdl->sdl_alen && if (sdl->sdl_alen &&
memcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) { memcmp(ar_sha(ah), CLLADDR(sdl), sdl->sdl_alen)) {
if (rt->rt_flags & RTF_STATIC) { if (rt->rt_flags & RTF_STATIC) {
arpstat.as_rcvoverperm++; arpstat.as_rcvoverperm++;
log(LOG_INFO, log(LOG_INFO,
@ -1069,7 +1085,7 @@ in_arpinput(struct mbuf *m)
} }
} }
#endif /* NTOKEN > 0 */ #endif /* NTOKEN > 0 */
memcpy(LLADDR(sdl), ar_sha(ah), sdl->sdl_alen = ah->ar_hln); (void)sockaddr_dl_setaddr(sdl, ar_sha(ah), ah->ar_hln);
if (rt->rt_expire) if (rt->rt_expire)
rt->rt_expire = time_second + arpt_keep; rt->rt_expire = time_second + arpt_keep;
rt->rt_flags &= ~RTF_REJECT; rt->rt_flags &= ~RTF_REJECT;
@ -1099,7 +1115,7 @@ reply:
tha = ar_tha(ah); tha = ar_tha(ah);
if (tha) if (tha)
memcpy(tha, ar_sha(ah), ah->ar_hln); memcpy(tha, ar_sha(ah), ah->ar_hln);
memcpy(ar_sha(ah), LLADDR(ifp->if_sadl), ah->ar_hln); memcpy(ar_sha(ah), CLLADDR(ifp->if_sadl), ah->ar_hln);
} else { } else {
la = arplookup(m, &itaddr, 0, SIN_PROXY); la = arplookup(m, &itaddr, 0, SIN_PROXY);
if (la == 0) if (la == 0)
@ -1111,8 +1127,8 @@ reply:
tha = ar_tha(ah); tha = ar_tha(ah);
if (tha) if (tha)
memcpy(tha, ar_sha(ah), ah->ar_hln); memcpy(tha, ar_sha(ah), ah->ar_hln);
sdl = SDL(rt->rt_gateway); sdl = satosdl(rt->rt_gateway);
memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln); memcpy(ar_sha(ah), CLLADDR(sdl), ah->ar_hln);
} }
memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
@ -1155,7 +1171,7 @@ static void arptfree(struct llinfo_arp *la)
if (rt == 0) if (rt == 0)
panic("arptfree"); panic("arptfree");
if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && if (rt->rt_refcnt > 0 && (sdl = satosdl(rt->rt_gateway)) &&
sdl->sdl_family == AF_LINK) { sdl->sdl_family == AF_LINK) {
sdl->sdl_alen = 0; sdl->sdl_alen = 0;
la->la_asked = 0; la->la_asked = 0;
@ -1165,11 +1181,18 @@ static void arptfree(struct llinfo_arp *la)
rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL);
} }
static struct llinfo_arp *
arplookup(struct mbuf *m, const struct in_addr *addr, int create, int proxy)
{
return arplookup1(m, addr, create, proxy, NULL);
}
/* /*
* Lookup or enter a new address in arptab. * Lookup or enter a new address in arptab.
*/ */
static struct llinfo_arp * static struct llinfo_arp *
arplookup(struct mbuf *m, const struct in_addr *addr, int create, int proxy) arplookup1(struct mbuf *m, const struct in_addr *addr, int create, int proxy,
struct rtentry *rt0)
{ {
struct arphdr *ah; struct arphdr *ah;
struct ifnet *ifp = m->m_pkthdr.rcvif; struct ifnet *ifp = m->m_pkthdr.rcvif;
@ -1178,21 +1201,26 @@ arplookup(struct mbuf *m, const struct in_addr *addr, int create, int proxy)
const char *why = 0; const char *why = 0;
ah = mtod(m, struct arphdr *); ah = mtod(m, struct arphdr *);
sin.sin_len = sizeof(sin); if (rt0 == NULL) {
sin.sin_family = AF_INET; sin.sin_len = sizeof(sin);
sin.sin_addr = *addr; sin.sin_family = AF_INET;
sin.sin_other = proxy ? SIN_PROXY : 0; sin.sin_addr = *addr;
rt = rtalloc1(sintosa(&sin), create); sin.sin_other = proxy ? SIN_PROXY : 0;
if (rt == 0) rt = rtalloc1(sintosa(&sin), create);
return (0); if (rt == NULL)
rt->rt_refcnt--; return (NULL);
rt->rt_refcnt--;
} else
rt = rt0;
if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) == RTF_LLINFO && #define IS_LLINFO(__rt) \
rt->rt_gateway->sa_family == AF_LINK) (((__rt)->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) == RTF_LLINFO && \
(__rt)->rt_gateway->sa_family == AF_LINK)
if (IS_LLINFO(rt))
return ((struct llinfo_arp *)rt->rt_llinfo); return ((struct llinfo_arp *)rt->rt_llinfo);
if (create) { if (create) {
if (rt->rt_flags & RTF_GATEWAY) if (rt->rt_flags & RTF_GATEWAY)
why = "host is not on local network"; why = "host is not on local network";
@ -1320,7 +1348,7 @@ in_revarpinput(struct mbuf *m)
goto wake; goto wake;
tha = ar_tha(ah); tha = ar_tha(ah);
KASSERT(tha); KASSERT(tha);
if (bcmp(tha, LLADDR(ifp->if_sadl), ifp->if_sadl->sdl_alen)) if (bcmp(tha, CLLADDR(ifp->if_sadl), ifp->if_sadl->sdl_alen))
goto out; goto out;
memcpy(&srv_ip, ar_spa(ah), sizeof(srv_ip)); memcpy(&srv_ip, ar_spa(ah), sizeof(srv_ip));
memcpy(&myip, ar_tpa(ah), sizeof(myip)); memcpy(&myip, ar_tpa(ah), sizeof(myip));
@ -1358,10 +1386,10 @@ revarprequest(struct ifnet *ifp)
ah->ar_pln = sizeof(struct in_addr); /* protocol address length */ ah->ar_pln = sizeof(struct in_addr); /* protocol address length */
ah->ar_op = htons(ARPOP_REVREQUEST); ah->ar_op = htons(ARPOP_REVREQUEST);
memcpy(ar_sha(ah), LLADDR(ifp->if_sadl), ah->ar_hln); memcpy(ar_sha(ah), CLLADDR(ifp->if_sadl), ah->ar_hln);
tha = ar_tha(ah); tha = ar_tha(ah);
KASSERT(tha); KASSERT(tha);
bcopy(LLADDR(ifp->if_sadl), tha, ah->ar_hln); bcopy(CLLADDR(ifp->if_sadl), tha, ah->ar_hln);
sa.sa_family = AF_ARP; sa.sa_family = AF_ARP;
sa.sa_len = 2; sa.sa_len = 2;