1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes /* 38df8bae1dSRodney W. Grimes * Ethernet address resolution protocol. 39df8bae1dSRodney W. Grimes * TODO: 40df8bae1dSRodney W. Grimes * add "inuse/lock" bit (or ref. count) along with valid bit 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 431d5e9e22SEivind Eklund #include "opt_inet.h" 44b715f178SLuigi Rizzo #include "opt_bdg.h" 451d5e9e22SEivind Eklund 46df8bae1dSRodney W. Grimes #include <sys/param.h> 47df8bae1dSRodney W. Grimes #include <sys/kernel.h> 48ce02431fSDoug Rabson #include <sys/queue.h> 49885f1aa4SPoul-Henning Kamp #include <sys/sysctl.h> 50885f1aa4SPoul-Henning Kamp #include <sys/systm.h> 51885f1aa4SPoul-Henning Kamp #include <sys/mbuf.h> 52885f1aa4SPoul-Henning Kamp #include <sys/malloc.h> 534458ac71SBruce Evans #include <sys/socket.h> 54885f1aa4SPoul-Henning Kamp #include <sys/syslog.h> 55df8bae1dSRodney W. Grimes 56df8bae1dSRodney W. Grimes #include <net/if.h> 57df8bae1dSRodney W. Grimes #include <net/if_dl.h> 58722012ccSJulian Elischer #include <net/if_types.h> 59df8bae1dSRodney W. Grimes #include <net/route.h> 60748e0b0aSGarrett Wollman #include <net/netisr.h> 61b149dd6cSLarry Lile #include <net/if_llc.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #include <netinet/in.h> 64df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 65df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 66df8bae1dSRodney W. Grimes 67fda82fc2SJulian Elischer #include <net/iso88025.h> 68fda82fc2SJulian Elischer 69df8bae1dSRodney W. Grimes #define SIN(s) ((struct sockaddr_in *)s) 70df8bae1dSRodney W. Grimes #define SDL(s) ((struct sockaddr_dl *)s) 71df8bae1dSRodney W. Grimes 72ce02431fSDoug Rabson SYSCTL_DECL(_net_link_ether); 73602d513cSGarrett Wollman SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); 74df8bae1dSRodney W. Grimes 75df8bae1dSRodney W. Grimes /* timer values */ 76602d513cSGarrett Wollman static int arpt_prune = (5*60*1); /* walk list every 5 minutes */ 77602d513cSGarrett Wollman static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ 78602d513cSGarrett Wollman static int arpt_down = 20; /* once declared down, don't send for 20 sec */ 79885f1aa4SPoul-Henning Kamp 80602d513cSGarrett Wollman SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, 81602d513cSGarrett Wollman &arpt_prune, 0, ""); 82602d513cSGarrett Wollman SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 83602d513cSGarrett Wollman &arpt_keep, 0, ""); 84602d513cSGarrett Wollman SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW, 85602d513cSGarrett Wollman &arpt_down, 0, ""); 86885f1aa4SPoul-Henning Kamp 87df8bae1dSRodney W. Grimes #define rt_expire rt_rmx.rmx_expire 88df8bae1dSRodney W. Grimes 8966800f57SGarrett Wollman struct llinfo_arp { 90e3975643SJake Burkholder LIST_ENTRY(llinfo_arp) la_le; 9166800f57SGarrett Wollman struct rtentry *la_rt; 9266800f57SGarrett Wollman struct mbuf *la_hold; /* last packet until resolved/timeout */ 9366800f57SGarrett Wollman long la_asked; /* last time we QUERIED for this addr */ 9466800f57SGarrett Wollman #define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */ 9566800f57SGarrett Wollman }; 9666800f57SGarrett Wollman 97e3975643SJake Burkholder static LIST_HEAD(, llinfo_arp) llinfo_arp; 98df8bae1dSRodney W. Grimes 99df5e1987SJonathan Lemon struct ifqueue arpintrq; 100f708ef1bSPoul-Henning Kamp static int arp_inuse, arp_allocated; 101df8bae1dSRodney W. Grimes 102885f1aa4SPoul-Henning Kamp static int arp_maxtries = 5; 103602d513cSGarrett Wollman static int useloopback = 1; /* use loopback interface for local traffic */ 104885f1aa4SPoul-Henning Kamp static int arp_proxyall = 0; 105602d513cSGarrett Wollman 106602d513cSGarrett Wollman SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, 107602d513cSGarrett Wollman &arp_maxtries, 0, ""); 108602d513cSGarrett Wollman SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, 109602d513cSGarrett Wollman &useloopback, 0, ""); 110602d513cSGarrett Wollman SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, 111602d513cSGarrett Wollman &arp_proxyall, 0, ""); 112885f1aa4SPoul-Henning Kamp 113df5e1987SJonathan Lemon static void arp_init __P((void)); 114081d3b93SBruce Evans static void arp_rtrequest __P((int, struct rtentry *, struct sockaddr *)); 115ed7509acSJulian Elischer static void arprequest __P((struct arpcom *, 116ed7509acSJulian Elischer struct in_addr *, struct in_addr *, u_char *)); 117885f1aa4SPoul-Henning Kamp static void arpintr __P((void)); 118885f1aa4SPoul-Henning Kamp static void arptfree __P((struct llinfo_arp *)); 119885f1aa4SPoul-Henning Kamp static void arptimer __P((void *)); 120885f1aa4SPoul-Henning Kamp static struct llinfo_arp 121885f1aa4SPoul-Henning Kamp *arplookup __P((u_long, int, int)); 1221d5e9e22SEivind Eklund #ifdef INET 123885f1aa4SPoul-Henning Kamp static void in_arpinput __P((struct mbuf *)); 1241d5e9e22SEivind Eklund #endif 12528e82295SGarrett Wollman 126df8bae1dSRodney W. Grimes /* 127df8bae1dSRodney W. Grimes * Timeout routine. Age arp_tab entries periodically. 128df8bae1dSRodney W. Grimes */ 129df8bae1dSRodney W. Grimes /* ARGSUSED */ 130df8bae1dSRodney W. Grimes static void 131df8bae1dSRodney W. Grimes arptimer(ignored_arg) 132df8bae1dSRodney W. Grimes void *ignored_arg; 133df8bae1dSRodney W. Grimes { 134df8bae1dSRodney W. Grimes int s = splnet(); 13566800f57SGarrett Wollman register struct llinfo_arp *la = llinfo_arp.lh_first; 13666800f57SGarrett Wollman struct llinfo_arp *ola; 137df8bae1dSRodney W. Grimes 138df8bae1dSRodney W. Grimes timeout(arptimer, (caddr_t)0, arpt_prune * hz); 13966800f57SGarrett Wollman while ((ola = la) != 0) { 140df8bae1dSRodney W. Grimes register struct rtentry *rt = la->la_rt; 14166800f57SGarrett Wollman la = la->la_le.le_next; 142227ee8a1SPoul-Henning Kamp if (rt->rt_expire && rt->rt_expire <= time_second) 14366800f57SGarrett Wollman arptfree(ola); /* timer has expired, clear */ 144df8bae1dSRodney W. Grimes } 145df8bae1dSRodney W. Grimes splx(s); 146df8bae1dSRodney W. Grimes } 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 149df8bae1dSRodney W. Grimes * Parallel to llc_rtrequest. 150df8bae1dSRodney W. Grimes */ 151b2774d00SGarrett Wollman static void 152df8bae1dSRodney W. Grimes arp_rtrequest(req, rt, sa) 153df8bae1dSRodney W. Grimes int req; 154df8bae1dSRodney W. Grimes register struct rtentry *rt; 155df8bae1dSRodney W. Grimes struct sockaddr *sa; 156df8bae1dSRodney W. Grimes { 157df8bae1dSRodney W. Grimes register struct sockaddr *gate = rt->rt_gateway; 158df8bae1dSRodney W. Grimes register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; 159df8bae1dSRodney W. Grimes static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 160885f1aa4SPoul-Henning Kamp static int arpinit_done; 161df8bae1dSRodney W. Grimes 162df8bae1dSRodney W. Grimes if (!arpinit_done) { 163df8bae1dSRodney W. Grimes arpinit_done = 1; 16466800f57SGarrett Wollman LIST_INIT(&llinfo_arp); 165df8bae1dSRodney W. Grimes timeout(arptimer, (caddr_t)0, hz); 166242c5536SPeter Wemm register_netisr(NETISR_ARP, arpintr); 167df8bae1dSRodney W. Grimes } 168df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 169df8bae1dSRodney W. Grimes return; 170df8bae1dSRodney W. Grimes switch (req) { 171df8bae1dSRodney W. Grimes 172df8bae1dSRodney W. Grimes case RTM_ADD: 173df8bae1dSRodney W. Grimes /* 174df8bae1dSRodney W. Grimes * XXX: If this is a manually added route to interface 175df8bae1dSRodney W. Grimes * such as older version of routed or gated might provide, 176df8bae1dSRodney W. Grimes * restore cloning bit. 177df8bae1dSRodney W. Grimes */ 178df8bae1dSRodney W. Grimes if ((rt->rt_flags & RTF_HOST) == 0 && 179df8bae1dSRodney W. Grimes SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 180df8bae1dSRodney W. Grimes rt->rt_flags |= RTF_CLONING; 181df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_CLONING) { 182df8bae1dSRodney W. Grimes /* 183df8bae1dSRodney W. Grimes * Case 1: This route should come from a route to iface. 184df8bae1dSRodney W. Grimes */ 185df8bae1dSRodney W. Grimes rt_setgate(rt, rt_key(rt), 186df8bae1dSRodney W. Grimes (struct sockaddr *)&null_sdl); 187df8bae1dSRodney W. Grimes gate = rt->rt_gateway; 188df8bae1dSRodney W. Grimes SDL(gate)->sdl_type = rt->rt_ifp->if_type; 189df8bae1dSRodney W. Grimes SDL(gate)->sdl_index = rt->rt_ifp->if_index; 190227ee8a1SPoul-Henning Kamp rt->rt_expire = time_second; 191df8bae1dSRodney W. Grimes break; 192df8bae1dSRodney W. Grimes } 193df8bae1dSRodney W. Grimes /* Announce a new entry if requested. */ 194df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_ANNOUNCE) 195df8bae1dSRodney W. Grimes arprequest((struct arpcom *)rt->rt_ifp, 196ed7509acSJulian Elischer &SIN(rt_key(rt))->sin_addr, 197ed7509acSJulian Elischer &SIN(rt_key(rt))->sin_addr, 198df8bae1dSRodney W. Grimes (u_char *)LLADDR(SDL(gate))); 199df8bae1dSRodney W. Grimes /*FALLTHROUGH*/ 200df8bae1dSRodney W. Grimes case RTM_RESOLVE: 201df8bae1dSRodney W. Grimes if (gate->sa_family != AF_LINK || 202df8bae1dSRodney W. Grimes gate->sa_len < sizeof(null_sdl)) { 20338aa9fc3SDavid Greenman log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); 204df8bae1dSRodney W. Grimes break; 205df8bae1dSRodney W. Grimes } 206df8bae1dSRodney W. Grimes SDL(gate)->sdl_type = rt->rt_ifp->if_type; 207df8bae1dSRodney W. Grimes SDL(gate)->sdl_index = rt->rt_ifp->if_index; 208df8bae1dSRodney W. Grimes if (la != 0) 209df8bae1dSRodney W. Grimes break; /* This happens on a route change */ 210df8bae1dSRodney W. Grimes /* 211df8bae1dSRodney W. Grimes * Case 2: This route may come from cloning, or a manual route 212df8bae1dSRodney W. Grimes * add with a LL address. 213df8bae1dSRodney W. Grimes */ 214df8bae1dSRodney W. Grimes R_Malloc(la, struct llinfo_arp *, sizeof(*la)); 215df8bae1dSRodney W. Grimes rt->rt_llinfo = (caddr_t)la; 216df8bae1dSRodney W. Grimes if (la == 0) { 217df8bae1dSRodney W. Grimes log(LOG_DEBUG, "arp_rtrequest: malloc failed\n"); 218df8bae1dSRodney W. Grimes break; 219df8bae1dSRodney W. Grimes } 220df8bae1dSRodney W. Grimes arp_inuse++, arp_allocated++; 221df8bae1dSRodney W. Grimes Bzero(la, sizeof(*la)); 222df8bae1dSRodney W. Grimes la->la_rt = rt; 223df8bae1dSRodney W. Grimes rt->rt_flags |= RTF_LLINFO; 22466800f57SGarrett Wollman LIST_INSERT_HEAD(&llinfo_arp, la, la_le); 225cbb0b46aSGarrett Wollman 2261d5e9e22SEivind Eklund #ifdef INET 227cbb0b46aSGarrett Wollman /* 228cbb0b46aSGarrett Wollman * This keeps the multicast addresses from showing up 229cbb0b46aSGarrett Wollman * in `arp -a' listings as unresolved. It's not actually 230cbb0b46aSGarrett Wollman * functional. Then the same for broadcast. 231cbb0b46aSGarrett Wollman */ 232cbb0b46aSGarrett Wollman if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) { 233cbb0b46aSGarrett Wollman ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr, 234cbb0b46aSGarrett Wollman LLADDR(SDL(gate))); 235cbb0b46aSGarrett Wollman SDL(gate)->sdl_alen = 6; 23651a109a1SPeter Wemm rt->rt_expire = 0; 237cbb0b46aSGarrett Wollman } 238cbb0b46aSGarrett Wollman if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { 239cbb0b46aSGarrett Wollman memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6); 240cbb0b46aSGarrett Wollman SDL(gate)->sdl_alen = 6; 24151a109a1SPeter Wemm rt->rt_expire = 0; 242cbb0b46aSGarrett Wollman } 2431d5e9e22SEivind Eklund #endif 244cbb0b46aSGarrett Wollman 245df8bae1dSRodney W. Grimes if (SIN(rt_key(rt))->sin_addr.s_addr == 246df8bae1dSRodney W. Grimes (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { 247df8bae1dSRodney W. Grimes /* 248df8bae1dSRodney W. Grimes * This test used to be 249df8bae1dSRodney W. Grimes * if (loif.if_flags & IFF_UP) 250df8bae1dSRodney W. Grimes * It allowed local traffic to be forced 251df8bae1dSRodney W. Grimes * through the hardware by configuring the loopback down. 252df8bae1dSRodney W. Grimes * However, it causes problems during network configuration 253df8bae1dSRodney W. Grimes * for boards that can't receive packets they send. 254df8bae1dSRodney W. Grimes * It is now necessary to clear "useloopback" and remove 255df8bae1dSRodney W. Grimes * the route to force traffic out to the hardware. 256df8bae1dSRodney W. Grimes */ 257df8bae1dSRodney W. Grimes rt->rt_expire = 0; 258df8bae1dSRodney W. Grimes Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr, 259df8bae1dSRodney W. Grimes LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); 260df8bae1dSRodney W. Grimes if (useloopback) 261f5fea3ddSPaul Traina rt->rt_ifp = loif; 262df8bae1dSRodney W. Grimes 263df8bae1dSRodney W. Grimes } 264df8bae1dSRodney W. Grimes break; 265df8bae1dSRodney W. Grimes 266df8bae1dSRodney W. Grimes case RTM_DELETE: 267df8bae1dSRodney W. Grimes if (la == 0) 268df8bae1dSRodney W. Grimes break; 269df8bae1dSRodney W. Grimes arp_inuse--; 27066800f57SGarrett Wollman LIST_REMOVE(la, la_le); 271df8bae1dSRodney W. Grimes rt->rt_llinfo = 0; 272df8bae1dSRodney W. Grimes rt->rt_flags &= ~RTF_LLINFO; 273df8bae1dSRodney W. Grimes if (la->la_hold) 274df8bae1dSRodney W. Grimes m_freem(la->la_hold); 275df8bae1dSRodney W. Grimes Free((caddr_t)la); 276df8bae1dSRodney W. Grimes } 277df8bae1dSRodney W. Grimes } 278df8bae1dSRodney W. Grimes 279df8bae1dSRodney W. Grimes /* 280df8bae1dSRodney W. Grimes * Broadcast an ARP request. Caller specifies: 281df8bae1dSRodney W. Grimes * - arp header source ip address 282df8bae1dSRodney W. Grimes * - arp header target ip address 283df8bae1dSRodney W. Grimes * - arp header source ethernet address 284df8bae1dSRodney W. Grimes */ 285df8bae1dSRodney W. Grimes static void 286df8bae1dSRodney W. Grimes arprequest(ac, sip, tip, enaddr) 287df8bae1dSRodney W. Grimes register struct arpcom *ac; 288ed7509acSJulian Elischer register struct in_addr *sip, *tip; 289df8bae1dSRodney W. Grimes register u_char *enaddr; 290df8bae1dSRodney W. Grimes { 291df8bae1dSRodney W. Grimes register struct mbuf *m; 292df8bae1dSRodney W. Grimes register struct ether_header *eh; 293df8bae1dSRodney W. Grimes register struct ether_arp *ea; 294df8bae1dSRodney W. Grimes struct sockaddr sa; 295b149dd6cSLarry Lile static u_char llcx[] = { 0x82, 0x40, LLC_SNAP_LSAP, LLC_SNAP_LSAP, 296b149dd6cSLarry Lile LLC_UI, 0x00, 0x00, 0x00, 0x08, 0x06 }; 297df8bae1dSRodney W. Grimes 298df8bae1dSRodney W. Grimes if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 299df8bae1dSRodney W. Grimes return; 300fda82fc2SJulian Elischer m->m_pkthdr.rcvif = (struct ifnet *)0; 301fda82fc2SJulian Elischer switch (ac->ac_if.if_type) { 302fda82fc2SJulian Elischer case IFT_ISO88025: 303b149dd6cSLarry Lile m->m_len = sizeof(*ea) + sizeof(llcx); 304b149dd6cSLarry Lile m->m_pkthdr.len = sizeof(*ea) + sizeof(llcx); 305b149dd6cSLarry Lile MH_ALIGN(m, sizeof(*ea) + sizeof(llcx)); 306b149dd6cSLarry Lile (void)memcpy(mtod(m, caddr_t), llcx, sizeof(llcx)); 307fda82fc2SJulian Elischer (void)memcpy(sa.sa_data, etherbroadcastaddr, 6); 308fda82fc2SJulian Elischer (void)memcpy(sa.sa_data + 6, enaddr, 6); 309b149dd6cSLarry Lile sa.sa_data[6] |= TR_RII; 310b149dd6cSLarry Lile sa.sa_data[12] = TR_AC; 311b149dd6cSLarry Lile sa.sa_data[13] = TR_LLC_FRAME; 312b149dd6cSLarry Lile ea = (struct ether_arp *)(mtod(m, char *) + sizeof(llcx)); 313fda82fc2SJulian Elischer bzero((caddr_t)ea, sizeof (*ea)); 314722012ccSJulian Elischer ea->arp_hrd = htons(ARPHRD_IEEE802); 315fda82fc2SJulian Elischer break; 316f9083fdbSLarry Lile case IFT_FDDI: 317f9083fdbSLarry Lile case IFT_ETHER: 318f9083fdbSLarry Lile /* 319f9083fdbSLarry Lile * This may not be correct for types not explicitly 320f9083fdbSLarry Lile * listed, but this is our best guess 321f9083fdbSLarry Lile */ 322fda82fc2SJulian Elischer default: 323f9083fdbSLarry Lile m->m_len = sizeof(*ea); 324f9083fdbSLarry Lile m->m_pkthdr.len = sizeof(*ea); 325f9083fdbSLarry Lile MH_ALIGN(m, sizeof(*ea)); 326f9083fdbSLarry Lile ea = mtod(m, struct ether_arp *); 327f9083fdbSLarry Lile eh = (struct ether_header *)sa.sa_data; 328f9083fdbSLarry Lile bzero((caddr_t)ea, sizeof (*ea)); 329f9083fdbSLarry Lile /* if_output will not swap */ 330f9083fdbSLarry Lile eh->ether_type = htons(ETHERTYPE_ARP); 331f9083fdbSLarry Lile (void)memcpy(eh->ether_dhost, etherbroadcastaddr, 332f9083fdbSLarry Lile sizeof(eh->ether_dhost)); 333f9083fdbSLarry Lile ea->arp_hrd = htons(ARPHRD_ETHER); 334f9083fdbSLarry Lile break; 335fda82fc2SJulian Elischer } 336df8bae1dSRodney W. Grimes ea->arp_pro = htons(ETHERTYPE_IP); 337df8bae1dSRodney W. Grimes ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ 338df8bae1dSRodney W. Grimes ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ 339df8bae1dSRodney W. Grimes ea->arp_op = htons(ARPOP_REQUEST); 34094a5d9b6SDavid Greenman (void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha)); 34194a5d9b6SDavid Greenman (void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa)); 34294a5d9b6SDavid Greenman (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa)); 343df8bae1dSRodney W. Grimes sa.sa_family = AF_UNSPEC; 344df8bae1dSRodney W. Grimes sa.sa_len = sizeof(sa); 345df8bae1dSRodney W. Grimes (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); 346df8bae1dSRodney W. Grimes } 347df8bae1dSRodney W. Grimes 348df8bae1dSRodney W. Grimes /* 349df8bae1dSRodney W. Grimes * Resolve an IP address into an ethernet address. If success, 350df8bae1dSRodney W. Grimes * desten is filled in. If there is no entry in arptab, 351df8bae1dSRodney W. Grimes * set one up and broadcast a request for the IP address. 352df8bae1dSRodney W. Grimes * Hold onto this mbuf and resend it once the address 353df8bae1dSRodney W. Grimes * is finally resolved. A return value of 1 indicates 354df8bae1dSRodney W. Grimes * that desten has been filled in and the packet should be sent 355df8bae1dSRodney W. Grimes * normally; a 0 return indicates that the packet has been 356df8bae1dSRodney W. Grimes * taken over here, either now or for later transmission. 357df8bae1dSRodney W. Grimes */ 358df8bae1dSRodney W. Grimes int 3595df72964SGarrett Wollman arpresolve(ac, rt, m, dst, desten, rt0) 360df8bae1dSRodney W. Grimes register struct arpcom *ac; 361df8bae1dSRodney W. Grimes register struct rtentry *rt; 362df8bae1dSRodney W. Grimes struct mbuf *m; 363df8bae1dSRodney W. Grimes register struct sockaddr *dst; 364df8bae1dSRodney W. Grimes register u_char *desten; 3655df72964SGarrett Wollman struct rtentry *rt0; 366df8bae1dSRodney W. Grimes { 367cc133fa3SBill Fenner register struct llinfo_arp *la = 0; 368df8bae1dSRodney W. Grimes struct sockaddr_dl *sdl; 369df8bae1dSRodney W. Grimes 370df8bae1dSRodney W. Grimes if (m->m_flags & M_BCAST) { /* broadcast */ 37194a5d9b6SDavid Greenman (void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr)); 372df8bae1dSRodney W. Grimes return (1); 373df8bae1dSRodney W. Grimes } 374df8bae1dSRodney W. Grimes if (m->m_flags & M_MCAST) { /* multicast */ 375df8bae1dSRodney W. Grimes ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); 376df8bae1dSRodney W. Grimes return(1); 377df8bae1dSRodney W. Grimes } 378df8bae1dSRodney W. Grimes if (rt) 379df8bae1dSRodney W. Grimes la = (struct llinfo_arp *)rt->rt_llinfo; 380e7bc5f27SBill Fenner if (la == 0) { 381623ae52eSPoul-Henning Kamp la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); 382623ae52eSPoul-Henning Kamp if (la) 383df8bae1dSRodney W. Grimes rt = la->la_rt; 384df8bae1dSRodney W. Grimes } 385df8bae1dSRodney W. Grimes if (la == 0 || rt == 0) { 386245086a0SPoul-Henning Kamp log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n", 387245086a0SPoul-Henning Kamp inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "", 388245086a0SPoul-Henning Kamp rt ? "rt" : ""); 389df8bae1dSRodney W. Grimes m_freem(m); 390df8bae1dSRodney W. Grimes return (0); 391df8bae1dSRodney W. Grimes } 392df8bae1dSRodney W. Grimes sdl = SDL(rt->rt_gateway); 393df8bae1dSRodney W. Grimes /* 394df8bae1dSRodney W. Grimes * Check the address family and length is valid, the address 395df8bae1dSRodney W. Grimes * is resolved; otherwise, try to resolve. 396df8bae1dSRodney W. Grimes */ 397227ee8a1SPoul-Henning Kamp if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && 398df8bae1dSRodney W. Grimes sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { 3990453d3cbSBruce Evans bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 400df8bae1dSRodney W. Grimes return 1; 401df8bae1dSRodney W. Grimes } 402df8bae1dSRodney W. Grimes /* 403df8bae1dSRodney W. Grimes * There is an arptab entry, but no ethernet address 404df8bae1dSRodney W. Grimes * response yet. Replace the held mbuf with this 405df8bae1dSRodney W. Grimes * latest one. 406df8bae1dSRodney W. Grimes */ 407df8bae1dSRodney W. Grimes if (la->la_hold) 408df8bae1dSRodney W. Grimes m_freem(la->la_hold); 409df8bae1dSRodney W. Grimes la->la_hold = m; 410df8bae1dSRodney W. Grimes if (rt->rt_expire) { 411df8bae1dSRodney W. Grimes rt->rt_flags &= ~RTF_REJECT; 412227ee8a1SPoul-Henning Kamp if (la->la_asked == 0 || rt->rt_expire != time_second) { 413227ee8a1SPoul-Henning Kamp rt->rt_expire = time_second; 414df8bae1dSRodney W. Grimes if (la->la_asked++ < arp_maxtries) 415203f0c07SBill Fenner arprequest(ac, 416ed7509acSJulian Elischer &SIN(rt->rt_ifa->ifa_addr)->sin_addr, 417ed7509acSJulian Elischer &SIN(dst)->sin_addr, ac->ac_enaddr); 418df8bae1dSRodney W. Grimes else { 419df8bae1dSRodney W. Grimes rt->rt_flags |= RTF_REJECT; 420df8bae1dSRodney W. Grimes rt->rt_expire += arpt_down; 421df8bae1dSRodney W. Grimes la->la_asked = 0; 422df8bae1dSRodney W. Grimes } 423df8bae1dSRodney W. Grimes 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes } 426df8bae1dSRodney W. Grimes return (0); 427df8bae1dSRodney W. Grimes } 428df8bae1dSRodney W. Grimes 429df8bae1dSRodney W. Grimes /* 430df8bae1dSRodney W. Grimes * Common length and type checks are done here, 431df8bae1dSRodney W. Grimes * then the protocol-specific routine is called. 432df8bae1dSRodney W. Grimes */ 433885f1aa4SPoul-Henning Kamp static void 434c5a1016bSBruce Evans arpintr() 435df8bae1dSRodney W. Grimes { 436732f6a43SWes Peters register struct mbuf *m; 437df8bae1dSRodney W. Grimes register struct arphdr *ar; 438732f6a43SWes Peters int s; 439df8bae1dSRodney W. Grimes 440df8bae1dSRodney W. Grimes while (arpintrq.ifq_head) { 441df8bae1dSRodney W. Grimes s = splimp(); 442df8bae1dSRodney W. Grimes IF_DEQUEUE(&arpintrq, m); 443df8bae1dSRodney W. Grimes splx(s); 444df8bae1dSRodney W. Grimes if (m == 0 || (m->m_flags & M_PKTHDR) == 0) 445df8bae1dSRodney W. Grimes panic("arpintr"); 44676ec7b2fSRobert Watson 44776ec7b2fSRobert Watson if (m->m_len < sizeof(struct arphdr) && 44884365e2bSMatthew Dillon ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) { 449e44d6283SJoerg Wunsch log(LOG_ERR, "arp: runt packet -- m_pullup failed\n"); 45076ec7b2fSRobert Watson continue; 45176ec7b2fSRobert Watson } 45276ec7b2fSRobert Watson ar = mtod(m, struct arphdr *); 45376ec7b2fSRobert Watson 45476ec7b2fSRobert Watson if (ntohs(ar->ar_hrd) != ARPHRD_ETHER 45576ec7b2fSRobert Watson && ntohs(ar->ar_hrd) != ARPHRD_IEEE802) { 45676ec7b2fSRobert Watson log(LOG_ERR, 457e44d6283SJoerg Wunsch "arp: unknown hardware address format (0x%2D)\n", 45876ec7b2fSRobert Watson (unsigned char *)&ar->ar_hrd, ""); 45976ec7b2fSRobert Watson m_freem(m); 46076ec7b2fSRobert Watson continue; 46176ec7b2fSRobert Watson } 46276ec7b2fSRobert Watson 463732f6a43SWes Peters if (m->m_pkthdr.len < sizeof(struct arphdr) + 2 * ar->ar_hln 46476ec7b2fSRobert Watson + 2 * ar->ar_pln) { 465f72d9d83SJoerg Wunsch log(LOG_ERR, "arp: runt packet\n"); 46676ec7b2fSRobert Watson m_freem(m); 46776ec7b2fSRobert Watson continue; 46876ec7b2fSRobert Watson } 469df8bae1dSRodney W. Grimes 470df8bae1dSRodney W. Grimes switch (ntohs(ar->ar_pro)) { 4711d5e9e22SEivind Eklund #ifdef INET 472df8bae1dSRodney W. Grimes case ETHERTYPE_IP: 473df8bae1dSRodney W. Grimes in_arpinput(m); 474df8bae1dSRodney W. Grimes continue; 4751d5e9e22SEivind Eklund #endif 476df8bae1dSRodney W. Grimes } 477df8bae1dSRodney W. Grimes m_freem(m); 478df8bae1dSRodney W. Grimes } 479df8bae1dSRodney W. Grimes } 480df8bae1dSRodney W. Grimes 4811d5e9e22SEivind Eklund #ifdef INET 482df8bae1dSRodney W. Grimes /* 483df8bae1dSRodney W. Grimes * ARP for Internet protocols on 10 Mb/s Ethernet. 484df8bae1dSRodney W. Grimes * Algorithm is that given in RFC 826. 485df8bae1dSRodney W. Grimes * In addition, a sanity check is performed on the sender 486df8bae1dSRodney W. Grimes * protocol address, to catch impersonators. 487df8bae1dSRodney W. Grimes * We no longer handle negotiations for use of trailer protocol: 488df8bae1dSRodney W. Grimes * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent 489df8bae1dSRodney W. Grimes * along with IP replies if we wanted trailers sent to us, 490df8bae1dSRodney W. Grimes * and also sent them in response to IP replies. 491df8bae1dSRodney W. Grimes * This allowed either end to announce the desire to receive 492df8bae1dSRodney W. Grimes * trailer packets. 493df8bae1dSRodney W. Grimes * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, 494df8bae1dSRodney W. Grimes * but formerly didn't normally send requests. 495df8bae1dSRodney W. Grimes */ 4963269187dSAlfred Perlstein static int log_arp_wrong_iface = 1; 4973269187dSAlfred Perlstein 4983269187dSAlfred Perlstein SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW, 4993269187dSAlfred Perlstein &log_arp_wrong_iface, 0, 5003269187dSAlfred Perlstein "log arp packets arriving on the wrong interface"); 5013269187dSAlfred Perlstein 502df8bae1dSRodney W. Grimes static void 503df8bae1dSRodney W. Grimes in_arpinput(m) 504df8bae1dSRodney W. Grimes struct mbuf *m; 505df8bae1dSRodney W. Grimes { 506df8bae1dSRodney W. Grimes register struct ether_arp *ea; 507df8bae1dSRodney W. Grimes register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; 508df8bae1dSRodney W. Grimes struct ether_header *eh; 509fda82fc2SJulian Elischer struct iso88025_header *th = (struct iso88025_header *)0; 510df8bae1dSRodney W. Grimes register struct llinfo_arp *la = 0; 511df8bae1dSRodney W. Grimes register struct rtentry *rt; 512df8bae1dSRodney W. Grimes struct in_ifaddr *ia, *maybe_ia = 0; 513df8bae1dSRodney W. Grimes struct sockaddr_dl *sdl; 514df8bae1dSRodney W. Grimes struct sockaddr sa; 515df8bae1dSRodney W. Grimes struct in_addr isaddr, itaddr, myaddr; 516b149dd6cSLarry Lile int op, rif_len; 517df8bae1dSRodney W. Grimes 518df8bae1dSRodney W. Grimes ea = mtod(m, struct ether_arp *); 519df8bae1dSRodney W. Grimes op = ntohs(ea->arp_op); 52094a5d9b6SDavid Greenman (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); 52194a5d9b6SDavid Greenman (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); 522cbf5d949SBruce Evans for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) 523b715f178SLuigi Rizzo #ifdef BRIDGE 524b715f178SLuigi Rizzo /* 525b715f178SLuigi Rizzo * For a bridge, we want to check the address irrespective 526b715f178SLuigi Rizzo * of the receive interface. (This will change slightly 527b715f178SLuigi Rizzo * when we have clusters of interfaces). 528b715f178SLuigi Rizzo */ 529b715f178SLuigi Rizzo { 530b715f178SLuigi Rizzo #else 531df8bae1dSRodney W. Grimes if (ia->ia_ifp == &ac->ac_if) { 532b715f178SLuigi Rizzo #endif 533df8bae1dSRodney W. Grimes maybe_ia = ia; 534df8bae1dSRodney W. Grimes if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || 535df8bae1dSRodney W. Grimes (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) 536df8bae1dSRodney W. Grimes break; 537df8bae1dSRodney W. Grimes } 538885f1aa4SPoul-Henning Kamp if (maybe_ia == 0) { 539885f1aa4SPoul-Henning Kamp m_freem(m); 540885f1aa4SPoul-Henning Kamp return; 541885f1aa4SPoul-Henning Kamp } 542df8bae1dSRodney W. Grimes myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; 543df8bae1dSRodney W. Grimes if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, 544885f1aa4SPoul-Henning Kamp sizeof (ea->arp_sha))) { 545885f1aa4SPoul-Henning Kamp m_freem(m); /* it's from me, ignore it. */ 546885f1aa4SPoul-Henning Kamp return; 547885f1aa4SPoul-Henning Kamp } 548df8bae1dSRodney W. Grimes if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, 549df8bae1dSRodney W. Grimes sizeof (ea->arp_sha))) { 550df8bae1dSRodney W. Grimes log(LOG_ERR, 551ac234f93SGarrett Wollman "arp: ether address is broadcast for IP address %s!\n", 552ef0cdf33SGarrett Wollman inet_ntoa(isaddr)); 553885f1aa4SPoul-Henning Kamp m_freem(m); 554885f1aa4SPoul-Henning Kamp return; 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes if (isaddr.s_addr == myaddr.s_addr) { 557df8bae1dSRodney W. Grimes log(LOG_ERR, 558254de4eaSBill Fenner "arp: %6D is using my IP address %s!\n", 559254de4eaSBill Fenner ea->arp_sha, ":", inet_ntoa(isaddr)); 560df8bae1dSRodney W. Grimes itaddr = myaddr; 561df8bae1dSRodney W. Grimes goto reply; 562df8bae1dSRodney W. Grimes } 563df8bae1dSRodney W. Grimes la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); 564df8bae1dSRodney W. Grimes if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { 565a1a2de51SLuigi Rizzo #ifndef BRIDGE /* the following is not an error when doing bridging */ 566dd9b6ddeSBill Fenner if (rt->rt_ifp != &ac->ac_if) { 5673269187dSAlfred Perlstein if (log_arp_wrong_iface) 568dd9b6ddeSBill Fenner log(LOG_ERR, "arp: %s is on %s%d but got reply from %6D on %s%d\n", 569dd9b6ddeSBill Fenner inet_ntoa(isaddr), 570dd9b6ddeSBill Fenner rt->rt_ifp->if_name, rt->rt_ifp->if_unit, 571dd9b6ddeSBill Fenner ea->arp_sha, ":", 572dd9b6ddeSBill Fenner ac->ac_if.if_name, ac->ac_if.if_unit); 573dd9b6ddeSBill Fenner goto reply; 574dd9b6ddeSBill Fenner } 575a1a2de51SLuigi Rizzo #endif 576df8bae1dSRodney W. Grimes if (sdl->sdl_alen && 577dfd5dee1SPeter Wemm bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) { 578dd9b6ddeSBill Fenner if (rt->rt_expire) 579dd9b6ddeSBill Fenner log(LOG_INFO, "arp: %s moved from %6D to %6D on %s%d\n", 580254de4eaSBill Fenner inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":", 581dd9b6ddeSBill Fenner ea->arp_sha, ":", 582dd9b6ddeSBill Fenner ac->ac_if.if_name, ac->ac_if.if_unit); 583dd9b6ddeSBill Fenner else { 584dd9b6ddeSBill Fenner log(LOG_ERR, 5850b757633SSheldon Hearn "arp: %6D attempts to modify permanent entry for %s on %s%d\n", 586dd9b6ddeSBill Fenner ea->arp_sha, ":", inet_ntoa(isaddr), 587dd9b6ddeSBill Fenner ac->ac_if.if_name, ac->ac_if.if_unit); 588dd9b6ddeSBill Fenner goto reply; 589dd9b6ddeSBill Fenner } 590dfd5dee1SPeter Wemm } 59194a5d9b6SDavid Greenman (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); 59294a5d9b6SDavid Greenman sdl->sdl_alen = sizeof(ea->arp_sha); 593b149dd6cSLarry Lile sdl->sdl_rcf = (u_short)0; 594243c4c6dSEivind Eklund /* 595243c4c6dSEivind Eklund * If we receive an arp from a token-ring station over 596243c4c6dSEivind Eklund * a token-ring nic then try to save the source 597243c4c6dSEivind Eklund * routing info. 598243c4c6dSEivind Eklund */ 599243c4c6dSEivind Eklund if (ac->ac_if.if_type == IFT_ISO88025) { 600fda82fc2SJulian Elischer th = (struct iso88025_header *)m->m_pkthdr.header; 601b149dd6cSLarry Lile rif_len = TR_RCF_RIFLEN(th->rcf); 602b149dd6cSLarry Lile if ((th->iso88025_shost[0] & TR_RII) && 603b149dd6cSLarry Lile (rif_len > 2)) { 604b149dd6cSLarry Lile sdl->sdl_rcf = th->rcf; 605b149dd6cSLarry Lile sdl->sdl_rcf ^= htons(TR_RCF_DIR); 606b149dd6cSLarry Lile memcpy(sdl->sdl_route, th->rd, rif_len - 2); 607b149dd6cSLarry Lile sdl->sdl_rcf &= ~htons(TR_RCF_BCST_MASK); 608f9083fdbSLarry Lile /* 609f9083fdbSLarry Lile * Set up source routing information for 610f9083fdbSLarry Lile * reply packet (XXX) 611f9083fdbSLarry Lile */ 612b149dd6cSLarry Lile m->m_data -= rif_len; 613b149dd6cSLarry Lile m->m_len += rif_len; 614b149dd6cSLarry Lile m->m_pkthdr.len += rif_len; 615fda82fc2SJulian Elischer } else { 616b149dd6cSLarry Lile th->iso88025_shost[0] &= ~TR_RII; 617fcf11853SLarry Lile } 618fda82fc2SJulian Elischer m->m_data -= 8; 619fda82fc2SJulian Elischer m->m_len += 8; 620fcf11853SLarry Lile m->m_pkthdr.len += 8; 621fda82fc2SJulian Elischer th->rcf = sdl->sdl_rcf; 622243c4c6dSEivind Eklund } else { 623b149dd6cSLarry Lile sdl->sdl_rcf = (u_short)0; 624fda82fc2SJulian Elischer } 625df8bae1dSRodney W. Grimes if (rt->rt_expire) 626227ee8a1SPoul-Henning Kamp rt->rt_expire = time_second + arpt_keep; 627df8bae1dSRodney W. Grimes rt->rt_flags &= ~RTF_REJECT; 628df8bae1dSRodney W. Grimes la->la_asked = 0; 629df8bae1dSRodney W. Grimes if (la->la_hold) { 630df8bae1dSRodney W. Grimes (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold, 631df8bae1dSRodney W. Grimes rt_key(rt), rt); 632df8bae1dSRodney W. Grimes la->la_hold = 0; 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes } 635df8bae1dSRodney W. Grimes reply: 636df8bae1dSRodney W. Grimes if (op != ARPOP_REQUEST) { 637df8bae1dSRodney W. Grimes m_freem(m); 638df8bae1dSRodney W. Grimes return; 639df8bae1dSRodney W. Grimes } 640df8bae1dSRodney W. Grimes if (itaddr.s_addr == myaddr.s_addr) { 641df8bae1dSRodney W. Grimes /* I am the target */ 64294a5d9b6SDavid Greenman (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); 64394a5d9b6SDavid Greenman (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); 644df8bae1dSRodney W. Grimes } else { 645df8bae1dSRodney W. Grimes la = arplookup(itaddr.s_addr, 0, SIN_PROXY); 64628e82295SGarrett Wollman if (la == NULL) { 64728e82295SGarrett Wollman struct sockaddr_in sin; 64828e82295SGarrett Wollman 649885f1aa4SPoul-Henning Kamp if (!arp_proxyall) { 650885f1aa4SPoul-Henning Kamp m_freem(m); 651885f1aa4SPoul-Henning Kamp return; 652885f1aa4SPoul-Henning Kamp } 65328e82295SGarrett Wollman 65428e82295SGarrett Wollman bzero(&sin, sizeof sin); 65528e82295SGarrett Wollman sin.sin_family = AF_INET; 65628e82295SGarrett Wollman sin.sin_len = sizeof sin; 65728e82295SGarrett Wollman sin.sin_addr = itaddr; 65828e82295SGarrett Wollman 65931246bc2SGarrett Wollman rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 660885f1aa4SPoul-Henning Kamp if (!rt) { 661885f1aa4SPoul-Henning Kamp m_freem(m); 662885f1aa4SPoul-Henning Kamp return; 663885f1aa4SPoul-Henning Kamp } 66428e82295SGarrett Wollman /* 66528e82295SGarrett Wollman * Don't send proxies for nodes on the same interface 66628e82295SGarrett Wollman * as this one came out of, or we'll get into a fight 66728e82295SGarrett Wollman * over who claims what Ether address. 66828e82295SGarrett Wollman */ 66928e82295SGarrett Wollman if (rt->rt_ifp == &ac->ac_if) { 67028e82295SGarrett Wollman rtfree(rt); 671885f1aa4SPoul-Henning Kamp m_freem(m); 672885f1aa4SPoul-Henning Kamp return; 67328e82295SGarrett Wollman } 67494a5d9b6SDavid Greenman (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); 67594a5d9b6SDavid Greenman (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); 67628e82295SGarrett Wollman rtfree(rt); 677cc728227SDavid Malone 678cc728227SDavid Malone /* 679cc728227SDavid Malone * Also check that the node which sent the ARP packet 680cc728227SDavid Malone * is on the the interface we expect it to be on. This 681cc728227SDavid Malone * avoids ARP chaos if an interface is connected to the 682cc728227SDavid Malone * wrong network. 683cc728227SDavid Malone */ 684cc728227SDavid Malone sin.sin_addr = isaddr; 685cc728227SDavid Malone 686cc728227SDavid Malone rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 687cc728227SDavid Malone if (!rt) { 688cc728227SDavid Malone m_freem(m); 689cc728227SDavid Malone return; 690cc728227SDavid Malone } 691cc728227SDavid Malone if (rt->rt_ifp != &ac->ac_if) { 692cc728227SDavid Malone log(LOG_INFO, "arp_proxy: ignoring request" 693cc728227SDavid Malone " from %s via %s%d, expecting %s%d\n", 694cc728227SDavid Malone inet_ntoa(isaddr), ac->ac_if.if_name, 695cc728227SDavid Malone ac->ac_if.if_unit, rt->rt_ifp->if_name, 696cc728227SDavid Malone rt->rt_ifp->if_unit); 697cc728227SDavid Malone rtfree(rt); 698cc728227SDavid Malone m_freem(m); 699cc728227SDavid Malone return; 700cc728227SDavid Malone } 701cc728227SDavid Malone rtfree(rt); 702cc728227SDavid Malone 703ac234f93SGarrett Wollman #ifdef DEBUG_PROXY 704ac234f93SGarrett Wollman printf("arp: proxying for %s\n", 705ef0cdf33SGarrett Wollman inet_ntoa(itaddr)); 706ac234f93SGarrett Wollman #endif 70728e82295SGarrett Wollman } else { 708df8bae1dSRodney W. Grimes rt = la->la_rt; 70994a5d9b6SDavid Greenman (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); 710df8bae1dSRodney W. Grimes sdl = SDL(rt->rt_gateway); 71194a5d9b6SDavid Greenman (void)memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha)); 71228e82295SGarrett Wollman } 713df8bae1dSRodney W. Grimes } 714df8bae1dSRodney W. Grimes 71594a5d9b6SDavid Greenman (void)memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa)); 71694a5d9b6SDavid Greenman (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa)); 717df8bae1dSRodney W. Grimes ea->arp_op = htons(ARPOP_REPLY); 718df8bae1dSRodney W. Grimes ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ 719243c4c6dSEivind Eklund switch (ac->ac_if.if_type) { 720243c4c6dSEivind Eklund case IFT_ISO88025: 721fda82fc2SJulian Elischer /* Re-arrange the source/dest address */ 722f9083fdbSLarry Lile memcpy(th->iso88025_dhost, th->iso88025_shost, 723f9083fdbSLarry Lile sizeof(th->iso88025_dhost)); 724f9083fdbSLarry Lile memcpy(th->iso88025_shost, ac->ac_enaddr, 725f9083fdbSLarry Lile sizeof(th->iso88025_shost)); 726fda82fc2SJulian Elischer /* Set the source routing bit if neccesary */ 727b149dd6cSLarry Lile if (th->iso88025_dhost[0] & TR_RII) { 728b149dd6cSLarry Lile th->iso88025_dhost[0] &= ~TR_RII; 729b149dd6cSLarry Lile if (TR_RCF_RIFLEN(th->rcf) > 2) 730b149dd6cSLarry Lile th->iso88025_shost[0] |= TR_RII; 731fda82fc2SJulian Elischer } 732fda82fc2SJulian Elischer /* Copy the addresses, ac and fc into sa_data */ 733f9083fdbSLarry Lile memcpy(sa.sa_data, th->iso88025_dhost, 734f9083fdbSLarry Lile sizeof(th->iso88025_dhost) * 2); 735b149dd6cSLarry Lile sa.sa_data[(sizeof(th->iso88025_dhost) * 2)] = TR_AC; 736b149dd6cSLarry Lile sa.sa_data[(sizeof(th->iso88025_dhost) * 2) + 1] = TR_LLC_FRAME; 737fda82fc2SJulian Elischer break; 738243c4c6dSEivind Eklund case IFT_ETHER: 739f9083fdbSLarry Lile case IFT_FDDI: 740f9083fdbSLarry Lile /* 741f9083fdbSLarry Lile * May not be correct for types not explictly 742f9083fdbSLarry Lile * listed, but it is our best guess. 743f9083fdbSLarry Lile */ 744f9083fdbSLarry Lile default: 745df8bae1dSRodney W. Grimes eh = (struct ether_header *)sa.sa_data; 746f9083fdbSLarry Lile (void)memcpy(eh->ether_dhost, ea->arp_tha, 747f9083fdbSLarry Lile sizeof(eh->ether_dhost)); 74834bed8b0SDavid Greenman eh->ether_type = htons(ETHERTYPE_ARP); 749fda82fc2SJulian Elischer break; 750fda82fc2SJulian Elischer } 751df8bae1dSRodney W. Grimes sa.sa_family = AF_UNSPEC; 752df8bae1dSRodney W. Grimes sa.sa_len = sizeof(sa); 753df8bae1dSRodney W. Grimes (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); 754df8bae1dSRodney W. Grimes return; 755df8bae1dSRodney W. Grimes } 7561d5e9e22SEivind Eklund #endif 757df8bae1dSRodney W. Grimes 758df8bae1dSRodney W. Grimes /* 759df8bae1dSRodney W. Grimes * Free an arp entry. 760df8bae1dSRodney W. Grimes */ 761df8bae1dSRodney W. Grimes static void 762df8bae1dSRodney W. Grimes arptfree(la) 763df8bae1dSRodney W. Grimes register struct llinfo_arp *la; 764df8bae1dSRodney W. Grimes { 765df8bae1dSRodney W. Grimes register struct rtentry *rt = la->la_rt; 766df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 767df8bae1dSRodney W. Grimes if (rt == 0) 768df8bae1dSRodney W. Grimes panic("arptfree"); 769df8bae1dSRodney W. Grimes if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && 770df8bae1dSRodney W. Grimes sdl->sdl_family == AF_LINK) { 771df8bae1dSRodney W. Grimes sdl->sdl_alen = 0; 772df8bae1dSRodney W. Grimes la->la_asked = 0; 773df8bae1dSRodney W. Grimes rt->rt_flags &= ~RTF_REJECT; 774df8bae1dSRodney W. Grimes return; 775df8bae1dSRodney W. Grimes } 776df8bae1dSRodney W. Grimes rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 777df8bae1dSRodney W. Grimes 0, (struct rtentry **)0); 778df8bae1dSRodney W. Grimes } 779df8bae1dSRodney W. Grimes /* 780df8bae1dSRodney W. Grimes * Lookup or enter a new address in arptab. 781df8bae1dSRodney W. Grimes */ 782df8bae1dSRodney W. Grimes static struct llinfo_arp * 783df8bae1dSRodney W. Grimes arplookup(addr, create, proxy) 784df8bae1dSRodney W. Grimes u_long addr; 785df8bae1dSRodney W. Grimes int create, proxy; 786df8bae1dSRodney W. Grimes { 787df8bae1dSRodney W. Grimes register struct rtentry *rt; 788df8bae1dSRodney W. Grimes static struct sockaddr_inarp sin = {sizeof(sin), AF_INET }; 789ac234f93SGarrett Wollman const char *why = 0; 790df8bae1dSRodney W. Grimes 791df8bae1dSRodney W. Grimes sin.sin_addr.s_addr = addr; 792df8bae1dSRodney W. Grimes sin.sin_other = proxy ? SIN_PROXY : 0; 79331246bc2SGarrett Wollman rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); 794df8bae1dSRodney W. Grimes if (rt == 0) 795df8bae1dSRodney W. Grimes return (0); 796df8bae1dSRodney W. Grimes rt->rt_refcnt--; 797ac234f93SGarrett Wollman 798ac234f93SGarrett Wollman if (rt->rt_flags & RTF_GATEWAY) 799ac234f93SGarrett Wollman why = "host is not on local network"; 800ac234f93SGarrett Wollman else if ((rt->rt_flags & RTF_LLINFO) == 0) 801ac234f93SGarrett Wollman why = "could not allocate llinfo"; 802ac234f93SGarrett Wollman else if (rt->rt_gateway->sa_family != AF_LINK) 803ac234f93SGarrett Wollman why = "gateway route is not ours"; 804ac234f93SGarrett Wollman 805ac234f93SGarrett Wollman if (why && create) { 806ac234f93SGarrett Wollman log(LOG_DEBUG, "arplookup %s failed: %s\n", 807ef0cdf33SGarrett Wollman inet_ntoa(sin.sin_addr), why); 808ac234f93SGarrett Wollman return 0; 809ac234f93SGarrett Wollman } else if (why) { 810ac234f93SGarrett Wollman return 0; 811df8bae1dSRodney W. Grimes } 812df8bae1dSRodney W. Grimes return ((struct llinfo_arp *)rt->rt_llinfo); 813df8bae1dSRodney W. Grimes } 814df8bae1dSRodney W. Grimes 815dd2e4102SGarrett Wollman void 816dd2e4102SGarrett Wollman arp_ifinit(ac, ifa) 817dd2e4102SGarrett Wollman struct arpcom *ac; 818dd2e4102SGarrett Wollman struct ifaddr *ifa; 819dd2e4102SGarrett Wollman { 820dd570d4dSTor Egge if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) 821ed7509acSJulian Elischer arprequest(ac, &IA_SIN(ifa)->sin_addr, 822ed7509acSJulian Elischer &IA_SIN(ifa)->sin_addr, ac->ac_enaddr); 823dd2e4102SGarrett Wollman ifa->ifa_rtrequest = arp_rtrequest; 824dd2e4102SGarrett Wollman ifa->ifa_flags |= RTF_CLONING; 825dd2e4102SGarrett Wollman } 826df5e1987SJonathan Lemon 827df5e1987SJonathan Lemon static void 828df5e1987SJonathan Lemon arp_init(void) 829df5e1987SJonathan Lemon { 830df5e1987SJonathan Lemon 831df5e1987SJonathan Lemon arpintrq.ifq_maxlen = 50; 832df5e1987SJonathan Lemon mtx_init(&arpintrq.ifq_mtx, "arp_inq", MTX_DEF); 833df5e1987SJonathan Lemon } 834df5e1987SJonathan Lemon 835df5e1987SJonathan Lemon SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); 836