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