if_ether.c revision 163606
1139823Simp/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1988, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 291541Srgrimes * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 3050477Speter * $FreeBSD: head/sys/netinet/if_ether.c 163606 2006-10-22 11:52:19Z rwatson $ 311541Srgrimes */ 321541Srgrimes 331541Srgrimes/* 341541Srgrimes * Ethernet address resolution protocol. 351541Srgrimes * TODO: 361541Srgrimes * add "inuse/lock" bit (or ref. count) along with valid bit 371541Srgrimes */ 381541Srgrimes 3932350Seivind#include "opt_inet.h" 40101090Srwatson#include "opt_mac.h" 41142215Sglebius#include "opt_carp.h" 4232350Seivind 431541Srgrimes#include <sys/param.h> 4412693Sphk#include <sys/kernel.h> 4544078Sdfr#include <sys/queue.h> 4612693Sphk#include <sys/sysctl.h> 471541Srgrimes#include <sys/systm.h> 4812693Sphk#include <sys/mbuf.h> 491541Srgrimes#include <sys/malloc.h> 5018892Sbde#include <sys/socket.h> 511541Srgrimes#include <sys/syslog.h> 521541Srgrimes 531541Srgrimes#include <net/if.h> 541541Srgrimes#include <net/if_dl.h> 5544165Sjulian#include <net/if_types.h> 561541Srgrimes#include <net/route.h> 578426Swollman#include <net/netisr.h> 5858313Slile#include <net/if_llc.h> 5971963Sjulian#include <net/ethernet.h> 601541Srgrimes 611541Srgrimes#include <netinet/in.h> 621541Srgrimes#include <netinet/in_var.h> 631541Srgrimes#include <netinet/if_ether.h> 641541Srgrimes 6584931Sfjoe#include <net/if_arc.h> 6644627Sjulian#include <net/iso88025.h> 6744627Sjulian 68142215Sglebius#ifdef DEV_CARP 69142215Sglebius#include <netinet/ip_carp.h> 70142215Sglebius#endif 71142215Sglebius 72163606Srwatson#include <security/mac/mac_framework.h> 73163606Srwatson 741541Srgrimes#define SIN(s) ((struct sockaddr_in *)s) 751541Srgrimes#define SDL(s) ((struct sockaddr_dl *)s) 761541Srgrimes 7744078SdfrSYSCTL_DECL(_net_link_ether); 7812942SwollmanSYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); 791541Srgrimes 8012693Sphk/* timer values */ 8112942Swollmanstatic int arpt_prune = (5*60*1); /* walk list every 5 minutes */ 8212942Swollmanstatic int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ 831541Srgrimes 8412942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, 85153478Semaste &arpt_prune, 0, "ARP table prune interval in seconds"); 8612942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 87153478Semaste &arpt_keep, 0, "ARP entry lifetime in seconds"); 8812693Sphk 891541Srgrimes#define rt_expire rt_rmx.rmx_expire 901541Srgrimes 9111225Swollmanstruct llinfo_arp { 9260938Sjake LIST_ENTRY(llinfo_arp) la_le; 9311225Swollman struct rtentry *la_rt; 94110308Sorion struct mbuf *la_hold; /* last packet until resolved/timeout */ 95110544Sorion u_short la_preempt; /* countdown for pre-expiry arps */ 96152188Sglebius u_short la_asked; /* # requests sent */ 9711225Swollman}; 9812693Sphk 9960938Sjakestatic LIST_HEAD(, llinfo_arp) llinfo_arp; 10011225Swollman 101111888Sjlemonstatic struct ifqueue arpintrq; 102120727Ssamstatic int arp_allocated; 1031541Srgrimes 10412693Sphkstatic int arp_maxtries = 5; 10512942Swollmanstatic int useloopback = 1; /* use loopback interface for local traffic */ 10612942Swollmanstatic int arp_proxyall = 0; 107120727Ssamstatic struct callout arp_callout; 1083282Swollman 10912942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, 110153478Semaste &arp_maxtries, 0, "ARP resolution attempts before returning error"); 11112942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, 112153478Semaste &useloopback, 0, "Use the loopback interface for local traffic"); 11312942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, 114153478Semaste &arp_proxyall, 0, "Enable proxy ARP for all suitable requests"); 11512693Sphk 11692723Salfredstatic void arp_init(void); 11792723Salfredstatic void arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *); 11892723Salfredstatic void arprequest(struct ifnet *, 11992723Salfred struct in_addr *, struct in_addr *, u_char *); 120111888Sjlemonstatic void arpintr(struct mbuf *); 12192723Salfredstatic void arptimer(void *); 122148955Sglebiusstatic struct rtentry 12392723Salfred *arplookup(u_long, int, int); 12432350Seivind#ifdef INET 12592723Salfredstatic void in_arpinput(struct mbuf *); 12632350Seivind#endif 12712693Sphk 1281541Srgrimes/* 1291541Srgrimes * Timeout routine. Age arp_tab entries periodically. 1301541Srgrimes */ 1311541Srgrimes/* ARGSUSED */ 1321541Srgrimesstatic void 133148955Sglebiusarptimer(void * __unused unused) 1341541Srgrimes{ 135109409Shsu struct llinfo_arp *la, *ola; 1361541Srgrimes 137109996Shsu RADIX_NODE_HEAD_LOCK(rt_tables[AF_INET]); 138148955Sglebius LIST_FOREACH_SAFE(la, &llinfo_arp, la_le, ola) { 139109409Shsu struct rtentry *rt = la->la_rt; 140148955Sglebius 141148955Sglebius RT_LOCK(rt); 142150351Sandre if (rt->rt_expire && rt->rt_expire <= time_uptime) { 143148955Sglebius struct sockaddr_dl *sdl = SDL(rt->rt_gateway); 144148955Sglebius 145148955Sglebius KASSERT(sdl->sdl_family == AF_LINK, ("sdl_family %d", 146148955Sglebius sdl->sdl_family)); 147148955Sglebius if (rt->rt_refcnt > 1) { 148148955Sglebius sdl->sdl_alen = 0; 149148955Sglebius la->la_preempt = la->la_asked = 0; 150148955Sglebius RT_UNLOCK(rt); 151148955Sglebius continue; 152148955Sglebius } 153148955Sglebius RT_UNLOCK(rt); 154148955Sglebius /* 155148955Sglebius * XXX: LIST_REMOVE() is deep inside rtrequest(). 156148955Sglebius */ 157148955Sglebius rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, 158148955Sglebius NULL); 159148955Sglebius continue; 160148955Sglebius } 161148955Sglebius RT_UNLOCK(rt); 1621541Srgrimes } 163109996Shsu RADIX_NODE_HEAD_UNLOCK(rt_tables[AF_INET]); 164120727Ssam 165120727Ssam callout_reset(&arp_callout, arpt_prune * hz, arptimer, NULL); 1661541Srgrimes} 1671541Srgrimes 1681541Srgrimes/* 1691541Srgrimes * Parallel to llc_rtrequest. 1701541Srgrimes */ 1715196Swollmanstatic void 17285074Sruarp_rtrequest(req, rt, info) 1731541Srgrimes int req; 174126936Smdodd struct rtentry *rt; 17585074Sru struct rt_addrinfo *info; 1761541Srgrimes{ 177126936Smdodd struct sockaddr *gate; 178126936Smdodd struct llinfo_arp *la; 1791541Srgrimes static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 180138615Smlaier struct in_ifaddr *ia; 181138615Smlaier struct ifaddr *ifa; 1821541Srgrimes 183120727Ssam RT_LOCK_ASSERT(rt); 184120727Ssam 1851541Srgrimes if (rt->rt_flags & RTF_GATEWAY) 1861541Srgrimes return; 187120727Ssam gate = rt->rt_gateway; 188120727Ssam la = (struct llinfo_arp *)rt->rt_llinfo; 1891541Srgrimes switch (req) { 1901541Srgrimes 1911541Srgrimes case RTM_ADD: 1921541Srgrimes /* 1931541Srgrimes * XXX: If this is a manually added route to interface 1941541Srgrimes * such as older version of routed or gated might provide, 1951541Srgrimes * restore cloning bit. 1961541Srgrimes */ 1971541Srgrimes if ((rt->rt_flags & RTF_HOST) == 0 && 198136960Sbms rt_mask(rt) != NULL && 1991541Srgrimes SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 2001541Srgrimes rt->rt_flags |= RTF_CLONING; 2011541Srgrimes if (rt->rt_flags & RTF_CLONING) { 2021541Srgrimes /* 2031541Srgrimes * Case 1: This route should come from a route to iface. 2041541Srgrimes */ 2051541Srgrimes rt_setgate(rt, rt_key(rt), 2061541Srgrimes (struct sockaddr *)&null_sdl); 2071541Srgrimes gate = rt->rt_gateway; 2081541Srgrimes SDL(gate)->sdl_type = rt->rt_ifp->if_type; 2091541Srgrimes SDL(gate)->sdl_index = rt->rt_ifp->if_index; 210150351Sandre rt->rt_expire = time_uptime; 2111541Srgrimes break; 2121541Srgrimes } 2131541Srgrimes /* Announce a new entry if requested. */ 2141541Srgrimes if (rt->rt_flags & RTF_ANNOUNCE) 21584931Sfjoe arprequest(rt->rt_ifp, 21636908Sjulian &SIN(rt_key(rt))->sin_addr, 21736908Sjulian &SIN(rt_key(rt))->sin_addr, 2181541Srgrimes (u_char *)LLADDR(SDL(gate))); 2191541Srgrimes /*FALLTHROUGH*/ 2201541Srgrimes case RTM_RESOLVE: 2211541Srgrimes if (gate->sa_family != AF_LINK || 2221541Srgrimes gate->sa_len < sizeof(null_sdl)) { 223120727Ssam log(LOG_DEBUG, "%s: bad gateway %s%s\n", __func__, 224120698Sbms inet_ntoa(SIN(rt_key(rt))->sin_addr), 225120698Sbms (gate->sa_family != AF_LINK) ? 226120699Sbms " (!AF_LINK)": ""); 2271541Srgrimes break; 2281541Srgrimes } 2291541Srgrimes SDL(gate)->sdl_type = rt->rt_ifp->if_type; 2301541Srgrimes SDL(gate)->sdl_index = rt->rt_ifp->if_index; 2311541Srgrimes if (la != 0) 2321541Srgrimes break; /* This happens on a route change */ 2331541Srgrimes /* 2341541Srgrimes * Case 2: This route may come from cloning, or a manual route 2351541Srgrimes * add with a LL address. 2361541Srgrimes */ 237120727Ssam R_Zalloc(la, struct llinfo_arp *, sizeof(*la)); 2381541Srgrimes rt->rt_llinfo = (caddr_t)la; 2391541Srgrimes if (la == 0) { 240120727Ssam log(LOG_DEBUG, "%s: malloc failed\n", __func__); 2411541Srgrimes break; 2421541Srgrimes } 243120727Ssam arp_allocated++; 244148955Sglebius /* 245148955Sglebius * We are storing a route entry outside of radix tree. So, 246148955Sglebius * it can be found and accessed by other means than radix 247148955Sglebius * lookup. The routing code assumes that any rtentry detached 248148955Sglebius * from radix can be destroyed safely. To prevent this, we 249148955Sglebius * add an additional reference. 250148955Sglebius */ 251148955Sglebius RT_ADDREF(rt); 2521541Srgrimes la->la_rt = rt; 2531541Srgrimes rt->rt_flags |= RTF_LLINFO; 254109996Shsu RADIX_NODE_HEAD_LOCK_ASSERT(rt_tables[AF_INET]); 25511225Swollman LIST_INSERT_HEAD(&llinfo_arp, la, la_le); 25613926Swollman 25732350Seivind#ifdef INET 25813926Swollman /* 25913926Swollman * This keeps the multicast addresses from showing up 26013926Swollman * in `arp -a' listings as unresolved. It's not actually 26113926Swollman * functional. Then the same for broadcast. 26213926Swollman */ 26387776Sjlemon if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr)) && 26487776Sjlemon rt->rt_ifp->if_type != IFT_ARCNET) { 26513926Swollman ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr, 26613926Swollman LLADDR(SDL(gate))); 26713926Swollman SDL(gate)->sdl_alen = 6; 26816576Speter rt->rt_expire = 0; 26913926Swollman } 27013926Swollman if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { 27184931Sfjoe memcpy(LLADDR(SDL(gate)), rt->rt_ifp->if_broadcastaddr, 27284931Sfjoe rt->rt_ifp->if_addrlen); 27384931Sfjoe SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen; 27416576Speter rt->rt_expire = 0; 27513926Swollman } 27632350Seivind#endif 27713926Swollman 278138615Smlaier TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 279138615Smlaier if (ia->ia_ifp == rt->rt_ifp && 280138615Smlaier SIN(rt_key(rt))->sin_addr.s_addr == 281138615Smlaier (IA_SIN(ia))->sin_addr.s_addr) 282138615Smlaier break; 283138615Smlaier } 284138615Smlaier if (ia) { 2851541Srgrimes /* 2861541Srgrimes * This test used to be 2871541Srgrimes * if (loif.if_flags & IFF_UP) 2881541Srgrimes * It allowed local traffic to be forced 2891541Srgrimes * through the hardware by configuring the loopback down. 2901541Srgrimes * However, it causes problems during network configuration 2911541Srgrimes * for boards that can't receive packets they send. 2921541Srgrimes * It is now necessary to clear "useloopback" and remove 2931541Srgrimes * the route to force traffic out to the hardware. 2941541Srgrimes */ 2951541Srgrimes rt->rt_expire = 0; 296128398Sluigi bcopy(IF_LLADDR(rt->rt_ifp), LLADDR(SDL(gate)), 29784931Sfjoe SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen); 298162586Sjmg if (useloopback) { 2998090Spst rt->rt_ifp = loif; 300162586Sjmg rt->rt_rmx.rmx_mtu = loif->if_mtu; 301162586Sjmg } 3021541Srgrimes 303138615Smlaier /* 304138615Smlaier * make sure to set rt->rt_ifa to the interface 305138615Smlaier * address we are using, otherwise we will have trouble 306138615Smlaier * with source address selection. 307138615Smlaier */ 308138615Smlaier ifa = &ia->ia_ifa; 309138615Smlaier if (ifa != rt->rt_ifa) { 310138615Smlaier IFAFREE(rt->rt_ifa); 311138615Smlaier IFAREF(ifa); 312138615Smlaier rt->rt_ifa = ifa; 313138615Smlaier } 3141541Srgrimes } 3151541Srgrimes break; 3161541Srgrimes 3171541Srgrimes case RTM_DELETE: 3181541Srgrimes if (la == 0) 3191541Srgrimes break; 320109996Shsu RADIX_NODE_HEAD_LOCK_ASSERT(rt_tables[AF_INET]); 32111225Swollman LIST_REMOVE(la, la_le); 322148955Sglebius RT_REMREF(rt); 3231541Srgrimes rt->rt_llinfo = 0; 3241541Srgrimes rt->rt_flags &= ~RTF_LLINFO; 3251541Srgrimes if (la->la_hold) 3261541Srgrimes m_freem(la->la_hold); 3271541Srgrimes Free((caddr_t)la); 3281541Srgrimes } 3291541Srgrimes} 3301541Srgrimes 3311541Srgrimes/* 3321541Srgrimes * Broadcast an ARP request. Caller specifies: 3331541Srgrimes * - arp header source ip address 3341541Srgrimes * - arp header target ip address 3351541Srgrimes * - arp header source ethernet address 3361541Srgrimes */ 3371541Srgrimesstatic void 33884931Sfjoearprequest(ifp, sip, tip, enaddr) 339126936Smdodd struct ifnet *ifp; 340126936Smdodd struct in_addr *sip, *tip; 341126936Smdodd u_char *enaddr; 3421541Srgrimes{ 343126936Smdodd struct mbuf *m; 344126936Smdodd struct arphdr *ah; 3451541Srgrimes struct sockaddr sa; 3461541Srgrimes 347111119Simp if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 3481541Srgrimes return; 349127261Smdodd m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + 350127261Smdodd 2*ifp->if_data.ifi_addrlen; 351127277Smdodd m->m_pkthdr.len = m->m_len; 352127277Smdodd MH_ALIGN(m, m->m_len); 353127277Smdodd ah = mtod(m, struct arphdr *); 354127261Smdodd bzero((caddr_t)ah, m->m_len); 355101090Srwatson#ifdef MAC 356101090Srwatson mac_create_mbuf_linklayer(ifp, m); 357101090Srwatson#endif 35884931Sfjoe ah->ar_pro = htons(ETHERTYPE_IP); 35984931Sfjoe ah->ar_hln = ifp->if_addrlen; /* hardware address length */ 36084931Sfjoe ah->ar_pln = sizeof(struct in_addr); /* protocol address length */ 36184931Sfjoe ah->ar_op = htons(ARPOP_REQUEST); 362127261Smdodd bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln); 363127261Smdodd bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln); 364127261Smdodd bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln); 365127261Smdodd sa.sa_family = AF_ARP; 366127261Smdodd sa.sa_len = 2; 367127261Smdodd m->m_flags |= M_BCAST; 368127261Smdodd (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0); 36984931Sfjoe 370127261Smdodd return; 3711541Srgrimes} 3721541Srgrimes 3731541Srgrimes/* 374128636Sluigi * Resolve an IP address into an ethernet address. 375128636Sluigi * On input: 376128636Sluigi * ifp is the interface we use 377128636Sluigi * dst is the next hop, 378128636Sluigi * rt0 is the route to the final destination (possibly useless) 379128636Sluigi * m is the mbuf 380128636Sluigi * desten is where we want the address. 381128636Sluigi * 382128636Sluigi * On success, desten is filled in and the function returns 0; 383128636Sluigi * If the packet must be held pending resolution, we return EWOULDBLOCK 384128636Sluigi * On other errors, we return the corresponding error code. 3851541Srgrimes */ 3861541Srgrimesint 387128636Sluigiarpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, 388127828Sluigi struct sockaddr *dst, u_char *desten) 3891541Srgrimes{ 390148955Sglebius struct llinfo_arp *la = NULL; 391148955Sglebius struct rtentry *rt = NULL; 3921541Srgrimes struct sockaddr_dl *sdl; 393128636Sluigi int error; 3941541Srgrimes 3951541Srgrimes if (m->m_flags & M_BCAST) { /* broadcast */ 39684931Sfjoe (void)memcpy(desten, ifp->if_broadcastaddr, ifp->if_addrlen); 397128636Sluigi return (0); 3981541Srgrimes } 39984931Sfjoe if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) {/* multicast */ 4001541Srgrimes ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); 401128636Sluigi return (0); 4021541Srgrimes } 403148955Sglebius 404148955Sglebius if (rt0 != NULL) { 405148955Sglebius error = rt_check(&rt, &rt0, dst); 406148955Sglebius if (error) { 407148955Sglebius m_freem(m); 408148955Sglebius return error; 409148955Sglebius } 4101541Srgrimes la = (struct llinfo_arp *)rt->rt_llinfo; 411148955Sglebius if (la == NULL) 412148955Sglebius RT_UNLOCK(rt); 4131541Srgrimes } 414148955Sglebius if (la == NULL) { 415148955Sglebius /* 416148955Sglebius * We enter this block in case if rt0 was NULL, 417148955Sglebius * or if rt found by rt_check() didn't have llinfo. 418148955Sglebius */ 419148955Sglebius rt = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); 420148955Sglebius if (rt == NULL) { 421148955Sglebius log(LOG_DEBUG, 422148955Sglebius "arpresolve: can't allocate route for %s\n", 423148955Sglebius inet_ntoa(SIN(dst)->sin_addr)); 424148955Sglebius m_freem(m); 425148955Sglebius return (EINVAL); /* XXX */ 426148955Sglebius } 427148955Sglebius la = (struct llinfo_arp *)rt->rt_llinfo; 428148955Sglebius if (la == NULL) { 429148955Sglebius RT_UNLOCK(rt); 430148955Sglebius log(LOG_DEBUG, 431148955Sglebius "arpresolve: can't allocate llinfo for %s\n", 432148955Sglebius inet_ntoa(SIN(dst)->sin_addr)); 433148955Sglebius m_freem(m); 434148955Sglebius return (EINVAL); /* XXX */ 435148955Sglebius } 4361541Srgrimes } 4371541Srgrimes sdl = SDL(rt->rt_gateway); 4381541Srgrimes /* 4391541Srgrimes * Check the address family and length is valid, the address 4401541Srgrimes * is resolved; otherwise, try to resolve. 4411541Srgrimes */ 442150351Sandre if ((rt->rt_expire == 0 || rt->rt_expire > time_uptime) && 4431541Srgrimes sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { 444149909Sglebius 445149909Sglebius bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 446149909Sglebius 44792802Sorion /* 44892802Sorion * If entry has an expiry time and it is approaching, 449152188Sglebius * send an ARP request. 45092802Sorion */ 45192802Sorion if ((rt->rt_expire != 0) && 452150351Sandre (time_uptime + la->la_preempt > rt->rt_expire)) { 453149909Sglebius struct in_addr sin = 454149909Sglebius SIN(rt->rt_ifa->ifa_addr)->sin_addr; 455149909Sglebius 456110544Sorion la->la_preempt--; 457149909Sglebius RT_UNLOCK(rt); 458149909Sglebius arprequest(ifp, &sin, &SIN(dst)->sin_addr, 459149909Sglebius IF_LLADDR(ifp)); 460149909Sglebius return (0); 46192802Sorion } 46292802Sorion 463148955Sglebius RT_UNLOCK(rt); 464128636Sluigi return (0); 4651541Srgrimes } 4661541Srgrimes /* 467120626Sru * If ARP is disabled or static on this interface, stop. 46878295Sjlemon * XXX 46978295Sjlemon * Probably should not allocate empty llinfo struct if we are 47078295Sjlemon * not going to be sending out an arp request. 47178295Sjlemon */ 472120626Sru if (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) { 473148955Sglebius RT_UNLOCK(rt); 47487410Sru m_freem(m); 475128636Sluigi return (EINVAL); 47687410Sru } 47778295Sjlemon /* 4781541Srgrimes * There is an arptab entry, but no ethernet address 4791541Srgrimes * response yet. Replace the held mbuf with this 4801541Srgrimes * latest one. 4811541Srgrimes */ 4821541Srgrimes if (la->la_hold) 4831541Srgrimes m_freem(la->la_hold); 4841541Srgrimes la->la_hold = m; 485149909Sglebius 486152188Sglebius KASSERT(rt->rt_expire > 0, ("sending ARP request for static entry")); 4871541Srgrimes 488152188Sglebius /* 489152188Sglebius * Return EWOULDBLOCK if we have tried less than arp_maxtries. It 490152188Sglebius * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH 491152188Sglebius * if we have already sent arp_maxtries ARP requests. Retransmit the 492152188Sglebius * ARP request, but not faster than one request per second. 493152188Sglebius */ 494152188Sglebius if (la->la_asked < arp_maxtries) 495152188Sglebius error = EWOULDBLOCK; /* First request. */ 496152188Sglebius else 497152188Sglebius error = (rt == rt0) ? EHOSTDOWN : EHOSTUNREACH; 498152188Sglebius 499152188Sglebius if (la->la_asked++ == 0 || rt->rt_expire != time_uptime) { 500152188Sglebius struct in_addr sin = 501152188Sglebius SIN(rt->rt_ifa->ifa_addr)->sin_addr; 502152188Sglebius 503152188Sglebius rt->rt_expire = time_uptime; 504152188Sglebius RT_UNLOCK(rt); 505152188Sglebius 506152188Sglebius arprequest(ifp, &sin, &SIN(dst)->sin_addr, 507152188Sglebius IF_LLADDR(ifp)); 508152188Sglebius } else 509152188Sglebius RT_UNLOCK(rt); 510152188Sglebius 511152188Sglebius return (error); 5121541Srgrimes} 5131541Srgrimes 5141541Srgrimes/* 5151541Srgrimes * Common length and type checks are done here, 5161541Srgrimes * then the protocol-specific routine is called. 5171541Srgrimes */ 51812693Sphkstatic void 519111888Sjlemonarpintr(struct mbuf *m) 5201541Srgrimes{ 521111888Sjlemon struct arphdr *ar; 5221541Srgrimes 523111888Sjlemon if (m->m_len < sizeof(struct arphdr) && 524111888Sjlemon ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) { 525111888Sjlemon log(LOG_ERR, "arp: runt packet -- m_pullup failed\n"); 526111888Sjlemon return; 527111888Sjlemon } 528111888Sjlemon ar = mtod(m, struct arphdr *); 5291541Srgrimes 530111888Sjlemon if (ntohs(ar->ar_hrd) != ARPHRD_ETHER && 531111888Sjlemon ntohs(ar->ar_hrd) != ARPHRD_IEEE802 && 532130407Sdfr ntohs(ar->ar_hrd) != ARPHRD_ARCNET && 533130407Sdfr ntohs(ar->ar_hrd) != ARPHRD_IEEE1394) { 534111888Sjlemon log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n", 535111888Sjlemon (unsigned char *)&ar->ar_hrd, ""); 536111888Sjlemon m_freem(m); 537111888Sjlemon return; 538111888Sjlemon } 5391541Srgrimes 540123768Sru if (m->m_len < arphdr_len(ar)) { 541123765Sru if ((m = m_pullup(m, arphdr_len(ar))) == NULL) { 542123765Sru log(LOG_ERR, "arp: runt packet\n"); 543123765Sru m_freem(m); 544123765Sru return; 545123765Sru } 546123765Sru ar = mtod(m, struct arphdr *); 547111888Sjlemon } 54857900Srwatson 549111888Sjlemon switch (ntohs(ar->ar_pro)) { 55032350Seivind#ifdef INET 551111888Sjlemon case ETHERTYPE_IP: 552111888Sjlemon in_arpinput(m); 553111888Sjlemon return; 55432350Seivind#endif 5551541Srgrimes } 556111888Sjlemon m_freem(m); 5571541Srgrimes} 5581541Srgrimes 55932350Seivind#ifdef INET 5601541Srgrimes/* 5611541Srgrimes * ARP for Internet protocols on 10 Mb/s Ethernet. 5621541Srgrimes * Algorithm is that given in RFC 826. 5631541Srgrimes * In addition, a sanity check is performed on the sender 5641541Srgrimes * protocol address, to catch impersonators. 5651541Srgrimes * We no longer handle negotiations for use of trailer protocol: 5661541Srgrimes * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent 5671541Srgrimes * along with IP replies if we wanted trailers sent to us, 5681541Srgrimes * and also sent them in response to IP replies. 5691541Srgrimes * This allowed either end to announce the desire to receive 5701541Srgrimes * trailer packets. 5711541Srgrimes * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, 5721541Srgrimes * but formerly didn't normally send requests. 5731541Srgrimes */ 57470699Salfredstatic int log_arp_wrong_iface = 1; 57582893Salfredstatic int log_arp_movements = 1; 576153513Sglebiusstatic int log_arp_permanent_modify = 1; 57770699Salfred 57870699SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW, 57970699Salfred &log_arp_wrong_iface, 0, 58070699Salfred "log arp packets arriving on the wrong interface"); 58182893SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_movements, CTLFLAG_RW, 58282893Salfred &log_arp_movements, 0, 58382966Salfred "log arp replies from MACs different than the one in the cache"); 584153513SglebiusSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_permanent_modify, CTLFLAG_RW, 585153513Sglebius &log_arp_permanent_modify, 0, 586153513Sglebius "log arp replies from MACs different than the one in the permanent arp entry"); 58770699Salfred 58882893Salfred 5891541Srgrimesstatic void 5901541Srgrimesin_arpinput(m) 5911541Srgrimes struct mbuf *m; 5921541Srgrimes{ 593126936Smdodd struct arphdr *ah; 594126936Smdodd struct ifnet *ifp = m->m_pkthdr.rcvif; 595148955Sglebius struct llinfo_arp *la; 596126936Smdodd struct rtentry *rt; 59784102Sjlemon struct ifaddr *ifa; 59884102Sjlemon struct in_ifaddr *ia; 5991541Srgrimes struct sockaddr_dl *sdl; 6001541Srgrimes struct sockaddr sa; 6011541Srgrimes struct in_addr isaddr, itaddr, myaddr; 602148955Sglebius struct mbuf *hold; 603142215Sglebius u_int8_t *enaddr = NULL; 60458313Slile int op, rif_len; 60584931Sfjoe int req_len; 606146986Sthompsa int bridged = 0; 607143491Sglebius#ifdef DEV_CARP 608143314Sglebius int carp_match = 0; 609143491Sglebius#endif 6101541Srgrimes 611155018Sthompsa if (ifp->if_bridge) 612146986Sthompsa bridged = 1; 613146986Sthompsa 61484931Sfjoe req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); 61584931Sfjoe if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) { 61674851Syar log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n"); 61774851Syar return; 61874851Syar } 61974851Syar 62084931Sfjoe ah = mtod(m, struct arphdr *); 62184931Sfjoe op = ntohs(ah->ar_op); 62284931Sfjoe (void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr)); 62384931Sfjoe (void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr)); 624134991Sglebius 62584102Sjlemon /* 62684102Sjlemon * For a bridge, we want to check the address irrespective 62784102Sjlemon * of the receive interface. (This will change slightly 62884102Sjlemon * when we have clusters of interfaces). 629142215Sglebius * If the interface does not match, but the recieving interface 630142215Sglebius * is part of carp, we call carp_iamatch to see if this is a 631142215Sglebius * request for the virtual host ip. 632142215Sglebius * XXX: This is really ugly! 63384102Sjlemon */ 634143314Sglebius LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { 635156409Sthompsa if (((bridged && ia->ia_ifp->if_bridge != NULL) || 636155145Sthompsa (ia->ia_ifp == ifp)) && 637143314Sglebius itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) 638143314Sglebius goto match; 639142215Sglebius#ifdef DEV_CARP 640143314Sglebius if (ifp->if_carp != NULL && 641143314Sglebius carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && 642143314Sglebius itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { 643143314Sglebius carp_match = 1; 644143314Sglebius goto match; 645143314Sglebius } 646142215Sglebius#endif 647143314Sglebius } 64884102Sjlemon LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) 649156409Sthompsa if (((bridged && ia->ia_ifp->if_bridge != NULL) || 650155145Sthompsa (ia->ia_ifp == ifp)) && 65184102Sjlemon isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) 65284102Sjlemon goto match; 65384102Sjlemon /* 65485223Sjlemon * No match, use the first inet address on the receive interface 65584102Sjlemon * as a dummy address for the rest of the function. 65684102Sjlemon */ 65785223Sjlemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 658160038Syar if (ifa->ifa_addr->sa_family == AF_INET) { 65985466Sjlemon ia = ifatoia(ifa); 66085466Sjlemon goto match; 66185466Sjlemon } 66285466Sjlemon /* 66385466Sjlemon * If bridging, fall back to using any inet address. 66485466Sjlemon */ 665146986Sthompsa if (!bridged || (ia = TAILQ_FIRST(&in_ifaddrhead)) == NULL) 666128645Sluigi goto drop; 66784102Sjlemonmatch: 668142215Sglebius if (!enaddr) 669142215Sglebius enaddr = (u_int8_t *)IF_LLADDR(ifp); 67084102Sjlemon myaddr = ia->ia_addr.sin_addr; 671142215Sglebius if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen)) 672128645Sluigi goto drop; /* it's from me, ignore it. */ 67384931Sfjoe if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) { 6741541Srgrimes log(LOG_ERR, 67584931Sfjoe "arp: link address is broadcast for IP address %s!\n", 6767088Swollman inet_ntoa(isaddr)); 677128645Sluigi goto drop; 6781541Srgrimes } 679136441Srwatson /* 680136441Srwatson * Warn if another host is using the same IP address, but only if the 681136441Srwatson * IP address isn't 0.0.0.0, which is used for DHCP only, in which 682136441Srwatson * case we suppress the warning to avoid false positive complaints of 683136441Srwatson * potential misconfiguration. 684136441Srwatson */ 685150942Sthompsa if (!bridged && isaddr.s_addr == myaddr.s_addr && myaddr.s_addr != 0) { 6861541Srgrimes log(LOG_ERR, 68784931Sfjoe "arp: %*D is using my IP address %s!\n", 68884931Sfjoe ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 68984931Sfjoe inet_ntoa(isaddr)); 6901541Srgrimes itaddr = myaddr; 6911541Srgrimes goto reply; 6921541Srgrimes } 693120626Sru if (ifp->if_flags & IFF_STATICARP) 694120626Sru goto reply; 695148955Sglebius rt = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); 696148955Sglebius if (rt != NULL) { 697148955Sglebius la = (struct llinfo_arp *)rt->rt_llinfo; 698148955Sglebius if (la == NULL) { 699148955Sglebius RT_UNLOCK(rt); 700148955Sglebius goto reply; 701148955Sglebius } 702148955Sglebius } else 703148955Sglebius goto reply; 704148955Sglebius 705148955Sglebius /* The following is not an error when doing bridging. */ 706148955Sglebius if (!bridged && rt->rt_ifp != ifp 707143491Sglebius#ifdef DEV_CARP 708148955Sglebius && (ifp->if_type != IFT_CARP || !carp_match) 709143491Sglebius#endif 710148955Sglebius ) { 711148955Sglebius if (log_arp_wrong_iface) 712148955Sglebius log(LOG_ERR, "arp: %s is on %s but got reply from %*D on %s\n", 713148955Sglebius inet_ntoa(isaddr), 714148955Sglebius rt->rt_ifp->if_xname, 715148955Sglebius ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 716148955Sglebius ifp->if_xname); 717148955Sglebius RT_UNLOCK(rt); 718148955Sglebius goto reply; 719148955Sglebius } 720148955Sglebius sdl = SDL(rt->rt_gateway); 721148955Sglebius if (sdl->sdl_alen && 722148955Sglebius bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) { 723148955Sglebius if (rt->rt_expire) { 724148955Sglebius if (log_arp_movements) 725148955Sglebius log(LOG_INFO, "arp: %s moved from %*D to %*D on %s\n", 726148955Sglebius inet_ntoa(isaddr), 727148955Sglebius ifp->if_addrlen, (u_char *)LLADDR(sdl), ":", 728148955Sglebius ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 729148955Sglebius ifp->if_xname); 730148955Sglebius } else { 731153513Sglebius RT_UNLOCK(rt); 732153513Sglebius if (log_arp_permanent_modify) 733153513Sglebius log(LOG_ERR, "arp: %*D attempts to modify " 734153513Sglebius "permanent entry for %s on %s\n", 735153513Sglebius ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 736153513Sglebius inet_ntoa(isaddr), ifp->if_xname); 737153513Sglebius goto reply; 73839389Sfenner } 739148955Sglebius } 740148955Sglebius /* 741148955Sglebius * sanity check for the address length. 742148955Sglebius * XXX this does not work for protocols with variable address 743148955Sglebius * length. -is 744148955Sglebius */ 745148955Sglebius if (sdl->sdl_alen && 746148955Sglebius sdl->sdl_alen != ah->ar_hln) { 747148955Sglebius log(LOG_WARNING, 748148955Sglebius "arp from %*D: new addr len %d, was %d", 749148955Sglebius ifp->if_addrlen, (u_char *) ar_sha(ah), ":", 750148955Sglebius ah->ar_hln, sdl->sdl_alen); 751148955Sglebius } 752148955Sglebius if (ifp->if_addrlen != ah->ar_hln) { 753148955Sglebius log(LOG_WARNING, 754148955Sglebius "arp from %*D: addr len: new %d, i/f %d (ignored)", 755148955Sglebius ifp->if_addrlen, (u_char *) ar_sha(ah), ":", 756148955Sglebius ah->ar_hln, ifp->if_addrlen); 757120727Ssam RT_UNLOCK(rt); 758148955Sglebius goto reply; 759148955Sglebius } 760148955Sglebius (void)memcpy(LLADDR(sdl), ar_sha(ah), 761148955Sglebius sdl->sdl_alen = ah->ar_hln); 762148955Sglebius /* 763148955Sglebius * If we receive an arp from a token-ring station over 764148955Sglebius * a token-ring nic then try to save the source 765148955Sglebius * routing info. 766148955Sglebius */ 767148955Sglebius if (ifp->if_type == IFT_ISO88025) { 768163006Sglebius struct iso88025_header *th = NULL; 769163006Sglebius struct iso88025_sockaddr_dl_data *trld; 770163006Sglebius 771148955Sglebius th = (struct iso88025_header *)m->m_pkthdr.header; 772148955Sglebius trld = SDL_ISO88025(sdl); 773148955Sglebius rif_len = TR_RCF_RIFLEN(th->rcf); 774148955Sglebius if ((th->iso88025_shost[0] & TR_RII) && 775148955Sglebius (rif_len > 2)) { 776148955Sglebius trld->trld_rcf = th->rcf; 777148955Sglebius trld->trld_rcf ^= htons(TR_RCF_DIR); 778148955Sglebius memcpy(trld->trld_route, th->rd, rif_len - 2); 779148955Sglebius trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK); 780148955Sglebius /* 781148955Sglebius * Set up source routing information for 782148955Sglebius * reply packet (XXX) 783148955Sglebius */ 784148955Sglebius m->m_data -= rif_len; 785148955Sglebius m->m_len += rif_len; 786148955Sglebius m->m_pkthdr.len += rif_len; 787148955Sglebius } else { 788148955Sglebius th->iso88025_shost[0] &= ~TR_RII; 789148955Sglebius trld->trld_rcf = 0; 7901541Srgrimes } 791148955Sglebius m->m_data -= 8; 792148955Sglebius m->m_len += 8; 793148955Sglebius m->m_pkthdr.len += 8; 794148955Sglebius th->rcf = trld->trld_rcf; 7951541Srgrimes } 796148955Sglebius if (rt->rt_expire) 797150351Sandre rt->rt_expire = time_uptime + arpt_keep; 798148955Sglebius la->la_asked = 0; 799148955Sglebius la->la_preempt = arp_maxtries; 800148955Sglebius hold = la->la_hold; 801148955Sglebius la->la_hold = NULL; 802148955Sglebius RT_UNLOCK(rt); 803148955Sglebius if (hold != NULL) 804148955Sglebius (*ifp->if_output)(ifp, hold, rt_key(rt), rt); 805148955Sglebius 8061541Srgrimesreply: 807128645Sluigi if (op != ARPOP_REQUEST) 808128645Sluigi goto drop; 8091541Srgrimes if (itaddr.s_addr == myaddr.s_addr) { 8101541Srgrimes /* I am the target */ 81184931Sfjoe (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 812142215Sglebius (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); 8131541Srgrimes } else { 814148955Sglebius rt = arplookup(itaddr.s_addr, 0, SIN_PROXY); 815148955Sglebius if (rt == NULL) { 8163282Swollman struct sockaddr_in sin; 8173282Swollman 818128645Sluigi if (!arp_proxyall) 819128645Sluigi goto drop; 8203282Swollman 8213282Swollman bzero(&sin, sizeof sin); 8223282Swollman sin.sin_family = AF_INET; 8233282Swollman sin.sin_len = sizeof sin; 8243282Swollman sin.sin_addr = itaddr; 8253282Swollman 8265101Swollman rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 827128645Sluigi if (!rt) 828128645Sluigi goto drop; 8293282Swollman /* 8303282Swollman * Don't send proxies for nodes on the same interface 8313282Swollman * as this one came out of, or we'll get into a fight 8323282Swollman * over who claims what Ether address. 8333282Swollman */ 83484931Sfjoe if (rt->rt_ifp == ifp) { 8353282Swollman rtfree(rt); 836128645Sluigi goto drop; 8373282Swollman } 83884931Sfjoe (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 839142215Sglebius (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); 8403282Swollman rtfree(rt); 84163080Sdwmalone 84263080Sdwmalone /* 84363080Sdwmalone * Also check that the node which sent the ARP packet 84463080Sdwmalone * is on the the interface we expect it to be on. This 84563080Sdwmalone * avoids ARP chaos if an interface is connected to the 84663080Sdwmalone * wrong network. 84763080Sdwmalone */ 84863080Sdwmalone sin.sin_addr = isaddr; 84963080Sdwmalone 85063080Sdwmalone rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 851128645Sluigi if (!rt) 852128645Sluigi goto drop; 85384931Sfjoe if (rt->rt_ifp != ifp) { 85463080Sdwmalone log(LOG_INFO, "arp_proxy: ignoring request" 855121816Sbrooks " from %s via %s, expecting %s\n", 856121816Sbrooks inet_ntoa(isaddr), ifp->if_xname, 857121816Sbrooks rt->rt_ifp->if_xname); 85863080Sdwmalone rtfree(rt); 859128645Sluigi goto drop; 86063080Sdwmalone } 86163080Sdwmalone rtfree(rt); 86263080Sdwmalone 8634069Swollman#ifdef DEBUG_PROXY 8648876Srgrimes printf("arp: proxying for %s\n", 8657088Swollman inet_ntoa(itaddr)); 8664069Swollman#endif 8673282Swollman } else { 868149451Sglebius /* 869149451Sglebius * Return proxied ARP replies only on the interface 870159448Sthompsa * or bridge cluster where this network resides. 871159448Sthompsa * Otherwise we may conflict with the host we are 872159448Sthompsa * proxying for. 873149451Sglebius */ 874159448Sthompsa if (rt->rt_ifp != ifp && 875163005Sglebius (rt->rt_ifp->if_bridge != ifp->if_bridge || 876163005Sglebius ifp->if_bridge == NULL)) { 877149451Sglebius RT_UNLOCK(rt); 878149451Sglebius goto drop; 879149451Sglebius } 880148955Sglebius sdl = SDL(rt->rt_gateway); 88184931Sfjoe (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 88284931Sfjoe (void)memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln); 883148955Sglebius RT_UNLOCK(rt); 8843282Swollman } 8851541Srgrimes } 8861541Srgrimes 88784931Sfjoe (void)memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); 88884931Sfjoe (void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln); 88984931Sfjoe ah->ar_op = htons(ARPOP_REPLY); 89084931Sfjoe ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */ 891127261Smdodd m->m_flags &= ~(M_BCAST|M_MCAST); /* never reply by broadcast */ 892127261Smdodd m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln); 893127261Smdodd m->m_pkthdr.len = m->m_len; 894127261Smdodd sa.sa_family = AF_ARP; 895127261Smdodd sa.sa_len = 2; 89684931Sfjoe (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0); 8971541Srgrimes return; 898128645Sluigi 899128645Sluigidrop: 900128645Sluigi m_freem(m); 9011541Srgrimes} 90232350Seivind#endif 9031541Srgrimes 9041541Srgrimes/* 9051541Srgrimes * Lookup or enter a new address in arptab. 9061541Srgrimes */ 907148955Sglebiusstatic struct rtentry * 9081541Srgrimesarplookup(addr, create, proxy) 9091541Srgrimes u_long addr; 9101541Srgrimes int create, proxy; 9111541Srgrimes{ 912126936Smdodd struct rtentry *rt; 913120727Ssam struct sockaddr_inarp sin; 9144069Swollman const char *why = 0; 9151541Srgrimes 916120727Ssam bzero(&sin, sizeof(sin)); 917120727Ssam sin.sin_len = sizeof(sin); 918120727Ssam sin.sin_family = AF_INET; 9191541Srgrimes sin.sin_addr.s_addr = addr; 920120727Ssam if (proxy) 921120727Ssam sin.sin_other = SIN_PROXY; 9225101Swollman rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); 9231541Srgrimes if (rt == 0) 9241541Srgrimes return (0); 9254069Swollman 92612693Sphk if (rt->rt_flags & RTF_GATEWAY) 9274069Swollman why = "host is not on local network"; 92812693Sphk else if ((rt->rt_flags & RTF_LLINFO) == 0) 9294069Swollman why = "could not allocate llinfo"; 93012693Sphk else if (rt->rt_gateway->sa_family != AF_LINK) 9314069Swollman why = "gateway route is not ours"; 9324069Swollman 933120383Sbms if (why) { 934120727Ssam#define ISDYNCLONE(_rt) \ 935120727Ssam (((_rt)->rt_flags & (RTF_STATIC | RTF_WASCLONED)) == RTF_WASCLONED) 936120727Ssam if (create) 937120383Sbms log(LOG_DEBUG, "arplookup %s failed: %s\n", 938120383Sbms inet_ntoa(sin.sin_addr), why); 939120727Ssam /* 940120727Ssam * If there are no references to this Layer 2 route, 941120727Ssam * and it is a cloned route, and not static, and 942120727Ssam * arplookup() is creating the route, then purge 943120727Ssam * it from the routing table as it is probably bogus. 944120727Ssam */ 945121770Ssam if (rt->rt_refcnt == 1 && ISDYNCLONE(rt)) 946121770Ssam rtexpunge(rt); 947121770Ssam RTFREE_LOCKED(rt); 948120383Sbms return (0); 949120727Ssam#undef ISDYNCLONE 950120727Ssam } else { 951122334Ssam RT_REMREF(rt); 952148955Sglebius return (rt); 9531541Srgrimes } 9541541Srgrimes} 9551541Srgrimes 9565195Swollmanvoid 95784931Sfjoearp_ifinit(ifp, ifa) 95884931Sfjoe struct ifnet *ifp; 9595195Swollman struct ifaddr *ifa; 9605195Swollman{ 96125822Stegge if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) 96284931Sfjoe arprequest(ifp, &IA_SIN(ifa)->sin_addr, 96384931Sfjoe &IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); 9645195Swollman ifa->ifa_rtrequest = arp_rtrequest; 9655195Swollman ifa->ifa_flags |= RTF_CLONING; 9665195Swollman} 96769152Sjlemon 968142215Sglebiusvoid 969142215Sglebiusarp_ifinit2(ifp, ifa, enaddr) 970142215Sglebius struct ifnet *ifp; 971142215Sglebius struct ifaddr *ifa; 972142215Sglebius u_char *enaddr; 973142215Sglebius{ 974142215Sglebius if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) 975142215Sglebius arprequest(ifp, &IA_SIN(ifa)->sin_addr, 976142215Sglebius &IA_SIN(ifa)->sin_addr, enaddr); 977142215Sglebius ifa->ifa_rtrequest = arp_rtrequest; 978142215Sglebius ifa->ifa_flags |= RTF_CLONING; 979142215Sglebius} 980142215Sglebius 98169152Sjlemonstatic void 98269152Sjlemonarp_init(void) 98369152Sjlemon{ 98469152Sjlemon 98569152Sjlemon arpintrq.ifq_maxlen = 50; 98693818Sjhb mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF); 98798459Speter LIST_INIT(&llinfo_arp); 988120727Ssam callout_init(&arp_callout, CALLOUT_MPSAFE); 989122320Ssam netisr_register(NETISR_ARP, arpintr, &arpintrq, NETISR_MPSAFE); 990128641Sluigi callout_reset(&arp_callout, hz, arptimer, NULL); 99169152Sjlemon} 99269152SjlemonSYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); 993