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$");
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>
67230442Sbz#ifdef INET
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
76249925Sglebius#define SIN(s) ((const struct sockaddr_in *)(s))
771541Srgrimes#define SDL(s) ((struct sockaddr_dl *)s)
781541Srgrimes
7944078SdfrSYSCTL_DECL(_net_link_ether);
80227309Sedstatic SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");
81227309Sedstatic SYSCTL_NODE(_net_link_ether, PF_ARP, arp, CTLFLAG_RW, 0, "");
821541Srgrimes
8312693Sphk/* timer values */
84215701Sdimstatic VNET_DEFINE(int, arpt_keep) = (20*60);	/* once resolved, good for 20
85195699Srwatson						 * minutes */
86215701Sdimstatic VNET_DEFINE(int, arp_maxtries) = 5;
87207369SbzVNET_DEFINE(int, useloopback) = 1;	/* use loopback interface for
88207369Sbz					 * local traffic */
89215701Sdimstatic VNET_DEFINE(int, arp_proxyall) = 0;
90238945Sglebiusstatic VNET_DEFINE(int, arpt_down) = 20;	/* keep incomplete entries for
91238945Sglebius						 * 20 seconds */
92253084SaeVNET_PCPUSTAT_DEFINE(struct arpstat, arpstat);  /* ARP statistics, see if_arp.h */
93253084SaeVNET_PCPUSTAT_SYSINIT(arpstat);
941541Srgrimes
95253084Sae#ifdef VIMAGE
96253084SaeVNET_PCPUSTAT_SYSUNINIT(arpstat);
97253084Sae#endif /* VIMAGE */
98253084Sae
99215701Sdimstatic VNET_DEFINE(int, arp_maxhold) = 1;
100215207Sgnn
101195727Srwatson#define	V_arpt_keep		VNET(arpt_keep)
102198111Sqingli#define	V_arpt_down		VNET(arpt_down)
103195727Srwatson#define	V_arp_maxtries		VNET(arp_maxtries)
104195727Srwatson#define	V_arp_proxyall		VNET(arp_proxyall)
105215207Sgnn#define	V_arp_maxhold		VNET(arp_maxhold)
10612693Sphk
107195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
108195699Srwatson	&VNET_NAME(arpt_keep), 0,
109195699Srwatson	"ARP entry lifetime in seconds");
110195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
111195699Srwatson	&VNET_NAME(arp_maxtries), 0,
112183550Szec	"ARP resolution attempts before returning error");
113195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
114195699Srwatson	&VNET_NAME(useloopback), 0,
115183550Szec	"Use the loopback interface for local traffic");
116195699SrwatsonSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
117195699Srwatson	&VNET_NAME(arp_proxyall), 0,
118183550Szec	"Enable proxy ARP for all suitable requests");
119215207SgnnSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, wait, CTLFLAG_RW,
120215207Sgnn	&VNET_NAME(arpt_down), 0,
121215207Sgnn	"Incomplete ARP entry lifetime in seconds");
122253084SaeSYSCTL_VNET_PCPUSTAT(_net_link_ether_arp, OID_AUTO, stats, struct arpstat,
123253084Sae    arpstat, "ARP statistics (struct arpstat, net/if_arp.h)");
124215207SgnnSYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, maxhold, CTLFLAG_RW,
125238945Sglebius	&VNET_NAME(arp_maxhold), 0,
126215207Sgnn	"Number of packets to hold per ARP entry");
12712693Sphk
12892723Salfredstatic void	arp_init(void);
129111888Sjlemonstatic void	arpintr(struct mbuf *);
13092723Salfredstatic void	arptimer(void *);
13132350Seivind#ifdef INET
13292723Salfredstatic void	in_arpinput(struct mbuf *);
13332350Seivind#endif
13412693Sphk
135193219Srwatsonstatic const struct netisr_handler arp_nh = {
136193219Srwatson	.nh_name = "arp",
137193219Srwatson	.nh_handler = arpintr,
138193219Srwatson	.nh_proto = NETISR_ARP,
139193219Srwatson	.nh_policy = NETISR_POLICY_SOURCE,
140193219Srwatson};
141193219Srwatson
142186119Sqingli#ifdef AF_INET
1431541Srgrimes/*
144186119Sqingli * called by in_ifscrub to remove entry from the table when
145186119Sqingli * the interface goes away
1461541Srgrimes */
147186119Sqinglivoid
148186119Sqingliarp_ifscrub(struct ifnet *ifp, uint32_t addr)
1491541Srgrimes{
150186119Sqingli	struct sockaddr_in addr4;
1511541Srgrimes
152186119Sqingli	bzero((void *)&addr4, sizeof(addr4));
153186119Sqingli	addr4.sin_len    = sizeof(addr4);
154186119Sqingli	addr4.sin_family = AF_INET;
155186119Sqingli	addr4.sin_addr.s_addr = addr;
156186119Sqingli	IF_AFDATA_LOCK(ifp);
157186119Sqingli	lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR),
158186119Sqingli	    (struct sockaddr *)&addr4);
159186119Sqingli	IF_AFDATA_UNLOCK(ifp);
1601541Srgrimes}
161186119Sqingli#endif
1621541Srgrimes
1631541Srgrimes/*
164186119Sqingli * Timeout routine.  Age arp_tab entries periodically.
1651541Srgrimes */
1665196Swollmanstatic void
167186119Sqingliarptimer(void *arg)
1681541Srgrimes{
169238990Sglebius	struct llentry *lle = (struct llentry *)arg;
170186119Sqingli	struct ifnet *ifp;
1711541Srgrimes
172238990Sglebius	if (lle->la_flags & LLE_STATIC) {
173238990Sglebius		LLE_WUNLOCK(lle);
174238990Sglebius		return;
175238990Sglebius	}
176238990Sglebius
177186119Sqingli	ifp = lle->lle_tbl->llt_ifp;
178196797Sgnn	CURVNET_SET(ifp->if_vnet);
179238990Sglebius
180252577Snp	if ((lle->la_flags & LLE_DELETED) == 0) {
181238990Sglebius		int evt;
182238990Sglebius
183238990Sglebius		if (lle->la_flags & LLE_VALID)
184238990Sglebius			evt = LLENTRY_EXPIRED;
185238990Sglebius		else
186238990Sglebius			evt = LLENTRY_TIMEDOUT;
187238990Sglebius		EVENTHANDLER_INVOKE(lle_event, lle, evt);
188238990Sglebius	}
189238990Sglebius
190238990Sglebius	callout_stop(&lle->la_timer);
191238990Sglebius
192238990Sglebius	/* XXX: LOR avoidance. We still have ref on lle. */
193238990Sglebius	LLE_WUNLOCK(lle);
194186119Sqingli	IF_AFDATA_LOCK(ifp);
195186119Sqingli	LLE_WLOCK(lle);
196237263Snp
197244183Sglebius	/* Guard against race with other llentry_free(). */
198244183Sglebius	if (lle->la_flags & LLE_LINKED) {
199244183Sglebius		size_t pkts_dropped;
200244183Sglebius
201244183Sglebius		LLE_REMREF(lle);
202244183Sglebius		pkts_dropped = llentry_free(lle);
203244183Sglebius		ARPSTAT_ADD(dropped, pkts_dropped);
204244183Sglebius	} else
205244183Sglebius		LLE_FREE_LOCKED(lle);
206244183Sglebius
207186119Sqingli	IF_AFDATA_UNLOCK(ifp);
208244183Sglebius
209238990Sglebius	ARPSTAT_INC(timeouts);
210244183Sglebius
211196797Sgnn	CURVNET_RESTORE();
2121541Srgrimes}
2131541Srgrimes
2141541Srgrimes/*
2151541Srgrimes * Broadcast an ARP request. Caller specifies:
2161541Srgrimes *	- arp header source ip address
2171541Srgrimes *	- arp header target ip address
2181541Srgrimes *	- arp header source ethernet address
2191541Srgrimes */
220186119Sqinglivoid
221249925Sglebiusarprequest(struct ifnet *ifp, const struct in_addr *sip,
222249925Sglebius    const struct in_addr *tip, u_char *enaddr)
2231541Srgrimes{
224126936Smdodd	struct mbuf *m;
225126936Smdodd	struct arphdr *ah;
2261541Srgrimes	struct sockaddr sa;
227229816Sglebius	u_char *carpaddr = NULL;
2281541Srgrimes
229186119Sqingli	if (sip == NULL) {
230186119Sqingli		/*
231186119Sqingli		 * The caller did not supply a source address, try to find
232186119Sqingli		 * a compatible one among those assigned to this interface.
233186119Sqingli		 */
234186119Sqingli		struct ifaddr *ifa;
235186119Sqingli
236229816Sglebius		IF_ADDR_RLOCK(ifp);
237186119Sqingli		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
238229816Sglebius			if (ifa->ifa_addr->sa_family != AF_INET)
239186119Sqingli				continue;
240229816Sglebius
241229816Sglebius			if (ifa->ifa_carp) {
242229816Sglebius				if ((*carp_iamatch_p)(ifa, &carpaddr) == 0)
243229816Sglebius					continue;
244229816Sglebius				sip = &IA_SIN(ifa)->sin_addr;
245229816Sglebius			} else {
246229816Sglebius				carpaddr = NULL;
247229816Sglebius				sip = &IA_SIN(ifa)->sin_addr;
248229816Sglebius			}
249229816Sglebius
250186119Sqingli			if (0 == ((sip->s_addr ^ tip->s_addr) &
251229816Sglebius			    IA_MASKSIN(ifa)->sin_addr.s_addr))
252186119Sqingli				break;  /* found it. */
253186119Sqingli		}
254229816Sglebius		IF_ADDR_RUNLOCK(ifp);
255238945Sglebius		if (sip == NULL) {
256186119Sqingli			printf("%s: cannot find matching address\n", __func__);
257186119Sqingli			return;
258186119Sqingli		}
259186119Sqingli	}
260229816Sglebius	if (enaddr == NULL)
261229816Sglebius		enaddr = carpaddr ? carpaddr : (u_char *)IF_LLADDR(ifp);
262186119Sqingli
263243882Sglebius	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
2641541Srgrimes		return;
265127261Smdodd	m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
266127261Smdodd		2*ifp->if_data.ifi_addrlen;
267127277Smdodd	m->m_pkthdr.len = m->m_len;
268127277Smdodd	MH_ALIGN(m, m->m_len);
269127277Smdodd	ah = mtod(m, struct arphdr *);
270127261Smdodd	bzero((caddr_t)ah, m->m_len);
271101090Srwatson#ifdef MAC
272173095Srwatson	mac_netinet_arp_send(ifp, m);
273101090Srwatson#endif
27484931Sfjoe	ah->ar_pro = htons(ETHERTYPE_IP);
27584931Sfjoe	ah->ar_hln = ifp->if_addrlen;		/* hardware address length */
27684931Sfjoe	ah->ar_pln = sizeof(struct in_addr);	/* protocol address length */
27784931Sfjoe	ah->ar_op = htons(ARPOP_REQUEST);
278249925Sglebius	bcopy(enaddr, ar_sha(ah), ah->ar_hln);
279249925Sglebius	bcopy(sip, ar_spa(ah), ah->ar_pln);
280249925Sglebius	bcopy(tip, ar_tpa(ah), ah->ar_pln);
281127261Smdodd	sa.sa_family = AF_ARP;
282127261Smdodd	sa.sa_len = 2;
283127261Smdodd	m->m_flags |= M_BCAST;
284254523Sandre	m_clrprotoflags(m);	/* Avoid confusing lower layers. */
285191148Skmacy	(*ifp->if_output)(ifp, m, &sa, NULL);
286196797Sgnn	ARPSTAT_INC(txrequests);
2871541Srgrimes}
2881541Srgrimes
2891541Srgrimes/*
290128636Sluigi * Resolve an IP address into an ethernet address.
291128636Sluigi * On input:
292128636Sluigi *    ifp is the interface we use
293175025Sjulian *    rt0 is the route to the final destination (possibly useless)
294175025Sjulian *    m is the mbuf. May be NULL if we don't have a packet.
295128636Sluigi *    dst is the next hop,
296128636Sluigi *    desten is where we want the address.
297128636Sluigi *
298128636Sluigi * On success, desten is filled in and the function returns 0;
299128636Sluigi * If the packet must be held pending resolution, we return EWOULDBLOCK
300128636Sluigi * On other errors, we return the corresponding error code.
301175025Sjulian * Note that m_freem() handles NULL.
3021541Srgrimes */
3031541Srgrimesint
304128636Sluigiarpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
305249925Sglebius	const struct sockaddr *dst, u_char *desten, struct llentry **lle)
3061541Srgrimes{
307186119Sqingli	struct llentry *la = 0;
308186200Skmacy	u_int flags = 0;
309215207Sgnn	struct mbuf *curr = NULL;
310215207Sgnn	struct mbuf *next = NULL;
311186119Sqingli	int error, renew;
3121541Srgrimes
313186119Sqingli	*lle = NULL;
314186119Sqingli	if (m != NULL) {
315175025Sjulian		if (m->m_flags & M_BCAST) {
316175025Sjulian			/* broadcast */
317175025Sjulian			(void)memcpy(desten,
318175025Sjulian			    ifp->if_broadcastaddr, ifp->if_addrlen);
319175025Sjulian			return (0);
320175025Sjulian		}
321175025Sjulian		if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) {
322175025Sjulian			/* multicast */
323175025Sjulian			ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
324175025Sjulian			return (0);
325175025Sjulian		}
3261541Srgrimes	}
327186119Sqingliretry:
328238967Sglebius	IF_AFDATA_RLOCK(ifp);
329186119Sqingli	la = lla_lookup(LLTABLE(ifp), flags, dst);
330238967Sglebius	IF_AFDATA_RUNLOCK(ifp);
331186200Skmacy	if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0)
332238967Sglebius	    && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) {
333186200Skmacy		flags |= (LLE_CREATE | LLE_EXCLUSIVE);
334238967Sglebius		IF_AFDATA_WLOCK(ifp);
335186200Skmacy		la = lla_lookup(LLTABLE(ifp), flags, dst);
336238967Sglebius		IF_AFDATA_WUNLOCK(ifp);
337186200Skmacy	}
338148955Sglebius	if (la == NULL) {
339186119Sqingli		if (flags & LLE_CREATE)
340148955Sglebius			log(LOG_DEBUG,
341148955Sglebius			    "arpresolve: can't allocate llinfo for %s\n",
342148955Sglebius			    inet_ntoa(SIN(dst)->sin_addr));
343186119Sqingli		m_freem(m);
344186119Sqingli		return (EINVAL);
345238945Sglebius	}
346149909Sglebius
347186119Sqingli	if ((la->la_flags & LLE_VALID) &&
348216075Sglebius	    ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) {
349186119Sqingli		bcopy(&la->ll_addr, desten, ifp->if_addrlen);
35092802Sorion		/*
35192802Sorion		 * If entry has an expiry time and it is approaching,
352186119Sqingli		 * see if we need to send an ARP request within this
353186119Sqingli		 * arpt_down interval.
35492802Sorion		 */
355186119Sqingli		if (!(la->la_flags & LLE_STATIC) &&
356216075Sglebius		    time_uptime + la->la_preempt > la->la_expire) {
357229816Sglebius			arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
358110544Sorion			la->la_preempt--;
359186119Sqingli		}
360238967Sglebius
361186119Sqingli		*lle = la;
362186119Sqingli		error = 0;
363186119Sqingli		goto done;
364238945Sglebius	}
365238945Sglebius
366186119Sqingli	if (la->la_flags & LLE_STATIC) {   /* should not happen! */
367186119Sqingli		log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n",
368186119Sqingli		    inet_ntoa(SIN(dst)->sin_addr));
369186119Sqingli		m_freem(m);
370186119Sqingli		error = EINVAL;
371186119Sqingli		goto done;
372186119Sqingli	}
37392802Sorion
374216075Sglebius	renew = (la->la_asked == 0 || la->la_expire != time_uptime);
375186119Sqingli	if ((renew || m != NULL) && (flags & LLE_EXCLUSIVE) == 0) {
376186119Sqingli		flags |= LLE_EXCLUSIVE;
377186119Sqingli		LLE_RUNLOCK(la);
378186119Sqingli		goto retry;
3791541Srgrimes	}
3801541Srgrimes	/*
3811541Srgrimes	 * There is an arptab entry, but no ethernet address
382215207Sgnn	 * response yet.  Add the mbuf to the list, dropping
383215207Sgnn	 * the oldest packet if we have exceeded the system
384215207Sgnn	 * setting.
3851541Srgrimes	 */
386186119Sqingli	if (m != NULL) {
387215207Sgnn		if (la->la_numheld >= V_arp_maxhold) {
388215207Sgnn			if (la->la_hold != NULL) {
389215207Sgnn				next = la->la_hold->m_nextpkt;
390215207Sgnn				m_freem(la->la_hold);
391215207Sgnn				la->la_hold = next;
392215207Sgnn				la->la_numheld--;
393215207Sgnn				ARPSTAT_INC(dropped);
394215207Sgnn			}
395238945Sglebius		}
396196797Sgnn		if (la->la_hold != NULL) {
397215207Sgnn			curr = la->la_hold;
398215207Sgnn			while (curr->m_nextpkt != NULL)
399215207Sgnn				curr = curr->m_nextpkt;
400215207Sgnn			curr->m_nextpkt = m;
401238945Sglebius		} else
402215207Sgnn			la->la_hold = m;
403215207Sgnn		la->la_numheld++;
404186119Sqingli		if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
405186119Sqingli			flags &= ~LLE_EXCLUSIVE;
406186119Sqingli			LLE_DOWNGRADE(la);
407186119Sqingli		}
408238967Sglebius
409174699Skmacy	}
410152188Sglebius	/*
411152188Sglebius	 * Return EWOULDBLOCK if we have tried less than arp_maxtries. It
412152188Sglebius	 * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH
413152188Sglebius	 * if we have already sent arp_maxtries ARP requests. Retransmit the
414152188Sglebius	 * ARP request, but not faster than one request per second.
415152188Sglebius	 */
416181803Sbz	if (la->la_asked < V_arp_maxtries)
417152188Sglebius		error = EWOULDBLOCK;	/* First request. */
418152188Sglebius	else
419201416Snp		error = rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) ?
420201416Snp		    EHOSTUNREACH : EHOSTDOWN;
421152188Sglebius
422186119Sqingli	if (renew) {
423206481Sbz		int canceled;
424206481Sbz
425186119Sqingli		LLE_ADDREF(la);
426216075Sglebius		la->la_expire = time_uptime;
427206481Sbz		canceled = callout_reset(&la->la_timer, hz * V_arpt_down,
428206481Sbz		    arptimer, la);
429206481Sbz		if (canceled)
430206481Sbz			LLE_REMREF(la);
431166010Smaxim		la->la_asked++;
432186119Sqingli		LLE_WUNLOCK(la);
433229816Sglebius		arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
434186119Sqingli		return (error);
435186119Sqingli	}
436186119Sqinglidone:
437186119Sqingli	if (flags & LLE_EXCLUSIVE)
438186119Sqingli		LLE_WUNLOCK(la);
439186119Sqingli	else
440186119Sqingli		LLE_RUNLOCK(la);
441152188Sglebius	return (error);
4421541Srgrimes}
4431541Srgrimes
4441541Srgrimes/*
4451541Srgrimes * Common length and type checks are done here,
4461541Srgrimes * then the protocol-specific routine is called.
4471541Srgrimes */
44812693Sphkstatic void
449111888Sjlemonarpintr(struct mbuf *m)
4501541Srgrimes{
451111888Sjlemon	struct arphdr *ar;
4521541Srgrimes
453111888Sjlemon	if (m->m_len < sizeof(struct arphdr) &&
454111888Sjlemon	    ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {
455227785Sglebius		log(LOG_NOTICE, "arp: runt packet -- m_pullup failed\n");
456111888Sjlemon		return;
457111888Sjlemon	}
458111888Sjlemon	ar = mtod(m, struct arphdr *);
4591541Srgrimes
460111888Sjlemon	if (ntohs(ar->ar_hrd) != ARPHRD_ETHER &&
461111888Sjlemon	    ntohs(ar->ar_hrd) != ARPHRD_IEEE802 &&
462130407Sdfr	    ntohs(ar->ar_hrd) != ARPHRD_ARCNET &&
463219819Sjeff	    ntohs(ar->ar_hrd) != ARPHRD_IEEE1394 &&
464219819Sjeff	    ntohs(ar->ar_hrd) != ARPHRD_INFINIBAND) {
465227790Sglebius		log(LOG_NOTICE, "arp: unknown hardware address format (0x%2D)"
466227790Sglebius		    " (from %*D to %*D)\n", (unsigned char *)&ar->ar_hrd, "",
467227790Sglebius		    ETHER_ADDR_LEN, (u_char *)ar_sha(ar), ":",
468227790Sglebius		    ETHER_ADDR_LEN, (u_char *)ar_tha(ar), ":");
469111888Sjlemon		m_freem(m);
470111888Sjlemon		return;
471111888Sjlemon	}
4721541Srgrimes
473123768Sru	if (m->m_len < arphdr_len(ar)) {
474123765Sru		if ((m = m_pullup(m, arphdr_len(ar))) == NULL) {
475227785Sglebius			log(LOG_NOTICE, "arp: runt packet\n");
476123765Sru			m_freem(m);
477123765Sru			return;
478123765Sru		}
479123765Sru		ar = mtod(m, struct arphdr *);
480111888Sjlemon	}
48157900Srwatson
482196797Sgnn	ARPSTAT_INC(received);
483111888Sjlemon	switch (ntohs(ar->ar_pro)) {
48432350Seivind#ifdef INET
485111888Sjlemon	case ETHERTYPE_IP:
486111888Sjlemon		in_arpinput(m);
487111888Sjlemon		return;
48832350Seivind#endif
4891541Srgrimes	}
490111888Sjlemon	m_freem(m);
4911541Srgrimes}
4921541Srgrimes
49332350Seivind#ifdef INET
4941541Srgrimes/*
4951541Srgrimes * ARP for Internet protocols on 10 Mb/s Ethernet.
4961541Srgrimes * Algorithm is that given in RFC 826.
4971541Srgrimes * In addition, a sanity check is performed on the sender
4981541Srgrimes * protocol address, to catch impersonators.
4991541Srgrimes * We no longer handle negotiations for use of trailer protocol:
5001541Srgrimes * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
5011541Srgrimes * along with IP replies if we wanted trailers sent to us,
5021541Srgrimes * and also sent them in response to IP replies.
5031541Srgrimes * This allowed either end to announce the desire to receive
5041541Srgrimes * trailer packets.
5051541Srgrimes * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
5061541Srgrimes * but formerly didn't normally send requests.
5071541Srgrimes */
50870699Salfredstatic int log_arp_wrong_iface = 1;
50982893Salfredstatic int log_arp_movements = 1;
510153513Sglebiusstatic int log_arp_permanent_modify = 1;
511240073Sglebiusstatic int allow_multicast = 0;
512250504Sglebiusstatic struct timeval arp_lastlog;
513250504Sglebiusstatic int arp_curpps;
514250504Sglebiusstatic int arp_maxpps = 1;
51570699Salfred
51670699SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW,
51770699Salfred	&log_arp_wrong_iface, 0,
51870699Salfred	"log arp packets arriving on the wrong interface");
51982893SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_movements, CTLFLAG_RW,
520238945Sglebius	&log_arp_movements, 0,
521238945Sglebius	"log arp replies from MACs different than the one in the cache");
522153513SglebiusSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_permanent_modify, CTLFLAG_RW,
523238945Sglebius	&log_arp_permanent_modify, 0,
524238945Sglebius	"log arp replies from MACs different than the one in the permanent arp entry");
525240073SglebiusSYSCTL_INT(_net_link_ether_inet, OID_AUTO, allow_multicast, CTLFLAG_RW,
526240073Sglebius	&allow_multicast, 0, "accept multicast addresses");
527250504SglebiusSYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_log_per_second,
528250504Sglebius	CTLFLAG_RW, &arp_maxpps, 0,
529250504Sglebius	"Maximum number of remotely triggered ARP messages that can be "
530250504Sglebius	"logged per second");
53170699Salfred
532250504Sglebius#define	ARP_LOG(pri, ...)	do {					\
533250504Sglebius	if (ppsratecheck(&arp_lastlog, &arp_curpps, arp_maxpps))	\
534250504Sglebius		log((pri), "arp: " __VA_ARGS__);			\
535250504Sglebius} while (0)
536250504Sglebius
5371541Srgrimesstatic void
538169454Srwatsonin_arpinput(struct mbuf *m)
5391541Srgrimes{
540126936Smdodd	struct arphdr *ah;
541126936Smdodd	struct ifnet *ifp = m->m_pkthdr.rcvif;
542186119Sqingli	struct llentry *la = NULL;
543126936Smdodd	struct rtentry *rt;
54484102Sjlemon	struct ifaddr *ifa;
54584102Sjlemon	struct in_ifaddr *ia;
5461541Srgrimes	struct sockaddr sa;
5471541Srgrimes	struct in_addr isaddr, itaddr, myaddr;
548142215Sglebius	u_int8_t *enaddr = NULL;
549186119Sqingli	int op, flags;
55084931Sfjoe	int req_len;
551181824Sphilip	int bridged = 0, is_bridge = 0;
552228571Sglebius	int carped;
553174559Skmacy	struct sockaddr_in sin;
554174559Skmacy	sin.sin_len = sizeof(struct sockaddr_in);
555174559Skmacy	sin.sin_family = AF_INET;
556174703Skmacy	sin.sin_addr.s_addr = 0;
557183550Szec
558155018Sthompsa	if (ifp->if_bridge)
559146986Sthompsa		bridged = 1;
560181824Sphilip	if (ifp->if_type == IFT_BRIDGE)
561181824Sphilip		is_bridge = 1;
562146986Sthompsa
56384931Sfjoe	req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
56484931Sfjoe	if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) {
565250504Sglebius		ARP_LOG(LOG_NOTICE, "runt packet -- m_pullup failed\n");
56674851Syar		return;
56774851Syar	}
56874851Syar
56984931Sfjoe	ah = mtod(m, struct arphdr *);
570238945Sglebius	/*
571217315Sgnn	 * ARP is only for IPv4 so we can reject packets with
572217315Sgnn	 * a protocol length not equal to an IPv4 address.
573217315Sgnn	 */
574217315Sgnn	if (ah->ar_pln != sizeof(struct in_addr)) {
575250504Sglebius		ARP_LOG(LOG_NOTICE, "requested protocol length != %zu\n",
576217315Sgnn		    sizeof(struct in_addr));
577249903Sglebius		goto drop;
578217315Sgnn	}
579217315Sgnn
580240073Sglebius	if (allow_multicast == 0 && ETHER_IS_MULTICAST(ar_sha(ah))) {
581250504Sglebius		ARP_LOG(LOG_NOTICE, "%*D is multicast\n",
582227785Sglebius		    ifp->if_addrlen, (u_char *)ar_sha(ah), ":");
583249903Sglebius		goto drop;
584217315Sgnn	}
585217315Sgnn
58684931Sfjoe	op = ntohs(ah->ar_op);
58784931Sfjoe	(void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr));
58884931Sfjoe	(void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr));
589134991Sglebius
590196797Sgnn	if (op == ARPOP_REPLY)
591196797Sgnn		ARPSTAT_INC(rxreplies);
592196797Sgnn
59384102Sjlemon	/*
59484102Sjlemon	 * For a bridge, we want to check the address irrespective
59584102Sjlemon	 * of the receive interface. (This will change slightly
59684102Sjlemon	 * when we have clusters of interfaces).
59784102Sjlemon	 */
598194951Srwatson	IN_IFADDR_RLOCK();
599143314Sglebius	LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) {
600217829Sthompsa		if (((bridged && ia->ia_ifp->if_bridge == ifp->if_bridge) ||
601186119Sqingli		    ia->ia_ifp == ifp) &&
602228571Sglebius		    itaddr.s_addr == ia->ia_addr.sin_addr.s_addr &&
603228571Sglebius		    (ia->ia_ifa.ifa_carp == NULL ||
604228571Sglebius		    (*carp_iamatch_p)(&ia->ia_ifa, &enaddr))) {
605194820Srwatson			ifa_ref(&ia->ia_ifa);
606194951Srwatson			IN_IFADDR_RUNLOCK();
607143314Sglebius			goto match;
608194820Srwatson		}
609143314Sglebius	}
61084102Sjlemon	LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash)
611217829Sthompsa		if (((bridged && ia->ia_ifp->if_bridge == ifp->if_bridge) ||
612186119Sqingli		    ia->ia_ifp == ifp) &&
613194820Srwatson		    isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) {
614194820Srwatson			ifa_ref(&ia->ia_ifa);
615194951Srwatson			IN_IFADDR_RUNLOCK();
61684102Sjlemon			goto match;
617194820Srwatson		}
618181824Sphilip
619181824Sphilip#define BDG_MEMBER_MATCHES_ARP(addr, ifp, ia)				\
620181824Sphilip  (ia->ia_ifp->if_bridge == ifp->if_softc &&				\
621181824Sphilip  !bcmp(IF_LLADDR(ia->ia_ifp), IF_LLADDR(ifp), ifp->if_addrlen) &&	\
622181824Sphilip  addr == ia->ia_addr.sin_addr.s_addr)
62384102Sjlemon	/*
624181824Sphilip	 * Check the case when bridge shares its MAC address with
625181824Sphilip	 * some of its children, so packets are claimed by bridge
626181824Sphilip	 * itself (bridge_input() does it first), but they are really
627181824Sphilip	 * meant to be destined to the bridge member.
628181824Sphilip	 */
629181824Sphilip	if (is_bridge) {
630181824Sphilip		LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) {
631181824Sphilip			if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) {
632194820Srwatson				ifa_ref(&ia->ia_ifa);
633181824Sphilip				ifp = ia->ia_ifp;
634194951Srwatson				IN_IFADDR_RUNLOCK();
635181824Sphilip				goto match;
636181824Sphilip			}
637181824Sphilip		}
638181824Sphilip	}
639181824Sphilip#undef BDG_MEMBER_MATCHES_ARP
640194951Srwatson	IN_IFADDR_RUNLOCK();
641181824Sphilip
642181824Sphilip	/*
64385223Sjlemon	 * No match, use the first inet address on the receive interface
64484102Sjlemon	 * as a dummy address for the rest of the function.
64584102Sjlemon	 */
646229621Sjhb	IF_ADDR_RLOCK(ifp);
64785223Sjlemon	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
648228959Sglebius		if (ifa->ifa_addr->sa_family == AF_INET &&
649228959Sglebius		    (ifa->ifa_carp == NULL ||
650228959Sglebius		    (*carp_iamatch_p)(ifa, &enaddr))) {
65185466Sjlemon			ia = ifatoia(ifa);
652194820Srwatson			ifa_ref(ifa);
653229621Sjhb			IF_ADDR_RUNLOCK(ifp);
65485466Sjlemon			goto match;
65585466Sjlemon		}
656229621Sjhb	IF_ADDR_RUNLOCK(ifp);
657194820Srwatson
65885466Sjlemon	/*
65985466Sjlemon	 * If bridging, fall back to using any inet address.
66085466Sjlemon	 */
661194951Srwatson	IN_IFADDR_RLOCK();
662194951Srwatson	if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) {
663194951Srwatson		IN_IFADDR_RUNLOCK();
664128645Sluigi		goto drop;
665194951Srwatson	}
666194820Srwatson	ifa_ref(&ia->ia_ifa);
667194951Srwatson	IN_IFADDR_RUNLOCK();
66884102Sjlemonmatch:
669142215Sglebius	if (!enaddr)
670142215Sglebius		enaddr = (u_int8_t *)IF_LLADDR(ifp);
671228571Sglebius	carped = (ia->ia_ifa.ifa_carp != NULL);
67284102Sjlemon	myaddr = ia->ia_addr.sin_addr;
673194820Srwatson	ifa_free(&ia->ia_ifa);
674142215Sglebius	if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen))
675128645Sluigi		goto drop;	/* it's from me, ignore it. */
67684931Sfjoe	if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) {
677250504Sglebius		ARP_LOG(LOG_NOTICE, "link address is broadcast for IP address "
678250504Sglebius		    "%s!\n", inet_ntoa(isaddr));
679128645Sluigi		goto drop;
6801541Srgrimes	}
681136441Srwatson	/*
682136441Srwatson	 * Warn if another host is using the same IP address, but only if the
683136441Srwatson	 * IP address isn't 0.0.0.0, which is used for DHCP only, in which
684136441Srwatson	 * case we suppress the warning to avoid false positive complaints of
685136441Srwatson	 * potential misconfiguration.
686136441Srwatson	 */
687228571Sglebius	if (!bridged && !carped && isaddr.s_addr == myaddr.s_addr &&
688228571Sglebius	    myaddr.s_addr != 0) {
689250504Sglebius		ARP_LOG(LOG_ERR, "%*D is using my IP address %s on %s!\n",
69084931Sfjoe		   ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
691174256Syar		   inet_ntoa(isaddr), ifp->if_xname);
6921541Srgrimes		itaddr = myaddr;
693196797Sgnn		ARPSTAT_INC(dupips);
6941541Srgrimes		goto reply;
6951541Srgrimes	}
696120626Sru	if (ifp->if_flags & IFF_STATICARP)
697120626Sru		goto reply;
698148955Sglebius
699186119Sqingli	bzero(&sin, sizeof(sin));
700186119Sqingli	sin.sin_len = sizeof(struct sockaddr_in);
701186119Sqingli	sin.sin_family = AF_INET;
702186119Sqingli	sin.sin_addr = isaddr;
703186119Sqingli	flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0;
704186119Sqingli	flags |= LLE_EXCLUSIVE;
705238945Sglebius	IF_AFDATA_LOCK(ifp);
706186119Sqingli	la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
707186119Sqingli	IF_AFDATA_UNLOCK(ifp);
708186119Sqingli	if (la != NULL) {
709186119Sqingli		/* the following is not an error when doing bridging */
710228571Sglebius		if (!bridged && la->lle_tbl->llt_ifp != ifp) {
711186119Sqingli			if (log_arp_wrong_iface)
712250504Sglebius				ARP_LOG(LOG_WARNING, "%s is on %s "
713186119Sqingli				    "but got reply from %*D on %s\n",
714186119Sqingli				    inet_ntoa(isaddr),
715186119Sqingli				    la->lle_tbl->llt_ifp->if_xname,
716186119Sqingli				    ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
717186119Sqingli				    ifp->if_xname);
718196738Sbz			LLE_WUNLOCK(la);
719186119Sqingli			goto reply;
720186119Sqingli		}
721186119Sqingli		if ((la->la_flags & LLE_VALID) &&
722186119Sqingli		    bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) {
723186119Sqingli			if (la->la_flags & LLE_STATIC) {
724196738Sbz				LLE_WUNLOCK(la);
725223840Sae				if (log_arp_permanent_modify)
726250504Sglebius					ARP_LOG(LOG_ERR,
727250504Sglebius					    "%*D attempts to modify "
728223840Sae					    "permanent entry for %s on %s\n",
729223840Sae					    ifp->if_addrlen,
730223840Sae					    (u_char *)ar_sha(ah), ":",
731223840Sae					    inet_ntoa(isaddr), ifp->if_xname);
732186119Sqingli				goto reply;
733178888Sjulian			}
734186119Sqingli			if (log_arp_movements) {
735250504Sglebius				ARP_LOG(LOG_INFO, "%s moved from %*D "
736186119Sqingli				    "to %*D on %s\n",
737186119Sqingli				    inet_ntoa(isaddr),
738186119Sqingli				    ifp->if_addrlen,
739186119Sqingli				    (u_char *)&la->ll_addr, ":",
740186119Sqingli				    ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
741186119Sqingli				    ifp->if_xname);
742178888Sjulian			}
743178888Sjulian		}
744238945Sglebius
745186119Sqingli		if (ifp->if_addrlen != ah->ar_hln) {
746196738Sbz			LLE_WUNLOCK(la);
747250504Sglebius			ARP_LOG(LOG_WARNING, "from %*D: addr len: new %d, "
748227785Sglebius			    "i/f %d (ignored)\n", ifp->if_addrlen,
749227785Sglebius			    (u_char *) ar_sha(ah), ":", ah->ar_hln,
750227785Sglebius			    ifp->if_addrlen);
751217315Sgnn			goto drop;
752178888Sjulian		}
753186119Sqingli		(void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen);
754186119Sqingli		la->la_flags |= LLE_VALID;
755178888Sjulian
756237263Snp		EVENTHANDLER_INVOKE(lle_event, la, LLENTRY_RESOLVED);
757196995Snp
758186119Sqingli		if (!(la->la_flags & LLE_STATIC)) {
759206481Sbz			int canceled;
760206481Sbz
761206481Sbz			LLE_ADDREF(la);
762216075Sglebius			la->la_expire = time_uptime + V_arpt_keep;
763206481Sbz			canceled = callout_reset(&la->la_timer,
764206481Sbz			    hz * V_arpt_keep, arptimer, la);
765206481Sbz			if (canceled)
766206481Sbz				LLE_REMREF(la);
76739389Sfenner		}
768178888Sjulian		la->la_asked = 0;
769181803Sbz		la->la_preempt = V_arp_maxtries;
770238945Sglebius		/*
771215207Sgnn		 * The packets are all freed within the call to the output
772215207Sgnn		 * routine.
773215207Sgnn		 *
774215207Sgnn		 * NB: The lock MUST be released before the call to the
775215207Sgnn		 * output routine.
776215207Sgnn		 */
777215207Sgnn		if (la->la_hold != NULL) {
778215207Sgnn			struct mbuf *m_hold, *m_hold_next;
779215207Sgnn
780217113Sgnn			m_hold = la->la_hold;
781217113Sgnn			la->la_hold = NULL;
782217113Sgnn			la->la_numheld = 0;
783186119Sqingli			memcpy(&sa, L3_ADDR(la), sizeof(sa));
784215207Sgnn			LLE_WUNLOCK(la);
785217121Sgnn			for (; m_hold != NULL; m_hold = m_hold_next) {
786215207Sgnn				m_hold_next = m_hold->m_nextpkt;
787215207Sgnn				m_hold->m_nextpkt = NULL;
788254523Sandre				/* Avoid confusing lower layers. */
789254523Sandre				m_clrprotoflags(m_hold);
790215207Sgnn				(*ifp->if_output)(ifp, m_hold, &sa, NULL);
791215207Sgnn			}
792215207Sgnn		} else
793215207Sgnn			LLE_WUNLOCK(la);
794223261Sbz	}
795178888Sjulianreply:
796128645Sluigi	if (op != ARPOP_REQUEST)
797128645Sluigi		goto drop;
798196797Sgnn	ARPSTAT_INC(rxrequests);
799186119Sqingli
8001541Srgrimes	if (itaddr.s_addr == myaddr.s_addr) {
801178888Sjulian		/* Shortcut.. the receiving interface is the target. */
80284931Sfjoe		(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
803142215Sglebius		(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
8041541Srgrimes	} else {
805186317Sqingli		struct llentry *lle = NULL;
8063282Swollman
807186317Sqingli		sin.sin_addr = itaddr;
808238945Sglebius		IF_AFDATA_LOCK(ifp);
809197225Sqingli		lle = lla_lookup(LLTABLE(ifp), 0, (struct sockaddr *)&sin);
810197225Sqingli		IF_AFDATA_UNLOCK(ifp);
811186317Sqingli
812197225Sqingli		if ((lle != NULL) && (lle->la_flags & LLE_PUB)) {
813186317Sqingli			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
814186317Sqingli			(void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln);
815186317Sqingli			LLE_RUNLOCK(lle);
816197225Sqingli		} else {
81763080Sdwmalone
818197225Sqingli			if (lle != NULL)
819197225Sqingli				LLE_RUNLOCK(lle);
820186317Sqingli
821197225Sqingli			if (!V_arp_proxyall)
822197225Sqingli				goto drop;
823238967Sglebius
824197225Sqingli			sin.sin_addr = itaddr;
825197225Sqingli			/* XXX MRT use table 0 for arp reply  */
826197225Sqingli			rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0);
827197225Sqingli			if (!rt)
828197225Sqingli				goto drop;
829197225Sqingli
830197225Sqingli			/*
831197225Sqingli			 * Don't send proxies for nodes on the same interface
832197225Sqingli			 * as this one came out of, or we'll get into a fight
833197225Sqingli			 * over who claims what Ether address.
834197225Sqingli			 */
835197225Sqingli			if (!rt->rt_ifp || rt->rt_ifp == ifp) {
836197225Sqingli				RTFREE_LOCKED(rt);
837197225Sqingli				goto drop;
838197225Sqingli			}
839185713Scsjp			RTFREE_LOCKED(rt);
84063080Sdwmalone
841197225Sqingli			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
842197225Sqingli			(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
843197225Sqingli
844197225Sqingli			/*
845197225Sqingli			 * Also check that the node which sent the ARP packet
846218909Sbrucec			 * is on the interface we expect it to be on. This
847197225Sqingli			 * avoids ARP chaos if an interface is connected to the
848197225Sqingli			 * wrong network.
849197225Sqingli			 */
850197225Sqingli			sin.sin_addr = isaddr;
851238967Sglebius
852197225Sqingli			/* XXX MRT use table 0 for arp checks */
853197225Sqingli			rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0);
854197225Sqingli			if (!rt)
855197225Sqingli				goto drop;
856197225Sqingli			if (rt->rt_ifp != ifp) {
857250504Sglebius				ARP_LOG(LOG_INFO, "proxy: ignoring request"
858197225Sqingli				    " from %s via %s, expecting %s\n",
859197225Sqingli				    inet_ntoa(isaddr), ifp->if_xname,
860197225Sqingli				    rt->rt_ifp->if_xname);
861197225Sqingli				RTFREE_LOCKED(rt);
862197225Sqingli				goto drop;
863197225Sqingli			}
864197225Sqingli			RTFREE_LOCKED(rt);
865197225Sqingli
8664069Swollman#ifdef DEBUG_PROXY
867238945Sglebius			printf("arp: proxying for %s\n", inet_ntoa(itaddr));
8684069Swollman#endif
869197225Sqingli		}
8701541Srgrimes	}
8711541Srgrimes
872166436Sbms	if (itaddr.s_addr == myaddr.s_addr &&
873166436Sbms	    IN_LINKLOCAL(ntohl(itaddr.s_addr))) {
874166436Sbms		/* RFC 3927 link-local IPv4; always reply by broadcast. */
875166436Sbms#ifdef DEBUG_LINKLOCAL
876166436Sbms		printf("arp: sending reply for link-local addr %s\n",
877166436Sbms		    inet_ntoa(itaddr));
878166436Sbms#endif
879166436Sbms		m->m_flags |= M_BCAST;
880166436Sbms		m->m_flags &= ~M_MCAST;
881166436Sbms	} else {
882166436Sbms		/* default behaviour; never reply by broadcast. */
883166436Sbms		m->m_flags &= ~(M_BCAST|M_MCAST);
884166436Sbms	}
88584931Sfjoe	(void)memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
88684931Sfjoe	(void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
88784931Sfjoe	ah->ar_op = htons(ARPOP_REPLY);
88884931Sfjoe	ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */
889238945Sglebius	m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln);
890238945Sglebius	m->m_pkthdr.len = m->m_len;
891223753Sae	m->m_pkthdr.rcvif = NULL;
892127261Smdodd	sa.sa_family = AF_ARP;
893127261Smdodd	sa.sa_len = 2;
894254523Sandre	m_clrprotoflags(m);	/* Avoid confusing lower layers. */
895191148Skmacy	(*ifp->if_output)(ifp, m, &sa, NULL);
896196797Sgnn	ARPSTAT_INC(txreplies);
8971541Srgrimes	return;
898128645Sluigi
899128645Sluigidrop:
900128645Sluigi	m_freem(m);
9011541Srgrimes}
90232350Seivind#endif
9031541Srgrimes
9045195Swollmanvoid
905169454Srwatsonarp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
9065195Swollman{
907186119Sqingli	struct llentry *lle;
908186119Sqingli
909228571Sglebius	if (ifa->ifa_carp != NULL)
910228571Sglebius		return;
911228571Sglebius
912186411Sqingli	if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) {
91384931Sfjoe		arprequest(ifp, &IA_SIN(ifa)->sin_addr,
91484931Sfjoe				&IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp));
915238945Sglebius		/*
916186411Sqingli		 * interface address is considered static entry
917186411Sqingli		 * because the output of the arp utility shows
918186411Sqingli		 * that L2 entry as permanent
919186411Sqingli		 */
920186411Sqingli		IF_AFDATA_LOCK(ifp);
921186411Sqingli		lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | LLE_STATIC),
922186411Sqingli				 (struct sockaddr *)IA_SIN(ifa));
923186411Sqingli		IF_AFDATA_UNLOCK(ifp);
924186411Sqingli		if (lle == NULL)
925186411Sqingli			log(LOG_INFO, "arp_ifinit: cannot create arp "
926186411Sqingli			    "entry for interface address\n");
927186411Sqingli		else
928186411Sqingli			LLE_RUNLOCK(lle);
929186411Sqingli	}
930186119Sqingli	ifa->ifa_rtrequest = NULL;
9315195Swollman}
93269152Sjlemon
933142215Sglebiusvoid
934169454Srwatsonarp_ifinit2(struct ifnet *ifp, struct ifaddr *ifa, u_char *enaddr)
935142215Sglebius{
936142215Sglebius	if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY)
937142215Sglebius		arprequest(ifp, &IA_SIN(ifa)->sin_addr,
938142215Sglebius				&IA_SIN(ifa)->sin_addr, enaddr);
939186119Sqingli	ifa->ifa_rtrequest = NULL;
940142215Sglebius}
941142215Sglebius
942190787Szecstatic void
943190787Szecarp_init(void)
944190787Szec{
945190787Szec
946193219Srwatson	netisr_register(&arp_nh);
94769152Sjlemon}
94869152SjlemonSYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
949