diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-05-18 08:05:52 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-05-18 08:05:52 +0000 |
commit | f1e7747c88752be2704c54e146eb5f7fe0c83954 (patch) | |
tree | b19194e928796a6da914b87665079fd2f4ecaf66 /sys | |
parent | cdcc4280b9419a2e074b969bcf05c5a0faaac1ab (diff) |
Move the code to update an ARP cache into its own function.
ok visa@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/if_ether.c | 221 |
1 files changed, 115 insertions, 106 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index c545ce81657..096a49822b8 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ether.c,v 1.205 2016/04/27 14:47:27 mpi Exp $ */ +/* $OpenBSD: if_ether.c,v 1.206 2016/05/18 08:05:51 mpi Exp $ */ /* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */ /* @@ -83,6 +83,7 @@ void arptimer(void *); struct rtentry *arplookup(u_int32_t, int, int, u_int); void in_arpinput(struct mbuf *); void in_revarpinput(struct mbuf *); +int arpcache(struct ifnet *, struct ether_arp *, struct rtentry *); LIST_HEAD(, llinfo_arp) arp_list; struct pool arp_pool; /* pool for llinfo_arp structures */ @@ -451,17 +452,14 @@ in_arpinput(struct mbuf *m) struct ether_arp *ea; struct ifnet *ifp; struct ether_header *eh; - struct llinfo_arp *la = NULL; struct rtentry *rt = NULL; - struct sockaddr_dl *sdl; struct sockaddr sa; struct sockaddr_in sin; struct in_addr isaddr, itaddr; - struct mbuf *mh; uint8_t enaddr[ETHER_ADDR_LEN]; char addr[INET_ADDRSTRLEN]; - int op, changed = 0, target = 0; - unsigned int len, rdomain; + int op, target = 0; + unsigned int rdomain; rdomain = rtable_l2(m->m_pkthdr.ph_rtableid); @@ -481,14 +479,12 @@ in_arpinput(struct mbuf *m) sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; - if (ETHER_IS_MULTICAST(&ea->arp_sha[0])) { - if (!memcmp(ea->arp_sha, etherbroadcastaddr, - sizeof (ea->arp_sha))) { - inet_ntop(AF_INET, &isaddr, addr, sizeof(addr)); - log(LOG_ERR, "arp: ether address is broadcast for " - "IP address %s!\n", addr); - goto out; - } + if (ETHER_IS_MULTICAST(&ea->arp_sha[0]) && + !memcmp(ea->arp_sha, etherbroadcastaddr, sizeof(ea->arp_sha))) { + inet_ntop(AF_INET, &isaddr, addr, sizeof(addr)); + log(LOG_ERR, "arp: ether address is broadcast for IP address " + "%s!\n", addr); + goto out; } memcpy(enaddr, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN); @@ -521,101 +517,13 @@ in_arpinput(struct mbuf *m) "duplicate IP address %s sent from ethernet address %s\n", addr, ether_sprintf(ea->arp_sha)); itaddr = isaddr; - } else if (rt != NULL && (sdl = satosdl(rt->rt_gateway)) != NULL) { - la = (struct llinfo_arp *)rt->rt_llinfo; - if (sdl->sdl_alen) { - if (memcmp(ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) { - if (rt->rt_flags & - (RTF_PERMANENT_ARP|RTF_LOCAL)) { - inet_ntop(AF_INET, &isaddr, addr, - sizeof(addr)); - log(LOG_WARNING, "arp: attempt to" - " overwrite permanent entry for %s" - " by %s on %s\n", addr, - ether_sprintf(ea->arp_sha), - ifp->if_xname); - goto out; - } else if (rt->rt_ifidx != ifp->if_index) { -#if NCARP > 0 - if (ifp->if_type != IFT_CARP) -#endif - { - struct ifnet *rifp = if_get( - rt->rt_ifidx); - if (rifp == NULL) - goto out; - inet_ntop(AF_INET, &isaddr, - addr, sizeof(addr)); - log(LOG_WARNING, "arp: attempt" - " to overwrite entry for" - " %s on %s by %s on %s\n", - addr, rifp->if_xname, - ether_sprintf(ea->arp_sha), - ifp->if_xname); - if_put(rifp); - } - goto out; - } else { - inet_ntop(AF_INET, &isaddr, addr, - sizeof(addr)); - log(LOG_INFO, "arp info overwritten for" - " %s by %s on %s\n", addr, - ether_sprintf(ea->arp_sha), - ifp->if_xname); - rt->rt_expire = 1;/* no longer static */ - } - changed = 1; - } - } else if (!if_isconnected(ifp, rt->rt_ifidx)) { - struct ifnet *rifp = if_get(rt->rt_ifidx); - if (rifp == NULL) - goto out; - inet_ntop(AF_INET, &isaddr, addr, sizeof(addr)); - log(LOG_WARNING, - "arp: attempt to add entry for %s " - "on %s by %s on %s\n", addr, - rifp->if_xname, - ether_sprintf(ea->arp_sha), - ifp->if_xname); - if_put(rifp); + } else if (rt != NULL) { + if (arpcache(ifp, ea, rt)) goto out; - } - sdl->sdl_alen = sizeof(ea->arp_sha); - memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); - if (rt->rt_expire) - rt->rt_expire = time_second + arpt_keep; - rt->rt_flags &= ~RTF_REJECT; - /* Notify userland that an ARP resolution has been done. */ - if (la->la_asked || changed) { - KERNEL_LOCK(); - rt_sendmsg(rt, RTM_RESOLVE, ifp->if_rdomain); - KERNEL_UNLOCK(); - } - la->la_asked = 0; - while ((len = ml_len(&la->la_ml)) != 0) { - mh = ml_dequeue(&la->la_ml); - la_hold_total--; - - ifp->if_output(ifp, mh, rt_key(rt), rt); - - if (ml_len(&la->la_ml) == len) { - /* mbuf is back in queue. Discard. */ - while ((mh = ml_dequeue(&la->la_ml)) != NULL) { - la_hold_total--; - m_freem(mh); - } - break; - } - } } - if (op != ARPOP_REQUEST) { -out: - rtfree(rt); - if_put(ifp); - m_freem(m); - return; - } + if (op != ARPOP_REQUEST) + goto out; rtfree(rt); if (target) { @@ -623,6 +531,8 @@ out: memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); memcpy(ea->arp_sha, LLADDR(ifp->if_sadl), sizeof(ea->arp_sha)); } else { + struct sockaddr_dl *sdl; + rt = arplookup(itaddr.s_addr, 0, SIN_PROXY, rdomain); if (rt == NULL) goto out; @@ -648,8 +558,107 @@ out: sa.sa_len = sizeof(sa); ifp->if_output(ifp, m, &sa, NULL); if_put(ifp); + return; + +out: + rtfree(rt); + if_put(ifp); + m_freem(m); } +int +arpcache(struct ifnet *ifp, struct ether_arp *ea, struct rtentry *rt) +{ + struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; + struct sockaddr_dl *sdl = satosdl(rt->rt_gateway); + struct in_addr *spa = (struct in_addr *)ea->arp_spa; + char addr[INET_ADDRSTRLEN]; + struct ifnet *rifp; + unsigned int len; + int changed = 0; + + KASSERT(sdl != NULL); + + if (sdl->sdl_alen > 0) { + if (memcmp(ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) { + if (ISSET(rt->rt_flags, RTF_PERMANENT_ARP|RTF_LOCAL)) { + inet_ntop(AF_INET, spa, addr, sizeof(addr)); + log(LOG_WARNING, "arp: attempt to overwrite " + "permanent entry for %s by %s on %s\n", addr, + ether_sprintf(ea->arp_sha), ifp->if_xname); + return (-1); + } else if (rt->rt_ifidx != ifp->if_index) { +#if NCARP > 0 + if (ifp->if_type != IFT_CARP) +#endif + { + rifp = if_get(rt->rt_ifidx); + if (rifp == NULL) + return (-1); + inet_ntop(AF_INET, spa, addr, + sizeof(addr)); + log(LOG_WARNING, "arp: attempt to " + "overwrite entry for %s on %s by " + "%s on %s\n", addr, rifp->if_xname, + ether_sprintf(ea->arp_sha), + ifp->if_xname); + if_put(rifp); + } + return (-1); + } else { + inet_ntop(AF_INET, spa, addr, sizeof(addr)); + log(LOG_INFO, "arp info overwritten for %s by " + "%s on %s\n", addr, + ether_sprintf(ea->arp_sha), ifp->if_xname); + rt->rt_expire = 1;/* no longer static */ + } + changed = 1; + } + } else if (!if_isconnected(ifp, rt->rt_ifidx)) { + rifp = if_get(rt->rt_ifidx); + if (rifp == NULL) + return (-1); + inet_ntop(AF_INET, spa, addr, sizeof(addr)); + log(LOG_WARNING, "arp: attempt to add entry for %s on %s by %s" + " on %s\n", addr, rifp->if_xname, + ether_sprintf(ea->arp_sha), ifp->if_xname); + if_put(rifp); + return (-1); + } + sdl->sdl_alen = sizeof(ea->arp_sha); + memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); + if (rt->rt_expire) + rt->rt_expire = time_second + arpt_keep; + rt->rt_flags &= ~RTF_REJECT; + + /* Notify userland that an ARP resolution has been done. */ + if (la->la_asked || changed) { + KERNEL_LOCK(); + rt_sendmsg(rt, RTM_RESOLVE, ifp->if_rdomain); + KERNEL_UNLOCK(); + } + + la->la_asked = 0; + while ((len = ml_len(&la->la_ml)) != 0) { + struct mbuf *mh; + + mh = ml_dequeue(&la->la_ml); + la_hold_total--; + + ifp->if_output(ifp, mh, rt_key(rt), rt); + + if (ml_len(&la->la_ml) == len) { + /* mbuf is back in queue. Discard. */ + while ((mh = ml_dequeue(&la->la_ml)) != NULL) { + la_hold_total--; + m_freem(mh); + } + break; + } + } + + return (0); +} /* * Free an arp entry. */ |