if_ether.c revision 211193
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 211193 2010-08-11 20:18:19Z will $"); 40172467Ssilby 4132350Seivind#include "opt_inet.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> 50183014Sjulian#include <sys/proc.h> 5118892Sbde#include <sys/socket.h> 521541Srgrimes#include <sys/syslog.h> 531541Srgrimes 541541Srgrimes#include <net/if.h> 551541Srgrimes#include <net/if_dl.h> 5644165Sjulian#include <net/if_types.h> 578426Swollman#include <net/netisr.h> 5858313Slile#include <net/if_llc.h> 5971963Sjulian#include <net/ethernet.h> 60194739Sbz#include <net/route.h> 61196019Srwatson#include <net/vnet.h> 621541Srgrimes 631541Srgrimes#include <netinet/in.h> 641541Srgrimes#include <netinet/in_var.h> 65186119Sqingli#include <net/if_llatbl.h> 661541Srgrimes#include <netinet/if_ether.h> 67211193Swill#if defined(INET) || defined(INET6) 68211193Swill#include <netinet/ip_carp.h> 69211193Swill#endif 701541Srgrimes 7184931Sfjoe#include <net/if_arc.h> 7244627Sjulian#include <net/iso88025.h> 7344627Sjulian 74163606Srwatson#include <security/mac/mac_framework.h> 75163606Srwatson 761541Srgrimes#define SIN(s) ((struct sockaddr_in *)s) 771541Srgrimes#define SDL(s) ((struct sockaddr_dl *)s) 781541Srgrimes 7944078SdfrSYSCTL_DECL(_net_link_ether); 8012942SwollmanSYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); 81196797SgnnSYSCTL_NODE(_net_link_ether, PF_ARP, arp, CTLFLAG_RW, 0, ""); 821541Srgrimes 8312693Sphk/* timer values */ 84195699Srwatsonstatic VNET_DEFINE(int, arpt_keep) = (20*60); /* once resolved, good for 20 85195699Srwatson * minutes */ 86207369Sbzstatic VNET_DEFINE(int, arp_maxtries) = 5; 87207369SbzVNET_DEFINE(int, useloopback) = 1; /* use loopback interface for 88207369Sbz * local traffic */ 89207369Sbzstatic VNET_DEFINE(int, arp_proxyall) = 0; 90198111Sqinglistatic VNET_DEFINE(int, arpt_down) = 20; /* keep incomplete entries for 91198111Sqingli * 20 seconds */ 92196797Sgnnstatic VNET_DEFINE(struct arpstat, arpstat); /* ARP statistics, see if_arp.h */ 931541Srgrimes 94195727Srwatson#define V_arpt_keep VNET(arpt_keep) 95198111Sqingli#define V_arpt_down VNET(arpt_down) 96195727Srwatson#define V_arp_maxtries VNET(arp_maxtries) 97195727Srwatson#define V_arp_proxyall VNET(arp_proxyall) 98196797Sgnn#define V_arpstat VNET(arpstat) 9912693Sphk 100195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 101195699Srwatson &VNET_NAME(arpt_keep), 0, 102195699Srwatson "ARP entry lifetime in seconds"); 103195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, 104195699Srwatson &VNET_NAME(arp_maxtries), 0, 105183550Szec "ARP resolution attempts before returning error"); 106195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, 107195699Srwatson &VNET_NAME(useloopback), 0, 108183550Szec "Use the loopback interface for local traffic"); 109195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, 110195699Srwatson &VNET_NAME(arp_proxyall), 0, 111183550Szec "Enable proxy ARP for all suitable requests"); 112196797SgnnSYSCTL_VNET_STRUCT(_net_link_ether_arp, OID_AUTO, stats, CTLFLAG_RW, 113196797Sgnn &VNET_NAME(arpstat), arpstat, 114196797Sgnn "ARP statistics (struct arpstat, net/if_arp.h)"); 11512693Sphk 11692723Salfredstatic void arp_init(void); 117186119Sqinglivoid arprequest(struct ifnet *, 11892723Salfred struct in_addr *, struct in_addr *, u_char *); 119111888Sjlemonstatic void arpintr(struct mbuf *); 12092723Salfredstatic void arptimer(void *); 12132350Seivind#ifdef INET 12292723Salfredstatic void in_arpinput(struct mbuf *); 12332350Seivind#endif 12412693Sphk 125193219Srwatsonstatic const struct netisr_handler arp_nh = { 126193219Srwatson .nh_name = "arp", 127193219Srwatson .nh_handler = arpintr, 128193219Srwatson .nh_proto = NETISR_ARP, 129193219Srwatson .nh_policy = NETISR_POLICY_SOURCE, 130193219Srwatson}; 131193219Srwatson 132186119Sqingli#ifdef AF_INET 133186119Sqinglivoid arp_ifscrub(struct ifnet *ifp, uint32_t addr); 134186119Sqingli 1351541Srgrimes/* 136186119Sqingli * called by in_ifscrub to remove entry from the table when 137186119Sqingli * the interface goes away 1381541Srgrimes */ 139186119Sqinglivoid 140186119Sqingliarp_ifscrub(struct ifnet *ifp, uint32_t addr) 1411541Srgrimes{ 142186119Sqingli struct sockaddr_in addr4; 1431541Srgrimes 144186119Sqingli bzero((void *)&addr4, sizeof(addr4)); 145186119Sqingli addr4.sin_len = sizeof(addr4); 146186119Sqingli addr4.sin_family = AF_INET; 147186119Sqingli addr4.sin_addr.s_addr = addr; 148191816Szec CURVNET_SET(ifp->if_vnet); 149186119Sqingli IF_AFDATA_LOCK(ifp); 150186119Sqingli lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR), 151186119Sqingli (struct sockaddr *)&addr4); 152186119Sqingli IF_AFDATA_UNLOCK(ifp); 153191816Szec CURVNET_RESTORE(); 1541541Srgrimes} 155186119Sqingli#endif 1561541Srgrimes 1571541Srgrimes/* 158186119Sqingli * Timeout routine. Age arp_tab entries periodically. 1591541Srgrimes */ 1605196Swollmanstatic void 161186119Sqingliarptimer(void *arg) 1621541Srgrimes{ 163186119Sqingli struct ifnet *ifp; 164210703Sbz struct llentry *lle; 1651541Srgrimes 166210703Sbz KASSERT(arg != NULL, ("%s: arg NULL", __func__)); 167210703Sbz lle = (struct llentry *)arg; 168186119Sqingli ifp = lle->lle_tbl->llt_ifp; 169196797Sgnn CURVNET_SET(ifp->if_vnet); 170186119Sqingli IF_AFDATA_LOCK(ifp); 171186119Sqingli LLE_WLOCK(lle); 172201544Sqingli if (lle->la_flags & LLE_STATIC) 173201544Sqingli LLE_WUNLOCK(lle); 174201544Sqingli else { 175201544Sqingli if (!callout_pending(&lle->la_timer) && 176201544Sqingli callout_active(&lle->la_timer)) { 177206481Sbz callout_stop(&lle->la_timer); 178206481Sbz LLE_REMREF(lle); 179201544Sqingli (void) llentry_free(lle); 180201544Sqingli ARPSTAT_INC(timeouts); 181201544Sqingli } 182198418Sqingli#ifdef DIAGNOSTIC 183201544Sqingli else { 184201544Sqingli struct sockaddr *l3addr = L3_ADDR(lle); 185201544Sqingli log(LOG_INFO, 186201544Sqingli "arptimer issue: %p, IPv4 address: \"%s\"\n", lle, 187201544Sqingli inet_ntoa( 188201544Sqingli ((const struct sockaddr_in *)l3addr)->sin_addr)); 189201544Sqingli } 190201544Sqingli#endif 1911541Srgrimes } 192186119Sqingli IF_AFDATA_UNLOCK(ifp); 193196797Sgnn CURVNET_RESTORE(); 1941541Srgrimes} 1951541Srgrimes 1961541Srgrimes/* 1971541Srgrimes * Broadcast an ARP request. Caller specifies: 1981541Srgrimes * - arp header source ip address 1991541Srgrimes * - arp header target ip address 2001541Srgrimes * - arp header source ethernet address 2011541Srgrimes */ 202186119Sqinglivoid 203186119Sqingliarprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, 204169454Srwatson u_char *enaddr) 2051541Srgrimes{ 206126936Smdodd struct mbuf *m; 207126936Smdodd struct arphdr *ah; 2081541Srgrimes struct sockaddr sa; 2091541Srgrimes 210186119Sqingli if (sip == NULL) { 211186119Sqingli /* XXX don't believe this can happen (or explain why) */ 212186119Sqingli /* 213186119Sqingli * The caller did not supply a source address, try to find 214186119Sqingli * a compatible one among those assigned to this interface. 215186119Sqingli */ 216186119Sqingli struct ifaddr *ifa; 217186119Sqingli 218186119Sqingli TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 219186119Sqingli if (!ifa->ifa_addr || 220186119Sqingli ifa->ifa_addr->sa_family != AF_INET) 221186119Sqingli continue; 222186119Sqingli sip = &SIN(ifa->ifa_addr)->sin_addr; 223186119Sqingli if (0 == ((sip->s_addr ^ tip->s_addr) & 224186119Sqingli SIN(ifa->ifa_netmask)->sin_addr.s_addr) ) 225186119Sqingli break; /* found it. */ 226186119Sqingli } 227186119Sqingli if (sip == NULL) { 228186119Sqingli printf("%s: cannot find matching address\n", __func__); 229186119Sqingli return; 230186119Sqingli } 231186119Sqingli } 232186119Sqingli 233111119Simp if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 2341541Srgrimes return; 235127261Smdodd m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + 236127261Smdodd 2*ifp->if_data.ifi_addrlen; 237127277Smdodd m->m_pkthdr.len = m->m_len; 238127277Smdodd MH_ALIGN(m, m->m_len); 239127277Smdodd ah = mtod(m, struct arphdr *); 240127261Smdodd bzero((caddr_t)ah, m->m_len); 241101090Srwatson#ifdef MAC 242173095Srwatson mac_netinet_arp_send(ifp, m); 243101090Srwatson#endif 24484931Sfjoe ah->ar_pro = htons(ETHERTYPE_IP); 24584931Sfjoe ah->ar_hln = ifp->if_addrlen; /* hardware address length */ 24684931Sfjoe ah->ar_pln = sizeof(struct in_addr); /* protocol address length */ 24784931Sfjoe ah->ar_op = htons(ARPOP_REQUEST); 248127261Smdodd bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln); 249127261Smdodd bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln); 250127261Smdodd bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln); 251127261Smdodd sa.sa_family = AF_ARP; 252127261Smdodd sa.sa_len = 2; 253127261Smdodd m->m_flags |= M_BCAST; 254191148Skmacy (*ifp->if_output)(ifp, m, &sa, NULL); 255196797Sgnn ARPSTAT_INC(txrequests); 2561541Srgrimes} 2571541Srgrimes 2581541Srgrimes/* 259128636Sluigi * Resolve an IP address into an ethernet address. 260128636Sluigi * On input: 261128636Sluigi * ifp is the interface we use 262175025Sjulian * rt0 is the route to the final destination (possibly useless) 263175025Sjulian * m is the mbuf. May be NULL if we don't have a packet. 264128636Sluigi * dst is the next hop, 265128636Sluigi * desten is where we want the address. 266128636Sluigi * 267128636Sluigi * On success, desten is filled in and the function returns 0; 268128636Sluigi * If the packet must be held pending resolution, we return EWOULDBLOCK 269128636Sluigi * On other errors, we return the corresponding error code. 270175025Sjulian * Note that m_freem() handles NULL. 2711541Srgrimes */ 2721541Srgrimesint 273128636Sluigiarpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, 274186119Sqingli struct sockaddr *dst, u_char *desten, struct llentry **lle) 2751541Srgrimes{ 276186119Sqingli struct llentry *la = 0; 277186200Skmacy u_int flags = 0; 278186119Sqingli int error, renew; 2791541Srgrimes 280186119Sqingli *lle = NULL; 281186119Sqingli if (m != NULL) { 282175025Sjulian if (m->m_flags & M_BCAST) { 283175025Sjulian /* broadcast */ 284175025Sjulian (void)memcpy(desten, 285175025Sjulian ifp->if_broadcastaddr, ifp->if_addrlen); 286175025Sjulian return (0); 287175025Sjulian } 288175025Sjulian if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) { 289175025Sjulian /* multicast */ 290175025Sjulian ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); 291175025Sjulian return (0); 292175025Sjulian } 2931541Srgrimes } 294186119Sqingli /* XXXXX 295183013Sjulian */ 296186119Sqingliretry: 297186200Skmacy IF_AFDATA_RLOCK(ifp); 298186119Sqingli la = lla_lookup(LLTABLE(ifp), flags, dst); 299186200Skmacy IF_AFDATA_RUNLOCK(ifp); 300186200Skmacy if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0) 301186200Skmacy && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) { 302186200Skmacy flags |= (LLE_CREATE | LLE_EXCLUSIVE); 303186200Skmacy IF_AFDATA_WLOCK(ifp); 304186200Skmacy la = lla_lookup(LLTABLE(ifp), flags, dst); 305186200Skmacy IF_AFDATA_WUNLOCK(ifp); 306186200Skmacy } 307148955Sglebius if (la == NULL) { 308186119Sqingli if (flags & LLE_CREATE) 309148955Sglebius log(LOG_DEBUG, 310148955Sglebius "arpresolve: can't allocate llinfo for %s\n", 311148955Sglebius inet_ntoa(SIN(dst)->sin_addr)); 312186119Sqingli m_freem(m); 313186119Sqingli return (EINVAL); 314186119Sqingli } 315149909Sglebius 316186119Sqingli if ((la->la_flags & LLE_VALID) && 317198111Sqingli ((la->la_flags & LLE_STATIC) || la->la_expire > time_second)) { 318186119Sqingli bcopy(&la->ll_addr, desten, ifp->if_addrlen); 31992802Sorion /* 32092802Sorion * If entry has an expiry time and it is approaching, 321186119Sqingli * see if we need to send an ARP request within this 322186119Sqingli * arpt_down interval. 32392802Sorion */ 324186119Sqingli if (!(la->la_flags & LLE_STATIC) && 325198111Sqingli time_second + la->la_preempt > la->la_expire) { 326186119Sqingli arprequest(ifp, NULL, 327186119Sqingli &SIN(dst)->sin_addr, IF_LLADDR(ifp)); 328149909Sglebius 329110544Sorion la->la_preempt--; 330186119Sqingli } 331186119Sqingli 332186119Sqingli *lle = la; 333186119Sqingli error = 0; 334186119Sqingli goto done; 335186119Sqingli } 336186119Sqingli 337186119Sqingli if (la->la_flags & LLE_STATIC) { /* should not happen! */ 338186119Sqingli log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n", 339186119Sqingli inet_ntoa(SIN(dst)->sin_addr)); 340186119Sqingli m_freem(m); 341186119Sqingli error = EINVAL; 342186119Sqingli goto done; 343186119Sqingli } 34492802Sorion 345198111Sqingli renew = (la->la_asked == 0 || la->la_expire != time_second); 346186119Sqingli if ((renew || m != NULL) && (flags & LLE_EXCLUSIVE) == 0) { 347186119Sqingli flags |= LLE_EXCLUSIVE; 348186119Sqingli LLE_RUNLOCK(la); 349186119Sqingli goto retry; 3501541Srgrimes } 3511541Srgrimes /* 3521541Srgrimes * There is an arptab entry, but no ethernet address 3531541Srgrimes * response yet. Replace the held mbuf with this 3541541Srgrimes * latest one. 3551541Srgrimes */ 356186119Sqingli if (m != NULL) { 357196797Sgnn if (la->la_hold != NULL) { 358175025Sjulian m_freem(la->la_hold); 359196797Sgnn ARPSTAT_INC(dropped); 360196797Sgnn } 361175025Sjulian la->la_hold = m; 362186119Sqingli if (renew == 0 && (flags & LLE_EXCLUSIVE)) { 363186119Sqingli flags &= ~LLE_EXCLUSIVE; 364186119Sqingli LLE_DOWNGRADE(la); 365186119Sqingli } 366186119Sqingli 367174699Skmacy } 368152188Sglebius /* 369152188Sglebius * Return EWOULDBLOCK if we have tried less than arp_maxtries. It 370152188Sglebius * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH 371152188Sglebius * if we have already sent arp_maxtries ARP requests. Retransmit the 372152188Sglebius * ARP request, but not faster than one request per second. 373152188Sglebius */ 374181803Sbz if (la->la_asked < V_arp_maxtries) 375152188Sglebius error = EWOULDBLOCK; /* First request. */ 376152188Sglebius else 377201416Snp error = rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) ? 378201416Snp EHOSTUNREACH : EHOSTDOWN; 379152188Sglebius 380186119Sqingli if (renew) { 381206481Sbz int canceled; 382206481Sbz 383186119Sqingli LLE_ADDREF(la); 384198301Sqingli la->la_expire = time_second + V_arpt_down; 385206481Sbz canceled = callout_reset(&la->la_timer, hz * V_arpt_down, 386206481Sbz arptimer, la); 387206481Sbz if (canceled) 388206481Sbz LLE_REMREF(la); 389166010Smaxim la->la_asked++; 390186119Sqingli LLE_WUNLOCK(la); 391186119Sqingli arprequest(ifp, NULL, &SIN(dst)->sin_addr, 392152188Sglebius IF_LLADDR(ifp)); 393186119Sqingli return (error); 394186119Sqingli } 395186119Sqinglidone: 396186119Sqingli if (flags & LLE_EXCLUSIVE) 397186119Sqingli LLE_WUNLOCK(la); 398186119Sqingli else 399186119Sqingli LLE_RUNLOCK(la); 400152188Sglebius return (error); 4011541Srgrimes} 4021541Srgrimes 4031541Srgrimes/* 4041541Srgrimes * Common length and type checks are done here, 4051541Srgrimes * then the protocol-specific routine is called. 4061541Srgrimes */ 40712693Sphkstatic void 408111888Sjlemonarpintr(struct mbuf *m) 4091541Srgrimes{ 410111888Sjlemon struct arphdr *ar; 4111541Srgrimes 412111888Sjlemon if (m->m_len < sizeof(struct arphdr) && 413111888Sjlemon ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) { 414111888Sjlemon log(LOG_ERR, "arp: runt packet -- m_pullup failed\n"); 415111888Sjlemon return; 416111888Sjlemon } 417111888Sjlemon ar = mtod(m, struct arphdr *); 4181541Srgrimes 419111888Sjlemon if (ntohs(ar->ar_hrd) != ARPHRD_ETHER && 420111888Sjlemon ntohs(ar->ar_hrd) != ARPHRD_IEEE802 && 421130407Sdfr ntohs(ar->ar_hrd) != ARPHRD_ARCNET && 422130407Sdfr ntohs(ar->ar_hrd) != ARPHRD_IEEE1394) { 423111888Sjlemon log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n", 424111888Sjlemon (unsigned char *)&ar->ar_hrd, ""); 425111888Sjlemon m_freem(m); 426111888Sjlemon return; 427111888Sjlemon } 4281541Srgrimes 429123768Sru if (m->m_len < arphdr_len(ar)) { 430123765Sru if ((m = m_pullup(m, arphdr_len(ar))) == NULL) { 431123765Sru log(LOG_ERR, "arp: runt packet\n"); 432123765Sru m_freem(m); 433123765Sru return; 434123765Sru } 435123765Sru ar = mtod(m, struct arphdr *); 436111888Sjlemon } 43757900Srwatson 438196797Sgnn ARPSTAT_INC(received); 439111888Sjlemon switch (ntohs(ar->ar_pro)) { 44032350Seivind#ifdef INET 441111888Sjlemon case ETHERTYPE_IP: 442111888Sjlemon in_arpinput(m); 443111888Sjlemon return; 44432350Seivind#endif 4451541Srgrimes } 446111888Sjlemon m_freem(m); 4471541Srgrimes} 4481541Srgrimes 44932350Seivind#ifdef INET 4501541Srgrimes/* 4511541Srgrimes * ARP for Internet protocols on 10 Mb/s Ethernet. 4521541Srgrimes * Algorithm is that given in RFC 826. 4531541Srgrimes * In addition, a sanity check is performed on the sender 4541541Srgrimes * protocol address, to catch impersonators. 4551541Srgrimes * We no longer handle negotiations for use of trailer protocol: 4561541Srgrimes * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent 4571541Srgrimes * along with IP replies if we wanted trailers sent to us, 4581541Srgrimes * and also sent them in response to IP replies. 4591541Srgrimes * This allowed either end to announce the desire to receive 4601541Srgrimes * trailer packets. 4611541Srgrimes * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, 4621541Srgrimes * but formerly didn't normally send requests. 4631541Srgrimes */ 46470699Salfredstatic int log_arp_wrong_iface = 1; 46582893Salfredstatic int log_arp_movements = 1; 466153513Sglebiusstatic int log_arp_permanent_modify = 1; 46770699Salfred 46870699SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW, 46970699Salfred &log_arp_wrong_iface, 0, 47070699Salfred "log arp packets arriving on the wrong interface"); 47182893SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_movements, CTLFLAG_RW, 47282893Salfred &log_arp_movements, 0, 47382966Salfred "log arp replies from MACs different than the one in the cache"); 474153513SglebiusSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_permanent_modify, CTLFLAG_RW, 475153513Sglebius &log_arp_permanent_modify, 0, 476153513Sglebius "log arp replies from MACs different than the one in the permanent arp entry"); 47770699Salfred 47882893Salfred 4791541Srgrimesstatic void 480169454Srwatsonin_arpinput(struct mbuf *m) 4811541Srgrimes{ 482126936Smdodd struct arphdr *ah; 483126936Smdodd struct ifnet *ifp = m->m_pkthdr.rcvif; 484186119Sqingli struct llentry *la = NULL; 485126936Smdodd struct rtentry *rt; 48684102Sjlemon struct ifaddr *ifa; 48784102Sjlemon struct in_ifaddr *ia; 488196738Sbz struct mbuf *hold; 4891541Srgrimes struct sockaddr sa; 4901541Srgrimes struct in_addr isaddr, itaddr, myaddr; 491142215Sglebius u_int8_t *enaddr = NULL; 492186119Sqingli int op, flags; 49384931Sfjoe int req_len; 494181824Sphilip int bridged = 0, is_bridge = 0; 495143314Sglebius int carp_match = 0; 496174559Skmacy struct sockaddr_in sin; 497174559Skmacy sin.sin_len = sizeof(struct sockaddr_in); 498174559Skmacy sin.sin_family = AF_INET; 499174703Skmacy sin.sin_addr.s_addr = 0; 500183550Szec 501155018Sthompsa if (ifp->if_bridge) 502146986Sthompsa bridged = 1; 503181824Sphilip if (ifp->if_type == IFT_BRIDGE) 504181824Sphilip is_bridge = 1; 505146986Sthompsa 50684931Sfjoe req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); 50784931Sfjoe if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) { 50874851Syar log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n"); 50974851Syar return; 51074851Syar } 51174851Syar 51284931Sfjoe ah = mtod(m, struct arphdr *); 51384931Sfjoe op = ntohs(ah->ar_op); 51484931Sfjoe (void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr)); 51584931Sfjoe (void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr)); 516134991Sglebius 517196797Sgnn if (op == ARPOP_REPLY) 518196797Sgnn ARPSTAT_INC(rxreplies); 519196797Sgnn 52084102Sjlemon /* 52184102Sjlemon * For a bridge, we want to check the address irrespective 52284102Sjlemon * of the receive interface. (This will change slightly 52384102Sjlemon * when we have clusters of interfaces). 524142215Sglebius * If the interface does not match, but the recieving interface 525142215Sglebius * is part of carp, we call carp_iamatch to see if this is a 526142215Sglebius * request for the virtual host ip. 527142215Sglebius * XXX: This is really ugly! 52884102Sjlemon */ 529194951Srwatson IN_IFADDR_RLOCK(); 530143314Sglebius LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { 531156409Sthompsa if (((bridged && ia->ia_ifp->if_bridge != NULL) || 532186119Sqingli ia->ia_ifp == ifp) && 533194820Srwatson itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { 534194820Srwatson ifa_ref(&ia->ia_ifa); 535194951Srwatson IN_IFADDR_RUNLOCK(); 536143314Sglebius goto match; 537194820Srwatson } 538143314Sglebius if (ifp->if_carp != NULL && 539211157Swill (*carp_iamatch_p)(ifp, ia, &isaddr, &enaddr) && 540143314Sglebius itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { 541143314Sglebius carp_match = 1; 542194820Srwatson ifa_ref(&ia->ia_ifa); 543194951Srwatson IN_IFADDR_RUNLOCK(); 544143314Sglebius goto match; 545143314Sglebius } 546143314Sglebius } 54784102Sjlemon LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) 548156409Sthompsa if (((bridged && ia->ia_ifp->if_bridge != NULL) || 549186119Sqingli ia->ia_ifp == ifp) && 550194820Srwatson isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { 551194820Srwatson ifa_ref(&ia->ia_ifa); 552194951Srwatson IN_IFADDR_RUNLOCK(); 55384102Sjlemon goto match; 554194820Srwatson } 555181824Sphilip 556181824Sphilip#define BDG_MEMBER_MATCHES_ARP(addr, ifp, ia) \ 557181824Sphilip (ia->ia_ifp->if_bridge == ifp->if_softc && \ 558181824Sphilip !bcmp(IF_LLADDR(ia->ia_ifp), IF_LLADDR(ifp), ifp->if_addrlen) && \ 559181824Sphilip addr == ia->ia_addr.sin_addr.s_addr) 56084102Sjlemon /* 561181824Sphilip * Check the case when bridge shares its MAC address with 562181824Sphilip * some of its children, so packets are claimed by bridge 563181824Sphilip * itself (bridge_input() does it first), but they are really 564181824Sphilip * meant to be destined to the bridge member. 565181824Sphilip */ 566181824Sphilip if (is_bridge) { 567181824Sphilip LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { 568181824Sphilip if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) { 569194820Srwatson ifa_ref(&ia->ia_ifa); 570181824Sphilip ifp = ia->ia_ifp; 571194951Srwatson IN_IFADDR_RUNLOCK(); 572181824Sphilip goto match; 573181824Sphilip } 574181824Sphilip } 575181824Sphilip } 576181824Sphilip#undef BDG_MEMBER_MATCHES_ARP 577194951Srwatson IN_IFADDR_RUNLOCK(); 578181824Sphilip 579181824Sphilip /* 58085223Sjlemon * No match, use the first inet address on the receive interface 58184102Sjlemon * as a dummy address for the rest of the function. 58284102Sjlemon */ 583194820Srwatson IF_ADDR_LOCK(ifp); 58485223Sjlemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 585160038Syar if (ifa->ifa_addr->sa_family == AF_INET) { 58685466Sjlemon ia = ifatoia(ifa); 587194820Srwatson ifa_ref(ifa); 588194837Srwatson IF_ADDR_UNLOCK(ifp); 58985466Sjlemon goto match; 59085466Sjlemon } 591194820Srwatson IF_ADDR_UNLOCK(ifp); 592194820Srwatson 59385466Sjlemon /* 59485466Sjlemon * If bridging, fall back to using any inet address. 59585466Sjlemon */ 596194951Srwatson IN_IFADDR_RLOCK(); 597194951Srwatson if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) { 598194951Srwatson IN_IFADDR_RUNLOCK(); 599128645Sluigi goto drop; 600194951Srwatson } 601194820Srwatson ifa_ref(&ia->ia_ifa); 602194951Srwatson IN_IFADDR_RUNLOCK(); 60384102Sjlemonmatch: 604142215Sglebius if (!enaddr) 605142215Sglebius enaddr = (u_int8_t *)IF_LLADDR(ifp); 60684102Sjlemon myaddr = ia->ia_addr.sin_addr; 607194820Srwatson ifa_free(&ia->ia_ifa); 608142215Sglebius if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen)) 609128645Sluigi goto drop; /* it's from me, ignore it. */ 61084931Sfjoe if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) { 6111541Srgrimes log(LOG_ERR, 61284931Sfjoe "arp: link address is broadcast for IP address %s!\n", 6137088Swollman inet_ntoa(isaddr)); 614128645Sluigi goto drop; 6151541Srgrimes } 616136441Srwatson /* 617136441Srwatson * Warn if another host is using the same IP address, but only if the 618136441Srwatson * IP address isn't 0.0.0.0, which is used for DHCP only, in which 619136441Srwatson * case we suppress the warning to avoid false positive complaints of 620136441Srwatson * potential misconfiguration. 621136441Srwatson */ 622150942Sthompsa if (!bridged && isaddr.s_addr == myaddr.s_addr && myaddr.s_addr != 0) { 6231541Srgrimes log(LOG_ERR, 624174256Syar "arp: %*D is using my IP address %s on %s!\n", 62584931Sfjoe ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 626174256Syar inet_ntoa(isaddr), ifp->if_xname); 6271541Srgrimes itaddr = myaddr; 628196797Sgnn ARPSTAT_INC(dupips); 6291541Srgrimes goto reply; 6301541Srgrimes } 631120626Sru if (ifp->if_flags & IFF_STATICARP) 632120626Sru goto reply; 633148955Sglebius 634186119Sqingli bzero(&sin, sizeof(sin)); 635186119Sqingli sin.sin_len = sizeof(struct sockaddr_in); 636186119Sqingli sin.sin_family = AF_INET; 637186119Sqingli sin.sin_addr = isaddr; 638186119Sqingli flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0; 639186119Sqingli flags |= LLE_EXCLUSIVE; 640186119Sqingli IF_AFDATA_LOCK(ifp); 641186119Sqingli la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin); 642186119Sqingli IF_AFDATA_UNLOCK(ifp); 643186119Sqingli if (la != NULL) { 644186119Sqingli /* the following is not an error when doing bridging */ 645211157Swill if (!bridged && la->lle_tbl->llt_ifp != ifp && !carp_match) { 646186119Sqingli if (log_arp_wrong_iface) 647186119Sqingli log(LOG_ERR, "arp: %s is on %s " 648186119Sqingli "but got reply from %*D on %s\n", 649186119Sqingli inet_ntoa(isaddr), 650186119Sqingli la->lle_tbl->llt_ifp->if_xname, 651186119Sqingli ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 652186119Sqingli ifp->if_xname); 653196738Sbz LLE_WUNLOCK(la); 654186119Sqingli goto reply; 655186119Sqingli } 656186119Sqingli if ((la->la_flags & LLE_VALID) && 657186119Sqingli bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { 658186119Sqingli if (la->la_flags & LLE_STATIC) { 659196738Sbz LLE_WUNLOCK(la); 660186119Sqingli log(LOG_ERR, 661186119Sqingli "arp: %*D attempts to modify permanent " 662186119Sqingli "entry for %s on %s\n", 663186119Sqingli ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 664186119Sqingli inet_ntoa(isaddr), ifp->if_xname); 665186119Sqingli goto reply; 666178888Sjulian } 667186119Sqingli if (log_arp_movements) { 668186119Sqingli log(LOG_INFO, "arp: %s moved from %*D " 669186119Sqingli "to %*D on %s\n", 670186119Sqingli inet_ntoa(isaddr), 671186119Sqingli ifp->if_addrlen, 672186119Sqingli (u_char *)&la->ll_addr, ":", 673186119Sqingli ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 674186119Sqingli ifp->if_xname); 675178888Sjulian } 676178888Sjulian } 677186119Sqingli 678186119Sqingli if (ifp->if_addrlen != ah->ar_hln) { 679196738Sbz LLE_WUNLOCK(la); 680186119Sqingli log(LOG_WARNING, 681186119Sqingli "arp from %*D: addr len: new %d, i/f %d (ignored)", 682186119Sqingli ifp->if_addrlen, (u_char *) ar_sha(ah), ":", 683186119Sqingli ah->ar_hln, ifp->if_addrlen); 684186119Sqingli goto reply; 685178888Sjulian } 686186119Sqingli (void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen); 687186119Sqingli la->la_flags |= LLE_VALID; 688178888Sjulian 689196995Snp EVENTHANDLER_INVOKE(arp_update_event, la); 690196995Snp 691186119Sqingli if (!(la->la_flags & LLE_STATIC)) { 692206481Sbz int canceled; 693206481Sbz 694206481Sbz LLE_ADDREF(la); 695198111Sqingli la->la_expire = time_second + V_arpt_keep; 696206481Sbz canceled = callout_reset(&la->la_timer, 697206481Sbz hz * V_arpt_keep, arptimer, la); 698206481Sbz if (canceled) 699206481Sbz LLE_REMREF(la); 70039389Sfenner } 701178888Sjulian la->la_asked = 0; 702181803Sbz la->la_preempt = V_arp_maxtries; 703196738Sbz hold = la->la_hold; 704196738Sbz if (hold != NULL) { 705196738Sbz la->la_hold = NULL; 706186119Sqingli memcpy(&sa, L3_ADDR(la), sizeof(sa)); 707186119Sqingli } 708196738Sbz LLE_WUNLOCK(la); 709196738Sbz if (hold != NULL) 710196738Sbz (*ifp->if_output)(ifp, hold, &sa, NULL); 711186119Sqingli } 712178888Sjulianreply: 713128645Sluigi if (op != ARPOP_REQUEST) 714128645Sluigi goto drop; 715196797Sgnn ARPSTAT_INC(rxrequests); 716186119Sqingli 7171541Srgrimes if (itaddr.s_addr == myaddr.s_addr) { 718178888Sjulian /* Shortcut.. the receiving interface is the target. */ 71984931Sfjoe (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 720142215Sglebius (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); 7211541Srgrimes } else { 722186317Sqingli struct llentry *lle = NULL; 7233282Swollman 724186317Sqingli sin.sin_addr = itaddr; 725197225Sqingli IF_AFDATA_LOCK(ifp); 726197225Sqingli lle = lla_lookup(LLTABLE(ifp), 0, (struct sockaddr *)&sin); 727197225Sqingli IF_AFDATA_UNLOCK(ifp); 728186317Sqingli 729197225Sqingli if ((lle != NULL) && (lle->la_flags & LLE_PUB)) { 730186317Sqingli (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 731186317Sqingli (void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln); 732186317Sqingli LLE_RUNLOCK(lle); 733197225Sqingli } else { 73463080Sdwmalone 735197225Sqingli if (lle != NULL) 736197225Sqingli LLE_RUNLOCK(lle); 737186317Sqingli 738197225Sqingli if (!V_arp_proxyall) 739197225Sqingli goto drop; 740197225Sqingli 741197225Sqingli sin.sin_addr = itaddr; 742197225Sqingli /* XXX MRT use table 0 for arp reply */ 743197225Sqingli rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); 744197225Sqingli if (!rt) 745197225Sqingli goto drop; 746197225Sqingli 747197225Sqingli /* 748197225Sqingli * Don't send proxies for nodes on the same interface 749197225Sqingli * as this one came out of, or we'll get into a fight 750197225Sqingli * over who claims what Ether address. 751197225Sqingli */ 752197225Sqingli if (!rt->rt_ifp || rt->rt_ifp == ifp) { 753197225Sqingli RTFREE_LOCKED(rt); 754197225Sqingli goto drop; 755197225Sqingli } 756185713Scsjp RTFREE_LOCKED(rt); 75763080Sdwmalone 758197225Sqingli (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 759197225Sqingli (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); 760197225Sqingli 761197225Sqingli /* 762197225Sqingli * Also check that the node which sent the ARP packet 763197225Sqingli * is on the the interface we expect it to be on. This 764197225Sqingli * avoids ARP chaos if an interface is connected to the 765197225Sqingli * wrong network. 766197225Sqingli */ 767197225Sqingli sin.sin_addr = isaddr; 768197225Sqingli 769197225Sqingli /* XXX MRT use table 0 for arp checks */ 770197225Sqingli rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); 771197225Sqingli if (!rt) 772197225Sqingli goto drop; 773197225Sqingli if (rt->rt_ifp != ifp) { 774197225Sqingli log(LOG_INFO, "arp_proxy: ignoring request" 775197225Sqingli " from %s via %s, expecting %s\n", 776197225Sqingli inet_ntoa(isaddr), ifp->if_xname, 777197225Sqingli rt->rt_ifp->if_xname); 778197225Sqingli RTFREE_LOCKED(rt); 779197225Sqingli goto drop; 780197225Sqingli } 781197225Sqingli RTFREE_LOCKED(rt); 782197225Sqingli 7834069Swollman#ifdef DEBUG_PROXY 784197225Sqingli printf("arp: proxying for %s\n", 785197225Sqingli inet_ntoa(itaddr)); 7864069Swollman#endif 787197225Sqingli } 7881541Srgrimes } 7891541Srgrimes 790166436Sbms if (itaddr.s_addr == myaddr.s_addr && 791166436Sbms IN_LINKLOCAL(ntohl(itaddr.s_addr))) { 792166436Sbms /* RFC 3927 link-local IPv4; always reply by broadcast. */ 793166436Sbms#ifdef DEBUG_LINKLOCAL 794166436Sbms printf("arp: sending reply for link-local addr %s\n", 795166436Sbms inet_ntoa(itaddr)); 796166436Sbms#endif 797166436Sbms m->m_flags |= M_BCAST; 798166436Sbms m->m_flags &= ~M_MCAST; 799166436Sbms } else { 800166436Sbms /* default behaviour; never reply by broadcast. */ 801166436Sbms m->m_flags &= ~(M_BCAST|M_MCAST); 802166436Sbms } 80384931Sfjoe (void)memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); 80484931Sfjoe (void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln); 80584931Sfjoe ah->ar_op = htons(ARPOP_REPLY); 80684931Sfjoe ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */ 807127261Smdodd m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln); 808127261Smdodd m->m_pkthdr.len = m->m_len; 809127261Smdodd sa.sa_family = AF_ARP; 810127261Smdodd sa.sa_len = 2; 811191148Skmacy (*ifp->if_output)(ifp, m, &sa, NULL); 812196797Sgnn ARPSTAT_INC(txreplies); 8131541Srgrimes return; 814128645Sluigi 815128645Sluigidrop: 816128645Sluigi m_freem(m); 8171541Srgrimes} 81832350Seivind#endif 8191541Srgrimes 8205195Swollmanvoid 821169454Srwatsonarp_ifinit(struct ifnet *ifp, struct ifaddr *ifa) 8225195Swollman{ 823186119Sqingli struct llentry *lle; 824186119Sqingli 825186411Sqingli if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) { 82684931Sfjoe arprequest(ifp, &IA_SIN(ifa)->sin_addr, 82784931Sfjoe &IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); 828186411Sqingli /* 829186411Sqingli * interface address is considered static entry 830186411Sqingli * because the output of the arp utility shows 831186411Sqingli * that L2 entry as permanent 832186411Sqingli */ 833186411Sqingli IF_AFDATA_LOCK(ifp); 834186411Sqingli lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | LLE_STATIC), 835186411Sqingli (struct sockaddr *)IA_SIN(ifa)); 836186411Sqingli IF_AFDATA_UNLOCK(ifp); 837186411Sqingli if (lle == NULL) 838186411Sqingli log(LOG_INFO, "arp_ifinit: cannot create arp " 839186411Sqingli "entry for interface address\n"); 840186411Sqingli else 841186411Sqingli LLE_RUNLOCK(lle); 842186411Sqingli } 843186119Sqingli ifa->ifa_rtrequest = NULL; 8445195Swollman} 84569152Sjlemon 846142215Sglebiusvoid 847169454Srwatsonarp_ifinit2(struct ifnet *ifp, struct ifaddr *ifa, u_char *enaddr) 848142215Sglebius{ 849142215Sglebius if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) 850142215Sglebius arprequest(ifp, &IA_SIN(ifa)->sin_addr, 851142215Sglebius &IA_SIN(ifa)->sin_addr, enaddr); 852186119Sqingli ifa->ifa_rtrequest = NULL; 853142215Sglebius} 854142215Sglebius 855190787Szecstatic void 856190787Szecarp_init(void) 857190787Szec{ 858190787Szec 859193219Srwatson netisr_register(&arp_nh); 86069152Sjlemon} 86169152SjlemonSYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); 862