if_ether.c revision 186411
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 301541Srgrimes */ 311541Srgrimes 321541Srgrimes/* 331541Srgrimes * Ethernet address resolution protocol. 341541Srgrimes * TODO: 351541Srgrimes * add "inuse/lock" bit (or ref. count) along with valid bit 361541Srgrimes */ 371541Srgrimes 38172467Ssilby#include <sys/cdefs.h> 39172467Ssilby__FBSDID("$FreeBSD: head/sys/netinet/if_ether.c 186411 2008-12-23 03:33:32Z qingli $"); 40172467Ssilby 4132350Seivind#include "opt_inet.h" 42101090Srwatson#include "opt_mac.h" 43142215Sglebius#include "opt_carp.h" 4432350Seivind 451541Srgrimes#include <sys/param.h> 4612693Sphk#include <sys/kernel.h> 4744078Sdfr#include <sys/queue.h> 4812693Sphk#include <sys/sysctl.h> 491541Srgrimes#include <sys/systm.h> 5012693Sphk#include <sys/mbuf.h> 511541Srgrimes#include <sys/malloc.h> 52183014Sjulian#include <sys/proc.h> 5318892Sbde#include <sys/socket.h> 541541Srgrimes#include <sys/syslog.h> 55181803Sbz#include <sys/vimage.h> 561541Srgrimes 571541Srgrimes#include <net/if.h> 581541Srgrimes#include <net/if_dl.h> 5944165Sjulian#include <net/if_types.h> 601541Srgrimes#include <net/route.h> 618426Swollman#include <net/netisr.h> 6258313Slile#include <net/if_llc.h> 6371963Sjulian#include <net/ethernet.h> 64185571Sbz#include <net/vnet.h> 651541Srgrimes 661541Srgrimes#include <netinet/in.h> 671541Srgrimes#include <netinet/in_var.h> 68186119Sqingli#include <net/if_llatbl.h> 691541Srgrimes#include <netinet/if_ether.h> 70185571Sbz#include <netinet/vinet.h> 711541Srgrimes 7284931Sfjoe#include <net/if_arc.h> 7344627Sjulian#include <net/iso88025.h> 7444627Sjulian 75142215Sglebius#ifdef DEV_CARP 76142215Sglebius#include <netinet/ip_carp.h> 77142215Sglebius#endif 78142215Sglebius 79163606Srwatson#include <security/mac/mac_framework.h> 80163606Srwatson 811541Srgrimes#define SIN(s) ((struct sockaddr_in *)s) 821541Srgrimes#define SDL(s) ((struct sockaddr_dl *)s) 83186119Sqingli#define LLTABLE(ifp) ((struct lltable *)(ifp)->if_afdata[AF_INET]) 841541Srgrimes 8544078SdfrSYSCTL_DECL(_net_link_ether); 8612942SwollmanSYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); 871541Srgrimes 8812693Sphk/* timer values */ 89185088Szec#ifdef VIMAGE_GLOBALS 90185088Szecstatic int arpt_keep; /* once resolved, good for 20 more minutes */ 91185088Szecstatic int arp_maxtries; 92186119Sqingliint useloopback; /* use loopback interface for local traffic */ 93185088Szecstatic int arp_proxyall; 94185088Szec#endif 951541Srgrimes 96185348SzecSYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, max_age, 97185348Szec CTLFLAG_RW, arpt_keep, 0, "ARP entry lifetime in seconds"); 9812693Sphk 99111888Sjlemonstatic struct ifqueue arpintrq; 1001541Srgrimes 101183550SzecSYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, maxtries, 102183550Szec CTLFLAG_RW, arp_maxtries, 0, 103183550Szec "ARP resolution attempts before returning error"); 104183550SzecSYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, useloopback, 105183550Szec CTLFLAG_RW, useloopback, 0, 106183550Szec "Use the loopback interface for local traffic"); 107183550SzecSYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, proxyall, 108183550Szec CTLFLAG_RW, arp_proxyall, 0, 109183550Szec "Enable proxy ARP for all suitable requests"); 11012693Sphk 11192723Salfredstatic void arp_init(void); 112186119Sqinglivoid arprequest(struct ifnet *, 11392723Salfred struct in_addr *, struct in_addr *, u_char *); 114111888Sjlemonstatic void arpintr(struct mbuf *); 11592723Salfredstatic void arptimer(void *); 11632350Seivind#ifdef INET 11792723Salfredstatic void in_arpinput(struct mbuf *); 11832350Seivind#endif 11912693Sphk 120186119Sqingli#ifdef AF_INET 121186119Sqinglivoid arp_ifscrub(struct ifnet *ifp, uint32_t addr); 122186119Sqingli 1231541Srgrimes/* 124186119Sqingli * called by in_ifscrub to remove entry from the table when 125186119Sqingli * the interface goes away 1261541Srgrimes */ 127186119Sqinglivoid 128186119Sqingliarp_ifscrub(struct ifnet *ifp, uint32_t addr) 1291541Srgrimes{ 130186119Sqingli struct sockaddr_in addr4; 1311541Srgrimes 132186119Sqingli bzero((void *)&addr4, sizeof(addr4)); 133186119Sqingli addr4.sin_len = sizeof(addr4); 134186119Sqingli addr4.sin_family = AF_INET; 135186119Sqingli addr4.sin_addr.s_addr = addr; 136186119Sqingli IF_AFDATA_LOCK(ifp); 137186119Sqingli lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR), 138186119Sqingli (struct sockaddr *)&addr4); 139186119Sqingli IF_AFDATA_UNLOCK(ifp); 1401541Srgrimes} 141186119Sqingli#endif 1421541Srgrimes 1431541Srgrimes/* 144186119Sqingli * Timeout routine. Age arp_tab entries periodically. 1451541Srgrimes */ 1465196Swollmanstatic void 147186119Sqingliarptimer(void *arg) 1481541Srgrimes{ 149186119Sqingli struct ifnet *ifp; 150186119Sqingli struct llentry *lle = (struct llentry *)arg; 1511541Srgrimes 152186119Sqingli if (lle == NULL) { 153186119Sqingli panic("%s: NULL entry!\n", __func__); 1541541Srgrimes return; 155186119Sqingli } 156186119Sqingli ifp = lle->lle_tbl->llt_ifp; 157186119Sqingli IF_AFDATA_LOCK(ifp); 158186119Sqingli LLE_WLOCK(lle); 159186119Sqingli if ((lle->la_flags & LLE_DELETED) || 160186119Sqingli (time_second >= lle->la_expire)) { 161186119Sqingli if (!callout_pending(&lle->la_timer) && 162186119Sqingli callout_active(&lle->la_timer)) 163186119Sqingli (void) llentry_free(lle); 164186119Sqingli } else { 1651541Srgrimes /* 166186119Sqingli * Still valid, just drop our reference 1671541Srgrimes */ 168186119Sqingli LLE_FREE_LOCKED(lle); 1691541Srgrimes } 170186119Sqingli IF_AFDATA_UNLOCK(ifp); 1711541Srgrimes} 1721541Srgrimes 1731541Srgrimes/* 1741541Srgrimes * Broadcast an ARP request. Caller specifies: 1751541Srgrimes * - arp header source ip address 1761541Srgrimes * - arp header target ip address 1771541Srgrimes * - arp header source ethernet address 1781541Srgrimes */ 179186119Sqinglivoid 180186119Sqingliarprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, 181169454Srwatson u_char *enaddr) 1821541Srgrimes{ 183126936Smdodd struct mbuf *m; 184126936Smdodd struct arphdr *ah; 1851541Srgrimes struct sockaddr sa; 1861541Srgrimes 187186119Sqingli if (sip == NULL) { 188186119Sqingli /* XXX don't believe this can happen (or explain why) */ 189186119Sqingli /* 190186119Sqingli * The caller did not supply a source address, try to find 191186119Sqingli * a compatible one among those assigned to this interface. 192186119Sqingli */ 193186119Sqingli struct ifaddr *ifa; 194186119Sqingli 195186119Sqingli TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 196186119Sqingli if (!ifa->ifa_addr || 197186119Sqingli ifa->ifa_addr->sa_family != AF_INET) 198186119Sqingli continue; 199186119Sqingli sip = &SIN(ifa->ifa_addr)->sin_addr; 200186119Sqingli if (0 == ((sip->s_addr ^ tip->s_addr) & 201186119Sqingli SIN(ifa->ifa_netmask)->sin_addr.s_addr) ) 202186119Sqingli break; /* found it. */ 203186119Sqingli } 204186119Sqingli if (sip == NULL) { 205186119Sqingli printf("%s: cannot find matching address\n", __func__); 206186119Sqingli return; 207186119Sqingli } 208186119Sqingli } 209186119Sqingli 210111119Simp if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 2111541Srgrimes return; 212127261Smdodd m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + 213127261Smdodd 2*ifp->if_data.ifi_addrlen; 214127277Smdodd m->m_pkthdr.len = m->m_len; 215127277Smdodd MH_ALIGN(m, m->m_len); 216127277Smdodd ah = mtod(m, struct arphdr *); 217127261Smdodd bzero((caddr_t)ah, m->m_len); 218101090Srwatson#ifdef MAC 219173095Srwatson mac_netinet_arp_send(ifp, m); 220101090Srwatson#endif 22184931Sfjoe ah->ar_pro = htons(ETHERTYPE_IP); 22284931Sfjoe ah->ar_hln = ifp->if_addrlen; /* hardware address length */ 22384931Sfjoe ah->ar_pln = sizeof(struct in_addr); /* protocol address length */ 22484931Sfjoe ah->ar_op = htons(ARPOP_REQUEST); 225127261Smdodd bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln); 226127261Smdodd bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln); 227127261Smdodd bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln); 228127261Smdodd sa.sa_family = AF_ARP; 229127261Smdodd sa.sa_len = 2; 230127261Smdodd m->m_flags |= M_BCAST; 231127261Smdodd (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0); 2321541Srgrimes} 2331541Srgrimes 2341541Srgrimes/* 235128636Sluigi * Resolve an IP address into an ethernet address. 236128636Sluigi * On input: 237128636Sluigi * ifp is the interface we use 238175025Sjulian * rt0 is the route to the final destination (possibly useless) 239175025Sjulian * m is the mbuf. May be NULL if we don't have a packet. 240128636Sluigi * dst is the next hop, 241128636Sluigi * desten is where we want the address. 242128636Sluigi * 243128636Sluigi * On success, desten is filled in and the function returns 0; 244128636Sluigi * If the packet must be held pending resolution, we return EWOULDBLOCK 245128636Sluigi * On other errors, we return the corresponding error code. 246175025Sjulian * Note that m_freem() handles NULL. 2471541Srgrimes */ 2481541Srgrimesint 249128636Sluigiarpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, 250186119Sqingli struct sockaddr *dst, u_char *desten, struct llentry **lle) 2511541Srgrimes{ 252183550Szec INIT_VNET_INET(ifp->if_vnet); 253186119Sqingli struct llentry *la = 0; 254186200Skmacy u_int flags = 0; 255186119Sqingli int error, renew; 2561541Srgrimes 257186119Sqingli *lle = NULL; 258186119Sqingli if (m != NULL) { 259175025Sjulian if (m->m_flags & M_BCAST) { 260175025Sjulian /* broadcast */ 261175025Sjulian (void)memcpy(desten, 262175025Sjulian ifp->if_broadcastaddr, ifp->if_addrlen); 263175025Sjulian return (0); 264175025Sjulian } 265175025Sjulian if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) { 266175025Sjulian /* multicast */ 267175025Sjulian ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); 268175025Sjulian return (0); 269175025Sjulian } 2701541Srgrimes } 271186119Sqingli /* XXXXX 272183013Sjulian */ 273186119Sqingliretry: 274186200Skmacy IF_AFDATA_RLOCK(ifp); 275186119Sqingli la = lla_lookup(LLTABLE(ifp), flags, dst); 276186200Skmacy IF_AFDATA_RUNLOCK(ifp); 277186200Skmacy if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0) 278186200Skmacy && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) { 279186200Skmacy flags |= (LLE_CREATE | LLE_EXCLUSIVE); 280186200Skmacy IF_AFDATA_WLOCK(ifp); 281186200Skmacy la = lla_lookup(LLTABLE(ifp), flags, dst); 282186200Skmacy IF_AFDATA_WUNLOCK(ifp); 283186200Skmacy } 284148955Sglebius if (la == NULL) { 285186119Sqingli if (flags & LLE_CREATE) 286148955Sglebius log(LOG_DEBUG, 287148955Sglebius "arpresolve: can't allocate llinfo for %s\n", 288148955Sglebius inet_ntoa(SIN(dst)->sin_addr)); 289186119Sqingli m_freem(m); 290186119Sqingli return (EINVAL); 291186119Sqingli } 292149909Sglebius 293186119Sqingli if ((la->la_flags & LLE_VALID) && 294186119Sqingli ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) { 295186119Sqingli bcopy(&la->ll_addr, desten, ifp->if_addrlen); 29692802Sorion /* 29792802Sorion * If entry has an expiry time and it is approaching, 298186119Sqingli * see if we need to send an ARP request within this 299186119Sqingli * arpt_down interval. 30092802Sorion */ 301186119Sqingli if (!(la->la_flags & LLE_STATIC) && 302186119Sqingli time_uptime + la->la_preempt > la->la_expire) { 303186119Sqingli arprequest(ifp, NULL, 304186119Sqingli &SIN(dst)->sin_addr, IF_LLADDR(ifp)); 305149909Sglebius 306110544Sorion la->la_preempt--; 307186119Sqingli } 308186119Sqingli 309186119Sqingli *lle = la; 310186119Sqingli error = 0; 311186119Sqingli goto done; 312186119Sqingli } 313186119Sqingli 314186119Sqingli if (la->la_flags & LLE_STATIC) { /* should not happen! */ 315186119Sqingli log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n", 316186119Sqingli inet_ntoa(SIN(dst)->sin_addr)); 317186119Sqingli m_freem(m); 318186119Sqingli error = EINVAL; 319186119Sqingli goto done; 320186119Sqingli } 32192802Sorion 322186119Sqingli renew = (la->la_asked == 0 || la->la_expire != time_uptime); 323186119Sqingli if ((renew || m != NULL) && (flags & LLE_EXCLUSIVE) == 0) { 324186119Sqingli flags |= LLE_EXCLUSIVE; 325186119Sqingli LLE_RUNLOCK(la); 326186119Sqingli goto retry; 3271541Srgrimes } 3281541Srgrimes /* 3291541Srgrimes * There is an arptab entry, but no ethernet address 3301541Srgrimes * response yet. Replace the held mbuf with this 3311541Srgrimes * latest one. 3321541Srgrimes */ 333186119Sqingli if (m != NULL) { 334186119Sqingli if (la->la_hold != NULL) 335175025Sjulian m_freem(la->la_hold); 336175025Sjulian la->la_hold = m; 337186119Sqingli if (renew == 0 && (flags & LLE_EXCLUSIVE)) { 338186119Sqingli flags &= ~LLE_EXCLUSIVE; 339186119Sqingli LLE_DOWNGRADE(la); 340186119Sqingli } 341186119Sqingli 342174699Skmacy } 343152188Sglebius /* 344152188Sglebius * Return EWOULDBLOCK if we have tried less than arp_maxtries. It 345152188Sglebius * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH 346152188Sglebius * if we have already sent arp_maxtries ARP requests. Retransmit the 347152188Sglebius * ARP request, but not faster than one request per second. 348152188Sglebius */ 349181803Sbz if (la->la_asked < V_arp_maxtries) 350152188Sglebius error = EWOULDBLOCK; /* First request. */ 351152188Sglebius else 352186119Sqingli error = 353186119Sqingli (rt0->rt_flags & RTF_GATEWAY) ? EHOSTDOWN : EHOSTUNREACH; 354152188Sglebius 355186119Sqingli if (renew) { 356186119Sqingli LLE_ADDREF(la); 357186119Sqingli la->la_expire = time_uptime; 358186119Sqingli callout_reset(&la->la_timer, hz, arptimer, la); 359166010Smaxim la->la_asked++; 360186119Sqingli LLE_WUNLOCK(la); 361186119Sqingli arprequest(ifp, NULL, &SIN(dst)->sin_addr, 362152188Sglebius IF_LLADDR(ifp)); 363186119Sqingli return (error); 364186119Sqingli } 365186119Sqinglidone: 366186119Sqingli if (flags & LLE_EXCLUSIVE) 367186119Sqingli LLE_WUNLOCK(la); 368186119Sqingli else 369186119Sqingli LLE_RUNLOCK(la); 370152188Sglebius return (error); 3711541Srgrimes} 3721541Srgrimes 3731541Srgrimes/* 3741541Srgrimes * Common length and type checks are done here, 3751541Srgrimes * then the protocol-specific routine is called. 3761541Srgrimes */ 37712693Sphkstatic void 378111888Sjlemonarpintr(struct mbuf *m) 3791541Srgrimes{ 380111888Sjlemon struct arphdr *ar; 3811541Srgrimes 382111888Sjlemon if (m->m_len < sizeof(struct arphdr) && 383111888Sjlemon ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) { 384111888Sjlemon log(LOG_ERR, "arp: runt packet -- m_pullup failed\n"); 385111888Sjlemon return; 386111888Sjlemon } 387111888Sjlemon ar = mtod(m, struct arphdr *); 3881541Srgrimes 389111888Sjlemon if (ntohs(ar->ar_hrd) != ARPHRD_ETHER && 390111888Sjlemon ntohs(ar->ar_hrd) != ARPHRD_IEEE802 && 391130407Sdfr ntohs(ar->ar_hrd) != ARPHRD_ARCNET && 392130407Sdfr ntohs(ar->ar_hrd) != ARPHRD_IEEE1394) { 393111888Sjlemon log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n", 394111888Sjlemon (unsigned char *)&ar->ar_hrd, ""); 395111888Sjlemon m_freem(m); 396111888Sjlemon return; 397111888Sjlemon } 3981541Srgrimes 399123768Sru if (m->m_len < arphdr_len(ar)) { 400123765Sru if ((m = m_pullup(m, arphdr_len(ar))) == NULL) { 401123765Sru log(LOG_ERR, "arp: runt packet\n"); 402123765Sru m_freem(m); 403123765Sru return; 404123765Sru } 405123765Sru ar = mtod(m, struct arphdr *); 406111888Sjlemon } 40757900Srwatson 408111888Sjlemon switch (ntohs(ar->ar_pro)) { 40932350Seivind#ifdef INET 410111888Sjlemon case ETHERTYPE_IP: 411111888Sjlemon in_arpinput(m); 412111888Sjlemon return; 41332350Seivind#endif 4141541Srgrimes } 415111888Sjlemon m_freem(m); 4161541Srgrimes} 4171541Srgrimes 41832350Seivind#ifdef INET 4191541Srgrimes/* 4201541Srgrimes * ARP for Internet protocols on 10 Mb/s Ethernet. 4211541Srgrimes * Algorithm is that given in RFC 826. 4221541Srgrimes * In addition, a sanity check is performed on the sender 4231541Srgrimes * protocol address, to catch impersonators. 4241541Srgrimes * We no longer handle negotiations for use of trailer protocol: 4251541Srgrimes * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent 4261541Srgrimes * along with IP replies if we wanted trailers sent to us, 4271541Srgrimes * and also sent them in response to IP replies. 4281541Srgrimes * This allowed either end to announce the desire to receive 4291541Srgrimes * trailer packets. 4301541Srgrimes * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, 4311541Srgrimes * but formerly didn't normally send requests. 4321541Srgrimes */ 43370699Salfredstatic int log_arp_wrong_iface = 1; 43482893Salfredstatic int log_arp_movements = 1; 435153513Sglebiusstatic int log_arp_permanent_modify = 1; 43670699Salfred 43770699SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW, 43870699Salfred &log_arp_wrong_iface, 0, 43970699Salfred "log arp packets arriving on the wrong interface"); 44082893SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_movements, CTLFLAG_RW, 44182893Salfred &log_arp_movements, 0, 44282966Salfred "log arp replies from MACs different than the one in the cache"); 443153513SglebiusSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_permanent_modify, CTLFLAG_RW, 444153513Sglebius &log_arp_permanent_modify, 0, 445153513Sglebius "log arp replies from MACs different than the one in the permanent arp entry"); 44670699Salfred 44782893Salfred 4481541Srgrimesstatic void 449169454Srwatsonin_arpinput(struct mbuf *m) 4501541Srgrimes{ 451126936Smdodd struct arphdr *ah; 452126936Smdodd struct ifnet *ifp = m->m_pkthdr.rcvif; 453186119Sqingli struct llentry *la = NULL; 454126936Smdodd struct rtentry *rt; 45584102Sjlemon struct ifaddr *ifa; 45684102Sjlemon struct in_ifaddr *ia; 4571541Srgrimes struct sockaddr sa; 4581541Srgrimes struct in_addr isaddr, itaddr, myaddr; 459142215Sglebius u_int8_t *enaddr = NULL; 460186119Sqingli int op, flags; 461186119Sqingli struct mbuf *m0; 46284931Sfjoe int req_len; 463181824Sphilip int bridged = 0, is_bridge = 0; 464143491Sglebius#ifdef DEV_CARP 465143314Sglebius int carp_match = 0; 466143491Sglebius#endif 467174559Skmacy struct sockaddr_in sin; 468174559Skmacy sin.sin_len = sizeof(struct sockaddr_in); 469174559Skmacy sin.sin_family = AF_INET; 470174703Skmacy sin.sin_addr.s_addr = 0; 471183550Szec INIT_VNET_INET(ifp->if_vnet); 472183550Szec 473155018Sthompsa if (ifp->if_bridge) 474146986Sthompsa bridged = 1; 475181824Sphilip if (ifp->if_type == IFT_BRIDGE) 476181824Sphilip is_bridge = 1; 477146986Sthompsa 47884931Sfjoe req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); 47984931Sfjoe if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) { 48074851Syar log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n"); 48174851Syar return; 48274851Syar } 48374851Syar 48484931Sfjoe ah = mtod(m, struct arphdr *); 48584931Sfjoe op = ntohs(ah->ar_op); 48684931Sfjoe (void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr)); 48784931Sfjoe (void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr)); 488134991Sglebius 48984102Sjlemon /* 49084102Sjlemon * For a bridge, we want to check the address irrespective 49184102Sjlemon * of the receive interface. (This will change slightly 49284102Sjlemon * when we have clusters of interfaces). 493142215Sglebius * If the interface does not match, but the recieving interface 494142215Sglebius * is part of carp, we call carp_iamatch to see if this is a 495142215Sglebius * request for the virtual host ip. 496142215Sglebius * XXX: This is really ugly! 49784102Sjlemon */ 498143314Sglebius LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { 499156409Sthompsa if (((bridged && ia->ia_ifp->if_bridge != NULL) || 500186119Sqingli ia->ia_ifp == ifp) && 501143314Sglebius itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) 502143314Sglebius goto match; 503142215Sglebius#ifdef DEV_CARP 504143314Sglebius if (ifp->if_carp != NULL && 505143314Sglebius carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && 506143314Sglebius itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { 507143314Sglebius carp_match = 1; 508143314Sglebius goto match; 509143314Sglebius } 510142215Sglebius#endif 511143314Sglebius } 51284102Sjlemon LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) 513156409Sthompsa if (((bridged && ia->ia_ifp->if_bridge != NULL) || 514186119Sqingli ia->ia_ifp == ifp) && 51584102Sjlemon isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) 51684102Sjlemon goto match; 517181824Sphilip 518181824Sphilip#define BDG_MEMBER_MATCHES_ARP(addr, ifp, ia) \ 519181824Sphilip (ia->ia_ifp->if_bridge == ifp->if_softc && \ 520181824Sphilip !bcmp(IF_LLADDR(ia->ia_ifp), IF_LLADDR(ifp), ifp->if_addrlen) && \ 521181824Sphilip addr == ia->ia_addr.sin_addr.s_addr) 52284102Sjlemon /* 523181824Sphilip * Check the case when bridge shares its MAC address with 524181824Sphilip * some of its children, so packets are claimed by bridge 525181824Sphilip * itself (bridge_input() does it first), but they are really 526181824Sphilip * meant to be destined to the bridge member. 527181824Sphilip */ 528181824Sphilip if (is_bridge) { 529181824Sphilip LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { 530181824Sphilip if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) { 531181824Sphilip ifp = ia->ia_ifp; 532181824Sphilip goto match; 533181824Sphilip } 534181824Sphilip } 535181824Sphilip } 536181824Sphilip#undef BDG_MEMBER_MATCHES_ARP 537181824Sphilip 538181824Sphilip /* 53985223Sjlemon * No match, use the first inet address on the receive interface 54084102Sjlemon * as a dummy address for the rest of the function. 54184102Sjlemon */ 54285223Sjlemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 543160038Syar if (ifa->ifa_addr->sa_family == AF_INET) { 54485466Sjlemon ia = ifatoia(ifa); 54585466Sjlemon goto match; 54685466Sjlemon } 54785466Sjlemon /* 54885466Sjlemon * If bridging, fall back to using any inet address. 54985466Sjlemon */ 550181803Sbz if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) 551128645Sluigi goto drop; 55284102Sjlemonmatch: 553142215Sglebius if (!enaddr) 554142215Sglebius enaddr = (u_int8_t *)IF_LLADDR(ifp); 55584102Sjlemon myaddr = ia->ia_addr.sin_addr; 556142215Sglebius if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen)) 557128645Sluigi goto drop; /* it's from me, ignore it. */ 55884931Sfjoe if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) { 5591541Srgrimes log(LOG_ERR, 56084931Sfjoe "arp: link address is broadcast for IP address %s!\n", 5617088Swollman inet_ntoa(isaddr)); 562128645Sluigi goto drop; 5631541Srgrimes } 564136441Srwatson /* 565136441Srwatson * Warn if another host is using the same IP address, but only if the 566136441Srwatson * IP address isn't 0.0.0.0, which is used for DHCP only, in which 567136441Srwatson * case we suppress the warning to avoid false positive complaints of 568136441Srwatson * potential misconfiguration. 569136441Srwatson */ 570150942Sthompsa if (!bridged && isaddr.s_addr == myaddr.s_addr && myaddr.s_addr != 0) { 5711541Srgrimes log(LOG_ERR, 572174256Syar "arp: %*D is using my IP address %s on %s!\n", 57384931Sfjoe ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 574174256Syar inet_ntoa(isaddr), ifp->if_xname); 5751541Srgrimes itaddr = myaddr; 5761541Srgrimes goto reply; 5771541Srgrimes } 578120626Sru if (ifp->if_flags & IFF_STATICARP) 579120626Sru goto reply; 580148955Sglebius 581186119Sqingli bzero(&sin, sizeof(sin)); 582186119Sqingli sin.sin_len = sizeof(struct sockaddr_in); 583186119Sqingli sin.sin_family = AF_INET; 584186119Sqingli sin.sin_addr = isaddr; 585186119Sqingli flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0; 586186119Sqingli flags |= LLE_EXCLUSIVE; 587186119Sqingli IF_AFDATA_LOCK(ifp); 588186119Sqingli la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin); 589186119Sqingli IF_AFDATA_UNLOCK(ifp); 590186119Sqingli if (la != NULL) { 591186119Sqingli /* the following is not an error when doing bridging */ 592186119Sqingli if (!bridged && la->lle_tbl->llt_ifp != ifp 593143491Sglebius#ifdef DEV_CARP 594186119Sqingli && (ifp->if_type != IFT_CARP || !carp_match) 595143491Sglebius#endif 596186119Sqingli ) { 597186119Sqingli if (log_arp_wrong_iface) 598186119Sqingli log(LOG_ERR, "arp: %s is on %s " 599186119Sqingli "but got reply from %*D on %s\n", 600186119Sqingli inet_ntoa(isaddr), 601186119Sqingli la->lle_tbl->llt_ifp->if_xname, 602186119Sqingli ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 603186119Sqingli ifp->if_xname); 604186119Sqingli goto reply; 605186119Sqingli } 606186119Sqingli if ((la->la_flags & LLE_VALID) && 607186119Sqingli bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { 608186119Sqingli if (la->la_flags & LLE_STATIC) { 609186119Sqingli log(LOG_ERR, 610186119Sqingli "arp: %*D attempts to modify permanent " 611186119Sqingli "entry for %s on %s\n", 612186119Sqingli ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 613186119Sqingli inet_ntoa(isaddr), ifp->if_xname); 614186119Sqingli goto reply; 615178888Sjulian } 616186119Sqingli if (log_arp_movements) { 617186119Sqingli log(LOG_INFO, "arp: %s moved from %*D " 618186119Sqingli "to %*D on %s\n", 619186119Sqingli inet_ntoa(isaddr), 620186119Sqingli ifp->if_addrlen, 621186119Sqingli (u_char *)&la->ll_addr, ":", 622186119Sqingli ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 623186119Sqingli ifp->if_xname); 624178888Sjulian } 625178888Sjulian } 626186119Sqingli 627186119Sqingli if (ifp->if_addrlen != ah->ar_hln) { 628186119Sqingli log(LOG_WARNING, 629186119Sqingli "arp from %*D: addr len: new %d, i/f %d (ignored)", 630186119Sqingli ifp->if_addrlen, (u_char *) ar_sha(ah), ":", 631186119Sqingli ah->ar_hln, ifp->if_addrlen); 632186119Sqingli goto reply; 633178888Sjulian } 634186119Sqingli (void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen); 635186119Sqingli la->la_flags |= LLE_VALID; 636178888Sjulian 637186119Sqingli if (!(la->la_flags & LLE_STATIC)) { 638186119Sqingli la->la_expire = time_uptime + V_arpt_keep; 639181803Sbz callout_reset(&la->la_timer, hz * V_arpt_keep, 640186119Sqingli arptimer, la); 64139389Sfenner } 642178888Sjulian la->la_asked = 0; 643181803Sbz la->la_preempt = V_arp_maxtries; 644186119Sqingli if (la->la_hold != NULL) { 645186119Sqingli m0 = la->la_hold; 646186119Sqingli la->la_hold = 0; 647186119Sqingli memcpy(&sa, L3_ADDR(la), sizeof(sa)); 648186119Sqingli LLE_WUNLOCK(la); 649186119Sqingli 650186119Sqingli (*ifp->if_output)(ifp, m0, &sa, NULL); 651186119Sqingli return; 652186119Sqingli } 653186119Sqingli } 654178888Sjulianreply: 655128645Sluigi if (op != ARPOP_REQUEST) 656128645Sluigi goto drop; 657186119Sqingli 6581541Srgrimes if (itaddr.s_addr == myaddr.s_addr) { 659178888Sjulian /* Shortcut.. the receiving interface is the target. */ 66084931Sfjoe (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 661142215Sglebius (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); 6621541Srgrimes } else { 663186317Sqingli struct llentry *lle = NULL; 6643282Swollman 665186317Sqingli if (!V_arp_proxyall) 666186317Sqingli goto drop; 667186317Sqingli 668186317Sqingli sin.sin_addr = itaddr; 669186317Sqingli /* XXX MRT use table 0 for arp reply */ 670186317Sqingli rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); 671186317Sqingli if (!rt) 672186317Sqingli goto drop; 673186317Sqingli 674186317Sqingli /* 675186317Sqingli * Don't send proxies for nodes on the same interface 676186317Sqingli * as this one came out of, or we'll get into a fight 677186317Sqingli * over who claims what Ether address. 678186317Sqingli */ 679186317Sqingli if (!rt->rt_ifp || rt->rt_ifp == ifp) { 680185713Scsjp RTFREE_LOCKED(rt); 681186317Sqingli goto drop; 682186317Sqingli } 683186317Sqingli IF_AFDATA_LOCK(rt->rt_ifp); 684186317Sqingli lle = lla_lookup(LLTABLE(rt->rt_ifp), 0, (struct sockaddr *)&sin); 685186317Sqingli IF_AFDATA_UNLOCK(rt->rt_ifp); 686186317Sqingli RTFREE_LOCKED(rt); 68763080Sdwmalone 688186317Sqingli if (lle != NULL) { 689186317Sqingli (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 690186317Sqingli (void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln); 691186317Sqingli LLE_RUNLOCK(lle); 692186317Sqingli } else 693186317Sqingli goto drop; 69463080Sdwmalone 695186317Sqingli /* 696186317Sqingli * Also check that the node which sent the ARP packet 697186317Sqingli * is on the the interface we expect it to be on. This 698186317Sqingli * avoids ARP chaos if an interface is connected to the 699186317Sqingli * wrong network. 700186317Sqingli */ 701186317Sqingli sin.sin_addr = isaddr; 702186317Sqingli 703186317Sqingli /* XXX MRT use table 0 for arp checks */ 704186317Sqingli rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); 705186317Sqingli if (!rt) 706186317Sqingli goto drop; 707186317Sqingli if (rt->rt_ifp != ifp) { 708186317Sqingli log(LOG_INFO, "arp_proxy: ignoring request" 709186317Sqingli " from %s via %s, expecting %s\n", 710186317Sqingli inet_ntoa(isaddr), ifp->if_xname, 711186317Sqingli rt->rt_ifp->if_xname); 712185713Scsjp RTFREE_LOCKED(rt); 713186317Sqingli goto drop; 714186317Sqingli } 715186317Sqingli RTFREE_LOCKED(rt); 71663080Sdwmalone 7174069Swollman#ifdef DEBUG_PROXY 718186317Sqingli printf("arp: proxying for %s\n", 719186317Sqingli inet_ntoa(itaddr)); 7204069Swollman#endif 7211541Srgrimes } 7221541Srgrimes 723186119Sqingli if (la != NULL) 724186119Sqingli LLE_WUNLOCK(la); 725166436Sbms if (itaddr.s_addr == myaddr.s_addr && 726166436Sbms IN_LINKLOCAL(ntohl(itaddr.s_addr))) { 727166436Sbms /* RFC 3927 link-local IPv4; always reply by broadcast. */ 728166436Sbms#ifdef DEBUG_LINKLOCAL 729166436Sbms printf("arp: sending reply for link-local addr %s\n", 730166436Sbms inet_ntoa(itaddr)); 731166436Sbms#endif 732166436Sbms m->m_flags |= M_BCAST; 733166436Sbms m->m_flags &= ~M_MCAST; 734166436Sbms } else { 735166436Sbms /* default behaviour; never reply by broadcast. */ 736166436Sbms m->m_flags &= ~(M_BCAST|M_MCAST); 737166436Sbms } 73884931Sfjoe (void)memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); 73984931Sfjoe (void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln); 74084931Sfjoe ah->ar_op = htons(ARPOP_REPLY); 74184931Sfjoe ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */ 742127261Smdodd m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln); 743127261Smdodd m->m_pkthdr.len = m->m_len; 744127261Smdodd sa.sa_family = AF_ARP; 745127261Smdodd sa.sa_len = 2; 74684931Sfjoe (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0); 7471541Srgrimes return; 748128645Sluigi 749128645Sluigidrop: 750186119Sqingli if (la != NULL) 751186119Sqingli LLE_WUNLOCK(la); 752128645Sluigi m_freem(m); 7531541Srgrimes} 75432350Seivind#endif 7551541Srgrimes 7565195Swollmanvoid 757169454Srwatsonarp_ifinit(struct ifnet *ifp, struct ifaddr *ifa) 7585195Swollman{ 759186119Sqingli struct llentry *lle; 760186119Sqingli 761186411Sqingli if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) { 76284931Sfjoe arprequest(ifp, &IA_SIN(ifa)->sin_addr, 76384931Sfjoe &IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); 764186411Sqingli /* 765186411Sqingli * interface address is considered static entry 766186411Sqingli * because the output of the arp utility shows 767186411Sqingli * that L2 entry as permanent 768186411Sqingli */ 769186411Sqingli IF_AFDATA_LOCK(ifp); 770186411Sqingli lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | LLE_STATIC), 771186411Sqingli (struct sockaddr *)IA_SIN(ifa)); 772186411Sqingli IF_AFDATA_UNLOCK(ifp); 773186411Sqingli if (lle == NULL) 774186411Sqingli log(LOG_INFO, "arp_ifinit: cannot create arp " 775186411Sqingli "entry for interface address\n"); 776186411Sqingli else 777186411Sqingli LLE_RUNLOCK(lle); 778186411Sqingli } 779186119Sqingli ifa->ifa_rtrequest = NULL; 7805195Swollman} 78169152Sjlemon 782142215Sglebiusvoid 783169454Srwatsonarp_ifinit2(struct ifnet *ifp, struct ifaddr *ifa, u_char *enaddr) 784142215Sglebius{ 785142215Sglebius if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) 786142215Sglebius arprequest(ifp, &IA_SIN(ifa)->sin_addr, 787142215Sglebius &IA_SIN(ifa)->sin_addr, enaddr); 788186119Sqingli ifa->ifa_rtrequest = NULL; 789142215Sglebius} 790142215Sglebius 79169152Sjlemonstatic void 79269152Sjlemonarp_init(void) 79369152Sjlemon{ 794185088Szec INIT_VNET_INET(curvnet); 79569152Sjlemon 796185088Szec V_arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ 797185088Szec V_arp_maxtries = 5; 798185088Szec V_useloopback = 1; /* use loopback interface for local traffic */ 799185088Szec V_arp_proxyall = 0; 800185088Szec 80169152Sjlemon arpintrq.ifq_maxlen = 50; 80293818Sjhb mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF); 803180239Srwatson netisr_register(NETISR_ARP, arpintr, &arpintrq, 0); 80469152Sjlemon} 80569152SjlemonSYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); 806