if_ether.c revision 44078
153475Sobrien/* 253475Sobrien * Copyright (c) 1982, 1986, 1988, 1993 353451Speter * The Regents of the University of California. All rights reserved. 453475Sobrien * 553475Sobrien * Redistribution and use in source and binary forms, with or without 653475Sobrien * modification, are permitted provided that the following conditions 753475Sobrien * are met: 853475Sobrien * 1. Redistributions of source code must retain the above copyright 953451Speter * notice, this list of conditions and the following disclaimer. 1053451Speter * 2. Redistributions in binary form must reproduce the above copyright 1153451Speter * notice, this list of conditions and the following disclaimer in the 1253451Speter * documentation and/or other materials provided with the distribution. 1353451Speter * 3. All advertising materials mentioning features or use of this software 1453451Speter * must display the following acknowledgement: 1553451Speter * This product includes software developed by the University of 1653451Speter * California, Berkeley and its contributors. 1753451Speter * 4. Neither the name of the University nor the names of its contributors 1853451Speter * may be used to endorse or promote products derived from this software 1953451Speter * without specific prior written permission. 2053475Sobrien * 2153475Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2253451Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2353475Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2453475Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2553475Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2653475Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2753475Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2853475Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2953451Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3053451Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3153475Sobrien * SUCH DAMAGE. 3253475Sobrien * 3353475Sobrien * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 3453475Sobrien * $Id: if_ether.c,v 1.52 1999/01/19 23:17:03 fenner Exp $ 3553451Speter */ 3653451Speter 3753475Sobrien/* 3853475Sobrien * Ethernet address resolution protocol. 3953475Sobrien * TODO: 4053451Speter * add "inuse/lock" bit (or ref. count) along with valid bit 4153451Speter */ 4253475Sobrien 4353475Sobrien#include "opt_inet.h" 4453451Speter#include "opt_bdg.h" 4553475Sobrien 4653475Sobrien#include <sys/param.h> 4753475Sobrien#include <sys/kernel.h> 4853475Sobrien#include <sys/queue.h> 4953475Sobrien#include <sys/sysctl.h> 5053475Sobrien#include <sys/systm.h> 5153475Sobrien#include <sys/mbuf.h> 5253451Speter#include <sys/malloc.h> 5353451Speter#include <sys/socket.h> 5453475Sobrien#include <sys/syslog.h> 5553475Sobrien 5653475Sobrien#include <net/if.h> 5753475Sobrien#include <net/if_dl.h> 5853451Speter#include <net/route.h> 5953451Speter#include <net/netisr.h> 6053451Speter 6153451Speter#include <netinet/in.h> 6253451Speter#include <netinet/in_var.h> 6353451Speter#include <netinet/if_ether.h> 6453451Speter 6553451Speter#define SIN(s) ((struct sockaddr_in *)s) 6653475Sobrien#define SDL(s) ((struct sockaddr_dl *)s) 6753451Speter 6853451SpeterSYSCTL_DECL(_net_link_ether); 6953451SpeterSYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); 7053451Speter 7153451Speter/* timer values */ 7253451Speterstatic int arpt_prune = (5*60*1); /* walk list every 5 minutes */ 7353451Speterstatic int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ 7453451Speterstatic int arpt_down = 20; /* once declared down, don't send for 20 sec */ 7553451Speter 7653451SpeterSYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, 7753451Speter &arpt_prune, 0, ""); 7853451SpeterSYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 7953451Speter &arpt_keep, 0, ""); 8053451SpeterSYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW, 8153475Sobrien &arpt_down, 0, ""); 8253475Sobrien 8353475Sobrien#define rt_expire rt_rmx.rmx_expire 8453475Sobrien 8553475Sobrienstruct llinfo_arp { 8653475Sobrien LIST_ENTRY(llinfo_arp) la_le; 8753475Sobrien struct rtentry *la_rt; 8853475Sobrien struct mbuf *la_hold; /* last packet until resolved/timeout */ 8953475Sobrien long la_asked; /* last time we QUERIED for this addr */ 9053475Sobrien#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */ 9153475Sobrien}; 9253475Sobrien 9353475Sobrienstatic LIST_HEAD(, llinfo_arp) llinfo_arp; 9453475Sobrien 9553475Sobrienstruct ifqueue arpintrq = {0, 0, 0, 50}; 9653475Sobrienstatic int arp_inuse, arp_allocated; 9753475Sobrien 9853475Sobrienstatic int arp_maxtries = 5; 9953475Sobrienstatic int useloopback = 1; /* use loopback interface for local traffic */ 10053475Sobrienstatic int arp_proxyall = 0; 10153475Sobrien 10253475SobrienSYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, 10353451Speter &arp_maxtries, 0, ""); 10453451SpeterSYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, 10553451Speter &useloopback, 0, ""); 10653451SpeterSYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, 10753451Speter &arp_proxyall, 0, ""); 10853451Speter 10953451Speterstatic void arp_rtrequest __P((int, struct rtentry *, struct sockaddr *)); 11053451Speterstatic void arprequest __P((struct arpcom *, 11153451Speter struct in_addr *, struct in_addr *, u_char *)); 11253451Speterstatic void arpintr __P((void)); 11353451Speterstatic void arptfree __P((struct llinfo_arp *)); 11453475Sobrienstatic void arptimer __P((void *)); 11553451Speterstatic struct llinfo_arp 11653451Speter *arplookup __P((u_long, int, int)); 11753451Speter#ifdef INET 11853475Sobrienstatic void in_arpinput __P((struct mbuf *)); 11953451Speter#endif 12053451Speter 12153451Speter/* 12253451Speter * Timeout routine. Age arp_tab entries periodically. 12353451Speter */ 12453451Speter/* ARGSUSED */ 12553475Sobrienstatic void 12653451Speterarptimer(ignored_arg) 12753475Sobrien void *ignored_arg; 12853475Sobrien{ 12953475Sobrien int s = splnet(); 13053475Sobrien register struct llinfo_arp *la = llinfo_arp.lh_first; 13153475Sobrien struct llinfo_arp *ola; 13253451Speter 13353475Sobrien timeout(arptimer, (caddr_t)0, arpt_prune * hz); 13453475Sobrien while ((ola = la) != 0) { 13553475Sobrien register struct rtentry *rt = la->la_rt; 13653475Sobrien la = la->la_le.le_next; 13753475Sobrien if (rt->rt_expire && rt->rt_expire <= time_second) 13853475Sobrien arptfree(ola); /* timer has expired, clear */ 13953475Sobrien } 14053475Sobrien splx(s); 14153475Sobrien} 14253451Speter 14353451Speter/* 14453451Speter * Parallel to llc_rtrequest. 14553451Speter */ 14653475Sobrienstatic void 14753451Speterarp_rtrequest(req, rt, sa) 14853475Sobrien int req; 14953475Sobrien register struct rtentry *rt; 15053475Sobrien struct sockaddr *sa; 15153475Sobrien{ 15253475Sobrien register struct sockaddr *gate = rt->rt_gateway; 15353451Speter register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; 15453451Speter static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 15553451Speter static int arpinit_done; 15653451Speter 15753475Sobrien if (!arpinit_done) { 15853475Sobrien arpinit_done = 1; 15953475Sobrien LIST_INIT(&llinfo_arp); 16053475Sobrien timeout(arptimer, (caddr_t)0, hz); 16153451Speter } 16253451Speter if (rt->rt_flags & RTF_GATEWAY) 16353475Sobrien return; 16453451Speter switch (req) { 16553475Sobrien 16653451Speter case RTM_ADD: 16753451Speter /* 16853475Sobrien * XXX: If this is a manually added route to interface 16953451Speter * such as older version of routed or gated might provide, 17053451Speter * restore cloning bit. 17153451Speter */ 17253451Speter if ((rt->rt_flags & RTF_HOST) == 0 && 17353451Speter SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 17453451Speter rt->rt_flags |= RTF_CLONING; 17553451Speter if (rt->rt_flags & RTF_CLONING) { 17653451Speter /* 17753451Speter * Case 1: This route should come from a route to iface. 17853451Speter */ 17953451Speter rt_setgate(rt, rt_key(rt), 18053451Speter (struct sockaddr *)&null_sdl); 18153451Speter gate = rt->rt_gateway; 18253451Speter SDL(gate)->sdl_type = rt->rt_ifp->if_type; 18353451Speter SDL(gate)->sdl_index = rt->rt_ifp->if_index; 18453451Speter rt->rt_expire = time_second; 18553451Speter break; 18653475Sobrien } 18753475Sobrien /* Announce a new entry if requested. */ 18853475Sobrien if (rt->rt_flags & RTF_ANNOUNCE) 18953475Sobrien arprequest((struct arpcom *)rt->rt_ifp, 19053451Speter &SIN(rt_key(rt))->sin_addr, 19153451Speter &SIN(rt_key(rt))->sin_addr, 19253475Sobrien (u_char *)LLADDR(SDL(gate))); 19353451Speter /*FALLTHROUGH*/ 19453451Speter case RTM_RESOLVE: 19553451Speter if (gate->sa_family != AF_LINK || 19653451Speter gate->sa_len < sizeof(null_sdl)) { 19753451Speter log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); 19853475Sobrien break; 19953475Sobrien } 20053451Speter SDL(gate)->sdl_type = rt->rt_ifp->if_type; 20153451Speter SDL(gate)->sdl_index = rt->rt_ifp->if_index; 20253451Speter if (la != 0) 20353451Speter break; /* This happens on a route change */ 20453451Speter /* 20553451Speter * Case 2: This route may come from cloning, or a manual route 20653475Sobrien * add with a LL address. 20753475Sobrien */ 20853451Speter R_Malloc(la, struct llinfo_arp *, sizeof(*la)); 20953451Speter rt->rt_llinfo = (caddr_t)la; 21053475Sobrien if (la == 0) { 21153451Speter log(LOG_DEBUG, "arp_rtrequest: malloc failed\n"); 21253451Speter break; 21353451Speter } 21453451Speter arp_inuse++, arp_allocated++; 21553475Sobrien Bzero(la, sizeof(*la)); 21653475Sobrien la->la_rt = rt; 21753475Sobrien rt->rt_flags |= RTF_LLINFO; 21853475Sobrien LIST_INSERT_HEAD(&llinfo_arp, la, la_le); 21953451Speter 22053451Speter#ifdef INET 22153475Sobrien /* 22253451Speter * This keeps the multicast addresses from showing up 22353451Speter * in `arp -a' listings as unresolved. It's not actually 22453475Sobrien * functional. Then the same for broadcast. 22553451Speter */ 22653451Speter if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) { 22753475Sobrien ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr, 22853451Speter LLADDR(SDL(gate))); 22953451Speter SDL(gate)->sdl_alen = 6; 23053451Speter rt->rt_expire = 0; 23153451Speter } 23253451Speter if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { 23353451Speter memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6); 23453451Speter SDL(gate)->sdl_alen = 6; 23553451Speter rt->rt_expire = 0; 23653451Speter } 23753451Speter#endif 23853451Speter 23953451Speter if (SIN(rt_key(rt))->sin_addr.s_addr == 24053451Speter (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { 24153451Speter /* 24253451Speter * This test used to be 24353451Speter * if (loif.if_flags & IFF_UP) 24453451Speter * It allowed local traffic to be forced 24553475Sobrien * through the hardware by configuring the loopback down. 24653475Sobrien * However, it causes problems during network configuration 24753475Sobrien * for boards that can't receive packets they send. 24853475Sobrien * It is now necessary to clear "useloopback" and remove 24953451Speter * the route to force traffic out to the hardware. 25053451Speter */ 25153475Sobrien rt->rt_expire = 0; 25253451Speter Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr, 25353451Speter LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); 25453451Speter if (useloopback) 25553451Speter rt->rt_ifp = loif; 25653451Speter 25753451Speter } 25853475Sobrien break; 25953475Sobrien 26053451Speter case RTM_DELETE: 26153451Speter if (la == 0) 26253451Speter break; 26353451Speter arp_inuse--; 26453451Speter LIST_REMOVE(la, la_le); 26553451Speter rt->rt_llinfo = 0; 26653475Sobrien rt->rt_flags &= ~RTF_LLINFO; 26753475Sobrien if (la->la_hold) 26853451Speter m_freem(la->la_hold); 26953451Speter Free((caddr_t)la); 27053451Speter } 27153451Speter} 27253451Speter 27353451Speter/* 27453451Speter * Broadcast an ARP request. Caller specifies: 27553451Speter * - arp header source ip address 27653451Speter * - arp header target ip address 27753451Speter * - arp header source ethernet address 27853451Speter */ 27953451Speterstatic void 28053451Speterarprequest(ac, sip, tip, enaddr) 28153475Sobrien register struct arpcom *ac; 28253475Sobrien register struct in_addr *sip, *tip; 28353451Speter register u_char *enaddr; 28453475Sobrien{ 28553475Sobrien register struct mbuf *m; 28653475Sobrien register struct ether_header *eh; 28753451Speter register struct ether_arp *ea; 28853451Speter struct sockaddr sa; 28953451Speter 29053451Speter if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 29153451Speter return; 29253451Speter m->m_len = sizeof(*ea); 29353451Speter m->m_pkthdr.len = sizeof(*ea); 29453475Sobrien MH_ALIGN(m, sizeof(*ea)); 29553475Sobrien ea = mtod(m, struct ether_arp *); 29653475Sobrien eh = (struct ether_header *)sa.sa_data; 29753475Sobrien bzero((caddr_t)ea, sizeof (*ea)); 29853451Speter (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)); 29953451Speter eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */ 30053451Speter ea->arp_hrd = htons(ARPHRD_ETHER); 30153451Speter ea->arp_pro = htons(ETHERTYPE_IP); 30253451Speter ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ 30353451Speter ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ 30453451Speter ea->arp_op = htons(ARPOP_REQUEST); 30553451Speter (void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha)); 30653451Speter (void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa)); 30753451Speter (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa)); 30853451Speter sa.sa_family = AF_UNSPEC; 30953451Speter sa.sa_len = sizeof(sa); 31053451Speter (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); 31153451Speter} 31253451Speter 31353451Speter/* 31453451Speter * Resolve an IP address into an ethernet address. If success, 31553451Speter * desten is filled in. If there is no entry in arptab, 31653451Speter * set one up and broadcast a request for the IP address. 31753451Speter * Hold onto this mbuf and resend it once the address 31853451Speter * is finally resolved. A return value of 1 indicates 31953451Speter * that desten has been filled in and the packet should be sent 32053451Speter * normally; a 0 return indicates that the packet has been 32153451Speter * taken over here, either now or for later transmission. 32253451Speter */ 32353451Speterint 32453451Speterarpresolve(ac, rt, m, dst, desten, rt0) 32553451Speter register struct arpcom *ac; 32653451Speter register struct rtentry *rt; 32753451Speter struct mbuf *m; 32853451Speter register struct sockaddr *dst; 32953451Speter register u_char *desten; 33053451Speter struct rtentry *rt0; 33153451Speter{ 33253451Speter register struct llinfo_arp *la = 0; 33353451Speter struct sockaddr_dl *sdl; 33453451Speter 33553451Speter if (m->m_flags & M_BCAST) { /* broadcast */ 33653451Speter (void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr)); 33753451Speter return (1); 33853451Speter } 33953451Speter if (m->m_flags & M_MCAST) { /* multicast */ 34053475Sobrien ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); 34153475Sobrien return(1); 34253475Sobrien } 34353475Sobrien if (rt) 34453475Sobrien la = (struct llinfo_arp *)rt->rt_llinfo; 34553475Sobrien if (la == 0) { 34653451Speter la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); 34753451Speter if (la) 34853451Speter rt = la->la_rt; 34953451Speter } 35053451Speter if (la == 0 || rt == 0) { 35153475Sobrien log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n", 35253475Sobrien inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "", 35353451Speter rt ? "rt" : ""); 35453451Speter m_freem(m); 35553451Speter return (0); 35653451Speter } 35753475Sobrien sdl = SDL(rt->rt_gateway); 35853475Sobrien /* 35953451Speter * Check the address family and length is valid, the address 36053451Speter * is resolved; otherwise, try to resolve. 36153451Speter */ 36253451Speter if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && 36353451Speter sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { 36453451Speter bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 36553451Speter return 1; 36653451Speter } 36753451Speter /* 36853451Speter * There is an arptab entry, but no ethernet address 36953451Speter * response yet. Replace the held mbuf with this 37053451Speter * latest one. 37153451Speter */ 37253451Speter if (la->la_hold) 37353451Speter m_freem(la->la_hold); 37453451Speter la->la_hold = m; 37553451Speter if (rt->rt_expire) { 37653451Speter rt->rt_flags &= ~RTF_REJECT; 37753451Speter if (la->la_asked == 0 || rt->rt_expire != time_second) { 37853451Speter rt->rt_expire = time_second; 37953475Sobrien if (la->la_asked++ < arp_maxtries) 38053475Sobrien arprequest(ac, 38153451Speter &SIN(rt->rt_ifa->ifa_addr)->sin_addr, 38253451Speter &SIN(dst)->sin_addr, ac->ac_enaddr); 38353451Speter else { 38453451Speter rt->rt_flags |= RTF_REJECT; 38553451Speter rt->rt_expire += arpt_down; 38653475Sobrien la->la_asked = 0; 38753451Speter } 38853451Speter 38953451Speter } 39053451Speter } 39153451Speter return (0); 39253451Speter} 39353451Speter 39453451Speter/* 39553451Speter * Common length and type checks are done here, 39653451Speter * then the protocol-specific routine is called. 39753475Sobrien */ 39853451Speterstatic void 39953451Speterarpintr() 40053451Speter{ 40153451Speter register struct mbuf *m; 40253451Speter register struct arphdr *ar; 40353451Speter int s; 40453451Speter 40553451Speter while (arpintrq.ifq_head) { 40653451Speter s = splimp(); 40753451Speter IF_DEQUEUE(&arpintrq, m); 40853451Speter splx(s); 40953451Speter if (m == 0 || (m->m_flags & M_PKTHDR) == 0) 41053451Speter panic("arpintr"); 41153451Speter if (m->m_len >= sizeof(struct arphdr) && 41253451Speter (ar = mtod(m, struct arphdr *)) && 41353475Sobrien ntohs(ar->ar_hrd) == ARPHRD_ETHER && 41453475Sobrien m->m_len >= 41553451Speter sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 41653451Speter 41753451Speter switch (ntohs(ar->ar_pro)) { 41853451Speter 41953451Speter#ifdef INET 42053475Sobrien case ETHERTYPE_IP: 42153451Speter in_arpinput(m); 42253451Speter continue; 42353451Speter#endif 42453451Speter } 42553451Speter m_freem(m); 42653451Speter } 42753451Speter} 42853451Speter 42953451SpeterNETISR_SET(NETISR_ARP, arpintr); 43053451Speter 43153475Sobrien 43253451Speter#ifdef INET 43353451Speter/* 43453451Speter * ARP for Internet protocols on 10 Mb/s Ethernet. 43553451Speter * Algorithm is that given in RFC 826. 43653451Speter * In addition, a sanity check is performed on the sender 43753451Speter * protocol address, to catch impersonators. 43853451Speter * We no longer handle negotiations for use of trailer protocol: 43953451Speter * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent 44053475Sobrien * along with IP replies if we wanted trailers sent to us, 44153475Sobrien * and also sent them in response to IP replies. 44253475Sobrien * This allowed either end to announce the desire to receive 44353475Sobrien * trailer packets. 44453475Sobrien * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, 44553475Sobrien * but formerly didn't normally send requests. 44653475Sobrien */ 44753475Sobrienstatic void 44853475Sobrienin_arpinput(m) 44953475Sobrien struct mbuf *m; 45053475Sobrien{ 45153475Sobrien register struct ether_arp *ea; 45253475Sobrien register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; 45353475Sobrien struct ether_header *eh; 45453475Sobrien register struct llinfo_arp *la = 0; 45553475Sobrien register struct rtentry *rt; 45653475Sobrien struct in_ifaddr *ia, *maybe_ia = 0; 45753475Sobrien struct sockaddr_dl *sdl; 45853475Sobrien struct sockaddr sa; 45953475Sobrien struct in_addr isaddr, itaddr, myaddr; 46053475Sobrien int op; 46153475Sobrien 46253475Sobrien ea = mtod(m, struct ether_arp *); 46353475Sobrien op = ntohs(ea->arp_op); 46453475Sobrien (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); 46553475Sobrien (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); 46653475Sobrien for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) 46753475Sobrien#ifdef BRIDGE 46853475Sobrien /* 46953475Sobrien * For a bridge, we want to check the address irrespective 47053475Sobrien * of the receive interface. (This will change slightly 47153475Sobrien * when we have clusters of interfaces). 47253475Sobrien */ 47353451Speter { 47453451Speter#else 47553451Speter if (ia->ia_ifp == &ac->ac_if) { 47653451Speter#endif 47753451Speter maybe_ia = ia; 47853451Speter if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || 47953451Speter (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) 48053475Sobrien break; 48153451Speter } 48253451Speter if (maybe_ia == 0) { 48353451Speter m_freem(m); 48453451Speter return; 48553451Speter } 48653451Speter myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; 48753451Speter if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, 48853451Speter sizeof (ea->arp_sha))) { 48953451Speter m_freem(m); /* it's from me, ignore it. */ 49053451Speter return; 49153451Speter } 49253451Speter if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, 49353451Speter sizeof (ea->arp_sha))) { 49453451Speter log(LOG_ERR, 49553451Speter "arp: ether address is broadcast for IP address %s!\n", 49653451Speter inet_ntoa(isaddr)); 49753451Speter m_freem(m); 49853451Speter return; 49953451Speter } 50053451Speter if (isaddr.s_addr == myaddr.s_addr) { 50153451Speter log(LOG_ERR, 50253451Speter "arp: %6D is using my IP address %s!\n", 50353451Speter ea->arp_sha, ":", inet_ntoa(isaddr)); 50453451Speter itaddr = myaddr; 50553451Speter goto reply; 50653451Speter } 50753451Speter la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); 50853451Speter if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { 50953451Speter#ifndef BRIDGE /* the following is not an error when doing bridging */ 51053451Speter if (rt->rt_ifp != &ac->ac_if) { 51153475Sobrien log(LOG_ERR, "arp: %s is on %s%d but got reply from %6D on %s%d\n", 51253475Sobrien inet_ntoa(isaddr), 51353475Sobrien rt->rt_ifp->if_name, rt->rt_ifp->if_unit, 51453475Sobrien ea->arp_sha, ":", 51553475Sobrien ac->ac_if.if_name, ac->ac_if.if_unit); 51653475Sobrien goto reply; 51753475Sobrien } 51853451Speter#endif 51953451Speter if (sdl->sdl_alen && 52053451Speter bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) 52153451Speter if (rt->rt_expire) 52253451Speter log(LOG_INFO, "arp: %s moved from %6D to %6D on %s%d\n", 52353451Speter inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":", 52453451Speter ea->arp_sha, ":", 52553451Speter ac->ac_if.if_name, ac->ac_if.if_unit); 52653451Speter else { 52753451Speter log(LOG_ERR, 52853451Speter "arp: %6D attempts to modify permanent entry for %s on %s%d", 52953451Speter ea->arp_sha, ":", inet_ntoa(isaddr), 53053451Speter ac->ac_if.if_name, ac->ac_if.if_unit); 53153451Speter goto reply; 53253451Speter } 53353451Speter (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); 53453451Speter sdl->sdl_alen = sizeof(ea->arp_sha); 53553451Speter if (rt->rt_expire) 53653451Speter rt->rt_expire = time_second + arpt_keep; 53753451Speter rt->rt_flags &= ~RTF_REJECT; 53853451Speter la->la_asked = 0; 53953451Speter if (la->la_hold) { 54053451Speter (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold, 54153451Speter rt_key(rt), rt); 54253451Speter la->la_hold = 0; 54353451Speter } 54453451Speter } 54553451Speterreply: 54653451Speter if (op != ARPOP_REQUEST) { 54753451Speter m_freem(m); 54853451Speter return; 54953451Speter } 55053451Speter if (itaddr.s_addr == myaddr.s_addr) { 55153451Speter /* I am the target */ 55253451Speter (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); 55353451Speter (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); 55453451Speter } else { 55553451Speter la = arplookup(itaddr.s_addr, 0, SIN_PROXY); 55653451Speter if (la == NULL) { 55753451Speter struct sockaddr_in sin; 55853451Speter 55953451Speter if (!arp_proxyall) { 56053451Speter m_freem(m); 56153451Speter return; 56253451Speter } 56353451Speter 56453451Speter bzero(&sin, sizeof sin); 56553451Speter sin.sin_family = AF_INET; 56653451Speter sin.sin_len = sizeof sin; 56753451Speter sin.sin_addr = itaddr; 56853451Speter 56953451Speter rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 57053451Speter if (!rt) { 57153451Speter m_freem(m); 57253451Speter return; 57353451Speter } 57453451Speter /* 57553451Speter * Don't send proxies for nodes on the same interface 57653451Speter * as this one came out of, or we'll get into a fight 57753451Speter * over who claims what Ether address. 57853451Speter */ 57953451Speter if (rt->rt_ifp == &ac->ac_if) { 58053451Speter rtfree(rt); 58153451Speter m_freem(m); 58253451Speter return; 58353451Speter } 58453451Speter (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); 58553451Speter (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); 58653451Speter rtfree(rt); 58753451Speter#ifdef DEBUG_PROXY 58853451Speter printf("arp: proxying for %s\n", 58953451Speter inet_ntoa(itaddr)); 59053451Speter#endif 59153451Speter } else { 59253451Speter rt = la->la_rt; 59353451Speter (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); 59453451Speter sdl = SDL(rt->rt_gateway); 59553475Sobrien (void)memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha)); 596 } 597 } 598 599 (void)memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa)); 600 (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa)); 601 ea->arp_op = htons(ARPOP_REPLY); 602 ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ 603 eh = (struct ether_header *)sa.sa_data; 604 (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); 605 eh->ether_type = htons(ETHERTYPE_ARP); 606 sa.sa_family = AF_UNSPEC; 607 sa.sa_len = sizeof(sa); 608 (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); 609 return; 610} 611#endif 612 613/* 614 * Free an arp entry. 615 */ 616static void 617arptfree(la) 618 register struct llinfo_arp *la; 619{ 620 register struct rtentry *rt = la->la_rt; 621 register struct sockaddr_dl *sdl; 622 if (rt == 0) 623 panic("arptfree"); 624 if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && 625 sdl->sdl_family == AF_LINK) { 626 sdl->sdl_alen = 0; 627 la->la_asked = 0; 628 rt->rt_flags &= ~RTF_REJECT; 629 return; 630 } 631 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 632 0, (struct rtentry **)0); 633} 634/* 635 * Lookup or enter a new address in arptab. 636 */ 637static struct llinfo_arp * 638arplookup(addr, create, proxy) 639 u_long addr; 640 int create, proxy; 641{ 642 register struct rtentry *rt; 643 static struct sockaddr_inarp sin = {sizeof(sin), AF_INET }; 644 const char *why = 0; 645 646 sin.sin_addr.s_addr = addr; 647 sin.sin_other = proxy ? SIN_PROXY : 0; 648 rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); 649 if (rt == 0) 650 return (0); 651 rt->rt_refcnt--; 652 653 if (rt->rt_flags & RTF_GATEWAY) 654 why = "host is not on local network"; 655 else if ((rt->rt_flags & RTF_LLINFO) == 0) 656 why = "could not allocate llinfo"; 657 else if (rt->rt_gateway->sa_family != AF_LINK) 658 why = "gateway route is not ours"; 659 660 if (why && create) { 661 log(LOG_DEBUG, "arplookup %s failed: %s\n", 662 inet_ntoa(sin.sin_addr), why); 663 return 0; 664 } else if (why) { 665 return 0; 666 } 667 return ((struct llinfo_arp *)rt->rt_llinfo); 668} 669 670void 671arp_ifinit(ac, ifa) 672 struct arpcom *ac; 673 struct ifaddr *ifa; 674{ 675 if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) 676 arprequest(ac, &IA_SIN(ifa)->sin_addr, 677 &IA_SIN(ifa)->sin_addr, ac->ac_enaddr); 678 ifa->ifa_rtrequest = arp_rtrequest; 679 ifa->ifa_flags |= RTF_CLONING; 680} 681