FreeBSD Bugzilla – Attachment 44337 Details for
Bug 68692
[net] [patch] Move ARP out of routing table
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
new_arp.patch
new_arp.patch (text/plain), 27.88 KB, created by
Sergey Matveychuk
on 2004-07-05 14:50:20 UTC
(
hide
)
Description:
new_arp.patch
Filename:
MIME Type:
Creator:
Sergey Matveychuk
Created:
2004-07-05 14:50:20 UTC
Size:
27.88 KB
patch
obsolete
>diff -ruN src.orig/sys/net/route.c src/sys/net/route.c >--- src.orig/sys/net/route.c Tue Jun 8 11:48:13 2004 >+++ src/sys/net/route.c Tue Jun 8 12:11:09 2004 >@@ -42,6 +42,7 @@ > #include <sys/kernel.h> > > #include <net/if.h> >+#include <net/if_dl.h> /* for sockaddr_dl */ > #include <net/route.h> > > #include <netinet/in.h> >@@ -1105,9 +1106,13 @@ > bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); > } > >+void arp_ifscrub(struct ifnet *ifp, uint32_t addr); >+ > /* > * Set up a routing table entry, normally > * for an interface. >+ * Instead of the destination address, use a sockaddr_dl for the >+ * gateway, using the index and type of the interface. > */ > int > rtinit(struct ifaddr *ifa, int cmd, int flags) >@@ -1118,6 +1123,7 @@ > struct rtentry *rt = NULL; > struct rt_addrinfo info; > int error; >+ static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; > > if (flags & RTF_HOST) { > dst = ifa->ifa_dstaddr; >@@ -1126,6 +1132,13 @@ > dst = ifa->ifa_addr; > netmask = ifa->ifa_netmask; > } >+ printf("rtinit cmd %d flags 0x%x, ifa_ifp %p dst %d:0x%x gw %d:0x%x\n", >+ cmd, flags, ifa->ifa_ifp, >+ dst->sa_family, >+ ntohl(((struct sockaddr_in *)dst)->sin_addr.s_addr), >+ ifa->ifa_addr->sa_family, >+ ntohl(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr)); >+ > /* > * If it's a delete, check that if it exists, it's on the correct > * interface or we might scrub a route to another ifa which would >@@ -1136,6 +1149,9 @@ > struct radix_node_head *rnh; > struct radix_node *rn; > >+ if (dst->sa_family == AF_INET) >+ arp_ifscrub(ifa->ifa_ifp, >+ ((struct sockaddr_in *)dst)->sin_addr.s_addr); > /* > * It's a delete, so it should already exist.. > * If it's a net, mask off the host bits >@@ -1175,10 +1191,14 @@ > info.rti_ifa = ifa; > info.rti_flags = flags | ifa->ifa_flags; > info.rti_info[RTAX_DST] = dst; >- info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; >+ info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; > info.rti_info[RTAX_NETMASK] = netmask; > error = rtrequest1(cmd, &info, &rt); > if (error == 0 && rt != NULL) { >+ ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = >+ rt->rt_ifp->if_type; >+ ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = >+ rt->rt_ifp->if_index; > /* > * notify any listening routing agents of the change > */ >diff -ruN src.orig/sys/net/rtsock.c src/sys/net/rtsock.c >--- src.orig/sys/net/rtsock.c Tue Jun 8 11:48:15 2004 >+++ src/sys/net/rtsock.c Tue Jun 8 12:11:09 2004 >@@ -93,6 +93,10 @@ > struct rt_metrics *out); > static void rt_dispatch(struct mbuf *, const struct sockaddr *); > >+/* support new arp code */ >+int arp_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info); >+int sysctl_dumparp(int af, struct sysctl_req *wr); >+ > /* > * It really doesn't make any sense at all for this code to share much > * with raw_usrreq.c, since its functionality is so restricted. XXX >@@ -277,6 +281,8 @@ > sosend, soreceive, sopoll, pru_sosetlabel_null > }; > >+ >+ > /*ARGSUSED*/ > static int > route_output(struct mbuf *m, struct socket *so) >@@ -353,6 +359,11 @@ > if (info.rti_info[RTAX_GATEWAY] == NULL) > senderr(EINVAL); > saved_nrt = NULL; >+ if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) { >+ /* support for new ARP code */ >+ arp_rt_output(rtm, &info); >+ break; >+ } > error = rtrequest1(RTM_ADD, &info, &saved_nrt); > if (error == 0 && saved_nrt) { > RT_LOCK(saved_nrt); >@@ -366,6 +377,11 @@ > > case RTM_DELETE: > saved_nrt = NULL; >+ if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) { >+ /* support for new ARP code */ >+ arp_rt_output(rtm, &info); >+ break; >+ } > error = rtrequest1(RTM_DELETE, &info, &saved_nrt); > if (error == 0) { > RT_LOCK(saved_nrt); >@@ -1081,6 +1097,7 @@ > int i, lim, s, error = EINVAL; > u_char af; > struct walkarg w; >+ int found = 0; > > name ++; > namelen--; >@@ -1112,8 +1129,17 @@ > error = rnh->rnh_walktree(rnh, > sysctl_dumpentry, &w);/* could sleep XXX */ > /* RADIX_NODE_HEAD_UNLOCK(rnh); */ >- } else if (af != 0) >- error = EAFNOSUPPORT; >+ if (error) >+ break; >+ found = 1; >+ } >+ /* >+ * take care of llinfo entries. XXX check AF_INET ? >+ */ >+ if (w.w_op == NET_RT_FLAGS && (RTF_LLINFO & w.w_arg)) >+ error = sysctl_dumparp(af, w.w_req); >+ else if (af != 0 && found == 0) >+ error = EAFNOSUPPORT; > break; > > case NET_RT_IFLIST: >diff -ruN src.orig/sys/netinet/if_ether.c src/sys/netinet/if_ether.c >--- src.orig/sys/netinet/if_ether.c Tue Jun 8 11:48:18 2004 >+++ src/sys/netinet/if_ether.c Tue Jun 8 12:20:44 2004 >@@ -27,7 +27,7 @@ > * SUCH DAMAGE. > * > * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 >- * $FreeBSD: src/sys/netinet/if_ether.c,v 1.127 2004/04/25 15:00:17 luigi Exp $ >+ * $FreeBSD$ > */ > > /* >@@ -101,7 +101,6 @@ > static LIST_HEAD(, llinfo_arp) llinfo_arp; > > static struct ifqueue arpintrq; >-static int arp_allocated; > > static int arp_maxtries = 5; > static int useloopback = 1; /* use loopback interface for local traffic */ >@@ -116,18 +115,303 @@ > &arp_proxyall, 0, ""); > > static void arp_init(void); >-static void arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *); > static void arprequest(struct ifnet *, > struct in_addr *, struct in_addr *, u_char *); > static void arpintr(struct mbuf *); > static void arptfree(struct llinfo_arp *); > static void arptimer(void *); >-static struct llinfo_arp >- *arplookup(u_long, int, int); >+struct llentry *arplookup(struct ifnet *ifp, uint32_t addr, uint32_t flags); > #ifdef INET > static void in_arpinput(struct mbuf *); > #endif > >+/*** >+ *** >+ *** Start of new arp support routines which should go to a separate file. >+ *** >+ ***/ >+#define DEB(x) >+#define DDB(x) x >+ >+struct llentry { >+ struct llentry *lle_next; >+ struct mbuf *la_hold; >+ uint16_t flags; /* see values in if_ether.h */ >+ uint8_t la_preempt; >+ uint8_t la_asked; >+ time_t expire; >+ struct in_addr l3_addr; >+ union { >+ uint64_t mac_aligned; >+ uint16_t mac16[3]; >+ } ll_addr; >+}; >+ >+MALLOC_DEFINE(M_ARP, "arp", "arp entries"); /* XXX will move to UMA */ >+ >+int arp_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info); >+int sysctl_dumparp(int af, struct sysctl_req *wr); >+void arp_ifscrub(struct ifnet *ifp, uint32_t addr); >+ >+/* >+ * called by in_ifscrub to remove entry from the table when >+ * the interface goes away >+ */ >+void >+arp_ifscrub(struct ifnet *ifp, uint32_t addr) >+{ >+ arplookup(ifp, addr, LLE_DELETE | LLE_IFADDR); >+} >+ >+/* >+ * Find an interface address matching the ifp-addr pair. >+ * This may replicate some of the functions of ifa_ifwithnet() >+ */ >+static struct ifaddr * >+find_ifa(struct ifnet *ifp, uint32_t addr) >+{ >+ struct ifaddr *ifa; >+ >+ if (ifp == NULL) >+ return NULL; >+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { >+ if (ifa->ifa_addr->sa_family != AF_INET) >+ continue; >+ if (ifp->if_flags & IFF_POINTOPOINT) >+ break; >+ if (((addr ^ SIN(ifa->ifa_addr)->sin_addr.s_addr) & >+ SIN(ifa->ifa_netmask)->sin_addr.s_addr ) == 0) >+ break; /* found! */ >+ } >+ return ifa; >+} >+ >+static void >+llentry_free(struct llentry **e) >+{ >+ struct llentry *x; >+ >+ if (e == 0) >+ panic("llentry_free: null ptr"); >+ x = *e; >+ *e = x->lle_next; >+ if (x->la_hold) >+ m_freem(x->la_hold); >+ free(x, M_ARP); >+} >+ >+/* >+ * Add a new table at the head of the list for interface ifp >+ */ >+struct lltable * >+lltable_new(struct ifnet *ifp, int af) >+{ >+ struct lltable *t; >+ >+ t = malloc(sizeof (struct lltable), M_ARP, M_DONTWAIT | M_ZERO); >+ if (t != NULL) { >+ t->llt_next = ifp->lltables; >+ t->llt_af = af; >+ ifp->lltables = t; >+ } >+ return t; >+} >+ >+struct lltable ** >+lltable_free(struct lltable **t) >+{ >+ struct lltable *x; >+ >+ if (t == NULL) >+ panic("lltable_free: null ptr"); >+ x = *t; >+ *t = x->llt_next; >+ free(x, M_ARP); >+ return t; >+} >+ >+static void >+newarptimer(__unused void *ignored_arg) >+{ >+ struct lltable *t; >+ struct llentry **e; >+ struct ifnet *ifp; >+ >+ IFNET_RLOCK(); >+ printf("arptimer!\n"); >+ TAILQ_FOREACH(ifp, &ifnet, if_link) { >+ for (t = ifp->lltables; t ; t = t->llt_next) { >+ if (t->llt_af != AF_INET) >+ continue; >+ for (e = (struct llentry **)&t->lle_head; *e; ) { >+ int kill; >+ >+ if ((*e)->flags & LLE_DELETED) >+ kill = 1; >+ else if ((*e)->flags & LLE_STATIC) >+ kill = 0; >+ else >+ kill = time_second >= (*e)->expire; >+ if (kill) >+ llentry_free(e); >+ else >+ e = &((*e)->lle_next); >+ } >+ } >+ } >+ IFNET_RUNLOCK(); >+ callout_reset(&arp_callout, arpt_prune * hz, newarptimer, NULL); >+} >+ >+static int >+inet_dumparp(struct ifnet *ifp, void *head, struct sysctl_req *wr) >+{ >+ struct llentry *e; >+ int error = 0; >+ >+ for (e = head; e; e = e->lle_next) { >+ struct { >+ struct rt_msghdr rtm; >+ struct sockaddr_inarp sin2; >+ struct sockaddr_dl sdl; >+ //struct sockaddr_inarp addr2; >+ } d; >+ >+ DEB(printf("ifp %p index %d flags 0x%x ip %x %s\n", >+ ifp, ifp->if_index, >+ e->flags, >+ ntohl(e->l3_addr.s_addr), >+ (e->flags & LLA_VALID) ? "valid" : "incomplete");) >+ if (e->flags & LLE_DELETED) /* skip deleted entries */ >+ continue; >+ /* >+ * produce a msg made of: >+ * struct rt_msghdr; >+ * struct sockaddr_inarp; >+ * struct sockaddr_dl; >+ */ >+ bzero(&d, sizeof (d)); >+ d.rtm.rtm_msglen = sizeof(d); >+ d.sin2.sin_family = AF_INET; >+ d.sin2.sin_len = sizeof(d.sin2); >+ d.sin2.sin_addr.s_addr = e->l3_addr.s_addr; >+ >+ if (e->flags & LLA_VALID) { /* valid MAC */ >+ d.sdl.sdl_family = AF_LINK; >+ d.sdl.sdl_len = sizeof(d.sdl); >+ d.sdl.sdl_alen = ifp->if_addrlen; >+ d.sdl.sdl_index = ifp->if_index; >+ d.sdl.sdl_type = ifp->if_type; >+ bcopy(&e->ll_addr, LLADDR(&d.sdl), ifp->if_addrlen); >+ } >+ d.rtm.rtm_rmx.rmx_expire = >+ e->flags & LLE_STATIC ? 0 : e->expire; >+ d.rtm.rtm_flags = RTF_LLINFO; >+ if (e->flags & LLE_STATIC) >+ d.rtm.rtm_flags |= RTF_STATIC; >+ d.rtm.rtm_index = ifp->if_index; >+ error = SYSCTL_OUT(wr, &d, sizeof(d)); >+ if (error) >+ break; >+ } >+ return error; >+} >+ >+/* >+ * glue to dump arp tables >+ */ >+int >+sysctl_dumparp(int af, struct sysctl_req *wr) >+{ >+ struct lltable *t; >+ struct ifnet *ifp; >+ int error = 0; >+ >+ IFNET_RLOCK(); >+ TAILQ_FOREACH(ifp, &ifnet, if_link) { >+ for (t = ifp->lltables; t ; t = t->llt_next) { >+ if (af != 0 && t->llt_af != af) >+ continue; >+ switch (af) { >+ case AF_INET: >+ error = inet_dumparp(ifp, t->lle_head, wr); >+ break; >+ /* other handlers, if any */ >+ } >+ if (error) >+ goto done; >+ } >+ } >+done: >+ IFNET_RUNLOCK(); >+ return (error); >+} >+ >+/* >+ * Called in route_output when adding/deleting a route to an interface. >+ */ >+int >+arp_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) >+{ >+ struct sockaddr_dl *dl = >+ (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; >+ struct sockaddr_in *dst = >+ (struct sockaddr_in *)info->rti_info[RTAX_DST]; >+ struct ifnet *ifp; >+ struct llentry *la; >+ u_int flags; >+ >+ printf("arp_rt_output type %d af: gw %d dst %d:%x if_index %d\n", >+ rtm->rtm_type, >+ dl ? dl->sdl_family : 0, >+ dst ? dst->sin_family : 0, >+ dst && dst->sin_family == AF_INET ? >+ ntohl(dst->sin_addr.s_addr) : 0, >+ dl ? dl->sdl_index : 0); >+ if (dl == NULL || dl->sdl_family != AF_LINK) { >+ /* XXX should also check (dl->sdl_index < if_indexlim) */ >+ printf("invalid gateway/index\n"); >+ return EINVAL; >+ } >+ ifp = ifnet_byindex(dl->sdl_index); >+ if (ifp == NULL) { >+ printf("invalid ifp\n"); >+ return EINVAL; >+ } >+ >+ switch (rtm->rtm_type) { >+ case RTM_ADD: >+ flags = LLE_CREATE; >+ break; >+ >+ case RTM_CHANGE: >+ default: >+ return EINVAL; /* XXX not implemented yet */ >+ >+ case RTM_DELETE: >+ flags = LLE_DELETE; >+ break; >+ } >+ la = arplookup(ifp, dst->sin_addr.s_addr, flags); >+ if (la == NULL) { >+ bcopy(LLADDR(dl), &la->ll_addr, ifp->if_addrlen); >+ la->flags |= LLA_VALID; >+ if (rtm->rtm_flags & RTF_STATIC) >+ la->flags |= LLE_STATIC; >+ else >+ la->expire = time_second + arpt_keep; >+ } >+ return 0; >+} >+ >+ >+ >+/*** >+ *** >+ *** End of new arp support routines which should go to a separate file. >+ *** >+ ***/ >+ > /* > * Timeout routine. Age arp_tab entries periodically. > */ >@@ -152,6 +436,9 @@ > callout_reset(&arp_callout, arpt_prune * hz, arptimer, NULL); > } > >+#if 0 /* this is unused */ >+static int arp_allocated; >+ > /* > * Parallel to llc_rtrequest. > */ >@@ -284,6 +571,7 @@ > Free((caddr_t)la); > } > } >+#endif /* arp_rtrequest unused */ > > /* > * Broadcast an ARP request. Caller specifies: >@@ -301,6 +589,28 @@ > struct arphdr *ah; > struct sockaddr sa; > >+ if (sip == NULL) { >+ /* >+ * The caller did not supply a source address, try to find >+ * a compatible one among those assigned to this interface. >+ */ >+ struct ifaddr *ifa; >+ >+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { >+ if (!ifa->ifa_addr || >+ ifa->ifa_addr->sa_family != AF_INET) >+ continue; >+ sip = &SIN(ifa->ifa_addr)->sin_addr; >+ if (0 == ((sip->s_addr ^ tip->s_addr) & >+ SIN(ifa->ifa_netmask)->sin_addr.s_addr) ) >+ break; /* found it. */ >+ } >+ } >+ if (sip == NULL) { >+ printf(" cannot find matching address, no arprequest\n"); >+ return; >+ } >+ > if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) > return; > m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + >@@ -344,16 +654,11 @@ > arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, > struct sockaddr *dst, u_char *desten) > { >- struct llinfo_arp *la = 0; >+ struct llentry *la = 0; > struct sockaddr_dl *sdl; >- int error; > struct rtentry *rt; >- >- error = rt_check(&rt, &rt0, dst); >- if (error) { >- m_freem(m); >- return error; >- } >+ u_int flags = (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) ? >+ 0 : LLE_CREATE; > > if (m->m_flags & M_BCAST) { /* broadcast */ > (void)memcpy(desten, ifp->if_broadcastaddr, ifp->if_addrlen); >@@ -363,51 +668,39 @@ > ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); > return (0); > } >- if (rt) >- la = (struct llinfo_arp *)rt->rt_llinfo; >- if (la == 0) { >- la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); >- if (la) >- rt = la->la_rt; >- } >- if (la == 0 || rt == 0) { >- log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n", >- inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "", >- rt ? "rt" : ""); >+ la = arplookup(ifp, SIN(dst)->sin_addr.s_addr, flags); >+ if (la == NULL) { >+ if (flags & LLE_CREATE) >+ log(LOG_DEBUG, >+ "arpresolve: can't allocate llinfo for %s\n", >+ inet_ntoa(SIN(dst)->sin_addr)); > m_freem(m); > return (EINVAL); /* XXX */ > } > sdl = SDL(rt->rt_gateway); > /* >- * Check the address family and length is valid, the address >- * is resolved; otherwise, try to resolve. >+ * If the entry is valid and not expired, use it. > */ >- if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && >- sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { >+ if (la->flags & LLA_VALID && >+ (la->flags & LLE_STATIC || la->expire > time_second)) { >+ bcopy(&la->ll_addr, desten, ifp->if_addrlen); > /* > * If entry has an expiry time and it is approaching, > * see if we need to send an ARP request within this > * arpt_down interval. > */ >- if ((rt->rt_expire != 0) && >- (time_second + la->la_preempt > rt->rt_expire)) { >- arprequest(ifp, >- &SIN(rt->rt_ifa->ifa_addr)->sin_addr, >- &SIN(dst)->sin_addr, >- IF_LLADDR(ifp)); >+ if (!(la->flags & LLE_STATIC) && >+ time_second + la->la_preempt > la->expire) { >+ arprequest(ifp, NULL, >+ &SIN(dst)->sin_addr, IF_LLADDR(ifp)); > la->la_preempt--; > } > >- bcopy(LLADDR(sdl), desten, sdl->sdl_alen); > return (0); > } >- /* >- * If ARP is disabled or static on this interface, stop. >- * XXX >- * Probably should not allocate empty llinfo struct if we are >- * not going to be sending out an arp request. >- */ >- if (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) { >+ if (la->flags & LLE_STATIC) { /* should not happen! */ >+ log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n", >+ inet_ntoa(SIN(dst)->sin_addr)); > m_freem(m); > return (EINVAL); > } >@@ -419,26 +712,26 @@ > if (la->la_hold) > m_freem(la->la_hold); > la->la_hold = m; >- if (rt->rt_expire) { >- RT_LOCK(rt); >- rt->rt_flags &= ~RTF_REJECT; >- if (la->la_asked == 0 || rt->rt_expire != time_second) { >- rt->rt_expire = time_second; >- if (la->la_asked++ < arp_maxtries) { >- arprequest(ifp, >- &SIN(rt->rt_ifa->ifa_addr)->sin_addr, >- &SIN(dst)->sin_addr, >- IF_LLADDR(ifp)); >- } else { >- rt->rt_flags |= RTF_REJECT; >- rt->rt_expire += arpt_down; >- la->la_asked = 0; >- la->la_preempt = arp_maxtries; >- } >- >+ /* >+ * Now implement the logic to issue requests -- we can send up >+ * to arp_maxtries with a 1-sec spacing, followed by a pause >+ * of arpt_down seconds if no replies are coming back. >+ * Take the chance to enforce limits on arp_maxtries and arpt_down >+ */ >+ if (la->expire <= time_second) { /* ok, expired */ >+ if (arp_maxtries > 100) /* enforce a sane limit */ >+ arp_maxtries = 100; >+ else if (arp_maxtries < 3) >+ arp_maxtries = 3; >+ if (la->la_asked++ < arp_maxtries) >+ la->expire = time_second + 1; >+ else { >+ la->la_asked = 0; >+ la->expire = time_second + arpt_down; >+ la->la_preempt = arp_maxtries; > } >- RT_UNLOCK(rt); >- } >+ arprequest(ifp, NULL, &SIN(dst)->sin_addr, IF_LLADDR(ifp)); >+ } > return (EWOULDBLOCK); > } > >@@ -518,16 +811,12 @@ > { > struct arphdr *ah; > struct ifnet *ifp = m->m_pkthdr.rcvif; >- struct iso88025_header *th = (struct iso88025_header *)0; >- struct iso88025_sockaddr_dl_data *trld; >- struct llinfo_arp *la = 0; >- struct rtentry *rt; >+ struct llentry *la = 0; > struct ifaddr *ifa; > struct in_ifaddr *ia; >- struct sockaddr_dl *sdl; > struct sockaddr sa; > struct in_addr isaddr, itaddr, myaddr; >- int op, rif_len; >+ int op; > int req_len; > > req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); >@@ -540,6 +829,19 @@ > op = ntohs(ah->ar_op); > (void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr)); > (void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr)); >+ /* >+ * sanity check for the address length. >+ * XXX this does not work for protocols with variable address >+ * length. -is >+ */ >+ if (ifp->if_addrlen != ah->ar_hln) { >+ log(LOG_WARNING, >+ "arp from %*D: addr len: new %d, i/f %d (ignored)", >+ ifp->if_addrlen, (u_char *) ar_sha(ah), ":", >+ ah->ar_hln, ifp->if_addrlen); >+ goto drop; >+ } >+ > #ifdef BRIDGE > #define BRIDGE_TEST (do_bridge) > #else >@@ -592,62 +894,41 @@ > } > if (ifp->if_flags & IFF_STATICARP) > goto reply; >- la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); >- if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { >- /* the following is not an error when doing bridging */ >- if (!BRIDGE_TEST && rt->rt_ifp != ifp) { >- if (log_arp_wrong_iface) >- log(LOG_ERR, "arp: %s is on %s but got reply from %*D on %s\n", >- inet_ntoa(isaddr), >- rt->rt_ifp->if_xname, >- ifp->if_addrlen, (u_char *)ar_sha(ah), ":", >- ifp->if_xname); >- goto reply; >- } >- if (sdl->sdl_alen && >- bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) { >- if (rt->rt_expire) { >- if (log_arp_movements) >- log(LOG_INFO, "arp: %s moved from %*D to %*D on %s\n", >- inet_ntoa(isaddr), >- ifp->if_addrlen, (u_char *)LLADDR(sdl), ":", >- ifp->if_addrlen, (u_char *)ar_sha(ah), ":", >- ifp->if_xname); >- } else { >+ /* Look up the source. If I am the target, create an entry for it. */ >+ la = arplookup(ifp, isaddr.s_addr, >+ (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0); >+ if (la != NULL) { >+ /* We have a valid entry. Check and store the MAC. */ >+ if (la->flags & LLA_VALID && >+ bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { >+ if (la->flags & LLE_STATIC) { > log(LOG_ERR, > "arp: %*D attempts to modify permanent entry for %s on %s\n", > ifp->if_addrlen, (u_char *)ar_sha(ah), ":", > inet_ntoa(isaddr), ifp->if_xname); > goto reply; > } >+ if (log_arp_movements) >+ log(LOG_INFO, "arp: %s moved from %*D to %*D on %s\n", >+ inet_ntoa(isaddr), >+ ifp->if_addrlen, (u_char *)&la->ll_addr, ":", >+ ifp->if_addrlen, (u_char *)ar_sha(ah), ":", >+ ifp->if_xname); > } >- /* >- * sanity check for the address length. >- * XXX this does not work for protocols with variable address >- * length. -is >- */ >- if (sdl->sdl_alen && >- sdl->sdl_alen != ah->ar_hln) { >- log(LOG_WARNING, >- "arp from %*D: new addr len %d, was %d", >- ifp->if_addrlen, (u_char *) ar_sha(ah), ":", >- ah->ar_hln, sdl->sdl_alen); >- } >- if (ifp->if_addrlen != ah->ar_hln) { >- log(LOG_WARNING, >- "arp from %*D: addr len: new %d, i/f %d (ignored)", >- ifp->if_addrlen, (u_char *) ar_sha(ah), ":", >- ah->ar_hln, ifp->if_addrlen); >- goto reply; >- } >- (void)memcpy(LLADDR(sdl), ar_sha(ah), >- sdl->sdl_alen = ah->ar_hln); >+ bcopy(ar_sha(ah), &la->ll_addr, ifp->if_addrlen); >+ la->flags |= LLA_VALID; >+#if 0 /* XXX this needs to be fixed */ > /* > * If we receive an arp from a token-ring station over > * a token-ring nic then try to save the source > * routing info. > */ > if (ifp->if_type == IFT_ISO88025) { >+ struct iso88025_header *th; >+ struct iso88025_sockaddr_dl_data *trld; >+ struct sockaddr_dl *sdl; >+ int rif_len; >+ > th = (struct iso88025_header *)m->m_pkthdr.header; > trld = SDL_ISO88025(sdl); > rif_len = TR_RCF_RIFLEN(th->rcf); >@@ -673,15 +954,20 @@ > m->m_pkthdr.len += 8; > th->rcf = trld->trld_rcf; > } >- RT_LOCK(rt); >- if (rt->rt_expire) >- rt->rt_expire = time_second + arpt_keep; >- rt->rt_flags &= ~RTF_REJECT; >- RT_UNLOCK(rt); >+#endif >+ if (!(la->flags & LLE_STATIC)) >+ la->expire = time_second + arpt_keep; > la->la_asked = 0; > la->la_preempt = arp_maxtries; > if (la->la_hold) { >- (*ifp->if_output)(ifp, la->la_hold, rt_key(rt), rt); >+ struct sockaddr_in sin; >+ >+ bzero(&sin, sizeof(sin)); >+ sin.sin_len = sizeof(struct sockaddr_in); >+ sin.sin_family = AF_INET; >+ sin.sin_addr.s_addr = la->l3_addr.s_addr; >+ ifp->if_output(ifp, la->la_hold, >+ (struct sockaddr *)&sin, NULL); > la->la_hold = 0; > } > } >@@ -693,9 +979,10 @@ > (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); > (void)memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln); > } else { >- la = arplookup(itaddr.s_addr, 0, SIN_PROXY); >+ la = arplookup(ifp, itaddr.s_addr, LLE_PROXY); > if (la == NULL) { > struct sockaddr_in sin; >+ struct rtentry *rt; > > if (!arp_proxyall) > goto drop; >@@ -747,10 +1034,8 @@ > inet_ntoa(itaddr)); > #endif > } else { >- rt = la->la_rt; > (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); >- sdl = SDL(rt->rt_gateway); >- (void)memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln); >+ (void)memcpy(ar_sha(ah), &la->ll_addr, ah->ar_hln); > } > } > >@@ -798,66 +1083,77 @@ > /* > * Lookup or enter a new address in arptab. > */ >-static struct llinfo_arp * >-arplookup(addr, create, proxy) >- u_long addr; >- int create, proxy; >+struct llentry * >+arplookup(struct ifnet *ifp, uint32_t l3addr, u_int flags) > { >- struct rtentry *rt; >- struct sockaddr_inarp sin; >- const char *why = 0; >- >- bzero(&sin, sizeof(sin)); >- sin.sin_len = sizeof(sin); >- sin.sin_family = AF_INET; >- sin.sin_addr.s_addr = addr; >- if (proxy) >- sin.sin_other = SIN_PROXY; >- rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); >- if (rt == 0) >- return (0); >- >- if (rt->rt_flags & RTF_GATEWAY) >- why = "host is not on local network"; >- else if ((rt->rt_flags & RTF_LLINFO) == 0) >- why = "could not allocate llinfo"; >- else if (rt->rt_gateway->sa_family != AF_LINK) >- why = "gateway route is not ours"; >- >- if (why) { >-#define ISDYNCLONE(_rt) \ >- (((_rt)->rt_flags & (RTF_STATIC | RTF_WASCLONED)) == RTF_WASCLONED) >- if (create) >- log(LOG_DEBUG, "arplookup %s failed: %s\n", >- inet_ntoa(sin.sin_addr), why); >- /* >- * If there are no references to this Layer 2 route, >- * and it is a cloned route, and not static, and >- * arplookup() is creating the route, then purge >- * it from the routing table as it is probably bogus. >- */ >- if (rt->rt_refcnt == 1 && ISDYNCLONE(rt)) >- rtexpunge(rt); >- RTFREE_LOCKED(rt); >- return (0); >-#undef ISDYNCLONE >- } else { >- RT_REMREF(rt); >- RT_UNLOCK(rt); >- return ((struct llinfo_arp *)rt->rt_llinfo); >- } >+ struct llentry *e; >+ struct lltable *t; >+ // uint proxy = flags & LLE_PROXY; >+ >+ if (ifp == NULL) >+ return NULL; >+ /* LOCK_IFNET */ >+ for (t = ifp->lltables; t && t->llt_af != AF_INET; t = t->llt_next) >+ ; >+ if (t == NULL && flags & LLE_CREATE) >+ t = lltable_new(ifp, AF_INET); >+ if (t == NULL) { >+ /* UNLOCK_ALL_TABLES */ >+ return NULL; /* failed! */ >+ } >+ /* LOCK_TABLE(t) */ >+ /* UNLOCK_ALL_TABLES */ >+ for (e = (struct llentry *)t->lle_head; e ; e = e->lle_next) { >+ if (e->flags & LLE_DELETED) >+ continue; >+ if (l3addr == e->l3_addr.s_addr) >+ break; >+ } >+ if (e == NULL) { /* entry not found */ >+ if (!(flags & LLE_CREATE)) >+ goto done; >+ if (find_ifa(ifp, l3addr) == NULL) { >+ printf("host is not on local network\n"); >+ goto done; >+ } >+ e = malloc(sizeof (struct llentry), M_ARP, M_DONTWAIT | M_ZERO); >+ if (e == NULL) { >+ printf("arp malloc failed\n"); >+ goto done; >+ } >+ e->expire = time_second; /* mark expired */ >+ e->l3_addr.s_addr = l3addr; >+ e->lle_next = t->lle_head; >+ t->lle_head = e; >+ } >+ if (flags & LLE_DELETE && >+ (e->flags & LLE_IFADDR) == (flags & LLE_IFADDR)) >+ e->flags = LLE_DELETED; >+done: >+ /* UNLOCK(t) */ >+ return e; > } > >+ > void > arp_ifinit(ifp, ifa) > struct ifnet *ifp; > struct ifaddr *ifa; > { >+ struct llentry *la; >+ >+ printf("arp_ifinit ifp %p addr 0x%x\n", >+ ifp, ntohl(IA_SIN(ifa)->sin_addr.s_addr)); >+ > if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) > arprequest(ifp, &IA_SIN(ifa)->sin_addr, > &IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); >- ifa->ifa_rtrequest = arp_rtrequest; >- ifa->ifa_flags |= RTF_CLONING; >+ la = arplookup(ifp, IA_SIN(ifa)->sin_addr.s_addr, LLE_CREATE); >+ if (la) { /* store our address */ >+ bcopy(IF_LLADDR(ifp), &la->ll_addr, ifp->if_addrlen); >+ la->flags |= LLA_VALID | LLE_STATIC | LLE_IFADDR; >+ } >+ ifa->ifa_rtrequest = NULL; > } > > static void >@@ -866,9 +1162,8 @@ > > arpintrq.ifq_maxlen = 50; > mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF); >- LIST_INIT(&llinfo_arp); > callout_init(&arp_callout, CALLOUT_MPSAFE); > netisr_register(NETISR_ARP, arpintr, &arpintrq, NETISR_MPSAFE); >- callout_reset(&arp_callout, hz, arptimer, NULL); >+ callout_reset(&arp_callout, hz, newarptimer, NULL); > } > SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); >diff -ruN src.orig/sys/netinet/if_ether.h src/sys/netinet/if_ether.h >--- src.orig/sys/netinet/if_ether.h Tue Jun 8 11:48:18 2004 >+++ src/sys/netinet/if_ether.h Tue Jun 8 12:11:09 2004 >@@ -112,6 +112,33 @@ > int arpresolve(struct ifnet *ifp, struct rtentry *rt, > struct mbuf *m, struct sockaddr *dst, u_char *desten); > void arp_ifinit(struct ifnet *, struct ifaddr *); >+ >+/* >+ * Support routines for the new arp table >+ */ >+struct lltable *lltable_new(struct ifnet *ifp, int af); >+struct lltable **lltable_free(struct lltable **t); > #endif > >+struct lltable { >+ struct lltable *llt_next; >+ void *lle_head; /* pointer to the list of address entries */ >+ int llt_af; /* address family */ >+}; >+ >+/* >+ * flags to be passed to arplookup. >+ */ >+#define LLE_DELETED 0x0001 /* entry must be deleted */ >+#define LLE_STATIC 0x0002 /* entry is static */ >+#define LLE_IFADDR 0x0004 /* entry is interface addr */ >+#define LLA_VALID 0x0008 /* ll_addr is valid */ >+#define LLE_PROXY 0x0010 /* proxy entry ??? */ >+#define LLE_PUB 0x0020 /* publish entry ??? */ >+#define LLE_CREATE 0x8000 /* create on a lookup miss */ >+#define LLE_DELETE 0x4000 /* delete on a lookup - match LLE_IFADDR */ >+ >+/* >+ * End of support code for the new arp table >+ */ > #endif >diff -ruN src.orig/usr.sbin/arp/arp.c src/usr.sbin/arp/arp.c >--- src.orig/usr.sbin/arp/arp.c Tue Jun 8 11:48:36 2004 >+++ src/usr.sbin/arp/arp.c Tue Jun 8 12:11:09 2004 >@@ -439,6 +439,17 @@ > !(rtm->rtm_flags & RTF_GATEWAY) && > valid_type(sdl->sdl_type) ) > break; /* found it */ >+ /* check the new arp interface */ >+ if (sdl->sdl_family == AF_LINK && >+ !(rtm->rtm_flags & RTF_GATEWAY) && >+ valid_type(sdl->sdl_type) ) { >+ /* >+ * found it. But overwrite the address to make >+ * sure that we really get it. >+ */ >+ addr->sin_addr.s_addr = dst->sin_addr.s_addr; >+ break; >+ } > if (dst->sin_other & SIN_PROXY) { > fprintf(stderr, "delete: cannot locate %s\n",host); > return (1);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 68692
: 44337