if_ether.c revision 142215
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
3050477Speter * $FreeBSD: head/sys/netinet/if_ether.c 142215 2005-02-22 13:04:05Z glebius $
311541Srgrimes */
321541Srgrimes
331541Srgrimes/*
341541Srgrimes * Ethernet address resolution protocol.
351541Srgrimes * TODO:
361541Srgrimes *	add "inuse/lock" bit (or ref. count) along with valid bit
371541Srgrimes */
381541Srgrimes
3932350Seivind#include "opt_inet.h"
4041793Sluigi#include "opt_bdg.h"
41101090Srwatson#include "opt_mac.h"
42142215Sglebius#include "opt_carp.h"
4332350Seivind
441541Srgrimes#include <sys/param.h>
4512693Sphk#include <sys/kernel.h>
4644078Sdfr#include <sys/queue.h>
4712693Sphk#include <sys/sysctl.h>
481541Srgrimes#include <sys/systm.h>
49101090Srwatson#include <sys/mac.h>
5012693Sphk#include <sys/mbuf.h>
511541Srgrimes#include <sys/malloc.h>
5218892Sbde#include <sys/socket.h>
531541Srgrimes#include <sys/syslog.h>
541541Srgrimes
551541Srgrimes#include <net/if.h>
561541Srgrimes#include <net/if_dl.h>
5744165Sjulian#include <net/if_types.h>
581541Srgrimes#include <net/route.h>
598426Swollman#include <net/netisr.h>
6058313Slile#include <net/if_llc.h>
6171963Sjulian#include <net/ethernet.h>
6271963Sjulian#include <net/bridge.h>
631541Srgrimes
641541Srgrimes#include <netinet/in.h>
651541Srgrimes#include <netinet/in_var.h>
661541Srgrimes#include <netinet/if_ether.h>
671541Srgrimes
6884931Sfjoe#include <net/if_arc.h>
6944627Sjulian#include <net/iso88025.h>
7044627Sjulian
71142215Sglebius#ifdef DEV_CARP
72142215Sglebius#include <netinet/ip_carp.h>
73142215Sglebius#endif
74142215Sglebius
751541Srgrimes#define SIN(s) ((struct sockaddr_in *)s)
761541Srgrimes#define SDL(s) ((struct sockaddr_dl *)s)
771541Srgrimes
7844078SdfrSYSCTL_DECL(_net_link_ether);
7912942SwollmanSYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");
801541Srgrimes
8112693Sphk/* timer values */
8212942Swollmanstatic int arpt_prune = (5*60*1); /* walk list every 5 minutes */
8312942Swollmanstatic int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
8412942Swollmanstatic int arpt_down = 20;	/* once declared down, don't send for 20 sec */
851541Srgrimes
8612942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
8712942Swollman	   &arpt_prune, 0, "");
8812942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
8912942Swollman	   &arpt_keep, 0, "");
9012942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,
9112942Swollman	   &arpt_down, 0, "");
9212693Sphk
931541Srgrimes#define	rt_expire rt_rmx.rmx_expire
941541Srgrimes
9511225Swollmanstruct llinfo_arp {
9660938Sjake	LIST_ENTRY(llinfo_arp) la_le;
9711225Swollman	struct	rtentry *la_rt;
98110308Sorion	struct	mbuf *la_hold;	/* last packet until resolved/timeout */
99110544Sorion	u_short	la_preempt;	/* countdown for pre-expiry arps */
100110308Sorion	u_short	la_asked;	/* #times we QUERIED following expiration */
10111225Swollman#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */
10211225Swollman};
10312693Sphk
10460938Sjakestatic	LIST_HEAD(, llinfo_arp) llinfo_arp;
10511225Swollman
106111888Sjlemonstatic struct	ifqueue arpintrq;
107120727Ssamstatic int	arp_allocated;
1081541Srgrimes
10912693Sphkstatic int	arp_maxtries = 5;
11012942Swollmanstatic int	useloopback = 1; /* use loopback interface for local traffic */
11112942Swollmanstatic int	arp_proxyall = 0;
112120727Ssamstatic struct callout arp_callout;
1133282Swollman
11412942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
11512942Swollman	   &arp_maxtries, 0, "");
11612942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
11712942Swollman	   &useloopback, 0, "");
11812942SwollmanSYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
11912942Swollman	   &arp_proxyall, 0, "");
12012693Sphk
12192723Salfredstatic void	arp_init(void);
12292723Salfredstatic void	arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
12392723Salfredstatic void	arprequest(struct ifnet *,
12492723Salfred			struct in_addr *, struct in_addr *, u_char *);
125111888Sjlemonstatic void	arpintr(struct mbuf *);
12692723Salfredstatic void	arptfree(struct llinfo_arp *);
12792723Salfredstatic void	arptimer(void *);
12812693Sphkstatic struct llinfo_arp
12992723Salfred		*arplookup(u_long, int, int);
13032350Seivind#ifdef INET
13192723Salfredstatic void	in_arpinput(struct mbuf *);
13232350Seivind#endif
13312693Sphk
1341541Srgrimes/*
1351541Srgrimes * Timeout routine.  Age arp_tab entries periodically.
1361541Srgrimes */
1371541Srgrimes/* ARGSUSED */
1381541Srgrimesstatic void
1391541Srgrimesarptimer(ignored_arg)
1401541Srgrimes	void *ignored_arg;
1411541Srgrimes{
142109409Shsu	struct llinfo_arp *la, *ola;
1431541Srgrimes
144109996Shsu	RADIX_NODE_HEAD_LOCK(rt_tables[AF_INET]);
145109409Shsu	la = LIST_FIRST(&llinfo_arp);
146109409Shsu	while (la != NULL) {
147109409Shsu		struct rtentry *rt = la->la_rt;
148109409Shsu		ola = la;
14971999Sphk		la = LIST_NEXT(la, la_le);
15034961Sphk		if (rt->rt_expire && rt->rt_expire <= time_second)
151109409Shsu			arptfree(ola);		/* timer has expired, clear */
1521541Srgrimes	}
153109996Shsu	RADIX_NODE_HEAD_UNLOCK(rt_tables[AF_INET]);
154120727Ssam
155120727Ssam	callout_reset(&arp_callout, arpt_prune * hz, arptimer, NULL);
1561541Srgrimes}
1571541Srgrimes
1581541Srgrimes/*
1591541Srgrimes * Parallel to llc_rtrequest.
1601541Srgrimes */
1615196Swollmanstatic void
16285074Sruarp_rtrequest(req, rt, info)
1631541Srgrimes	int req;
164126936Smdodd	struct rtentry *rt;
16585074Sru	struct rt_addrinfo *info;
1661541Srgrimes{
167126936Smdodd	struct sockaddr *gate;
168126936Smdodd	struct llinfo_arp *la;
1691541Srgrimes	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
170138615Smlaier	struct in_ifaddr *ia;
171138615Smlaier	struct ifaddr *ifa;
1721541Srgrimes
173120727Ssam	RT_LOCK_ASSERT(rt);
174120727Ssam
1751541Srgrimes	if (rt->rt_flags & RTF_GATEWAY)
1761541Srgrimes		return;
177120727Ssam	gate = rt->rt_gateway;
178120727Ssam	la = (struct llinfo_arp *)rt->rt_llinfo;
1791541Srgrimes	switch (req) {
1801541Srgrimes
1811541Srgrimes	case RTM_ADD:
1821541Srgrimes		/*
1831541Srgrimes		 * XXX: If this is a manually added route to interface
1841541Srgrimes		 * such as older version of routed or gated might provide,
1851541Srgrimes		 * restore cloning bit.
1861541Srgrimes		 */
1871541Srgrimes		if ((rt->rt_flags & RTF_HOST) == 0 &&
188136960Sbms		    rt_mask(rt) != NULL &&
1891541Srgrimes		    SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
1901541Srgrimes			rt->rt_flags |= RTF_CLONING;
1911541Srgrimes		if (rt->rt_flags & RTF_CLONING) {
1921541Srgrimes			/*
1931541Srgrimes			 * Case 1: This route should come from a route to iface.
1941541Srgrimes			 */
1951541Srgrimes			rt_setgate(rt, rt_key(rt),
1961541Srgrimes					(struct sockaddr *)&null_sdl);
1971541Srgrimes			gate = rt->rt_gateway;
1981541Srgrimes			SDL(gate)->sdl_type = rt->rt_ifp->if_type;
1991541Srgrimes			SDL(gate)->sdl_index = rt->rt_ifp->if_index;
20034961Sphk			rt->rt_expire = time_second;
2011541Srgrimes			break;
2021541Srgrimes		}
2031541Srgrimes		/* Announce a new entry if requested. */
2041541Srgrimes		if (rt->rt_flags & RTF_ANNOUNCE)
20584931Sfjoe			arprequest(rt->rt_ifp,
20636908Sjulian			    &SIN(rt_key(rt))->sin_addr,
20736908Sjulian			    &SIN(rt_key(rt))->sin_addr,
2081541Srgrimes			    (u_char *)LLADDR(SDL(gate)));
2091541Srgrimes		/*FALLTHROUGH*/
2101541Srgrimes	case RTM_RESOLVE:
2111541Srgrimes		if (gate->sa_family != AF_LINK ||
2121541Srgrimes		    gate->sa_len < sizeof(null_sdl)) {
213120727Ssam			log(LOG_DEBUG, "%s: bad gateway %s%s\n", __func__,
214120698Sbms			    inet_ntoa(SIN(rt_key(rt))->sin_addr),
215120698Sbms			    (gate->sa_family != AF_LINK) ?
216120699Sbms			    " (!AF_LINK)": "");
2171541Srgrimes			break;
2181541Srgrimes		}
2191541Srgrimes		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
2201541Srgrimes		SDL(gate)->sdl_index = rt->rt_ifp->if_index;
2211541Srgrimes		if (la != 0)
2221541Srgrimes			break; /* This happens on a route change */
2231541Srgrimes		/*
2241541Srgrimes		 * Case 2:  This route may come from cloning, or a manual route
2251541Srgrimes		 * add with a LL address.
2261541Srgrimes		 */
227120727Ssam		R_Zalloc(la, struct llinfo_arp *, sizeof(*la));
2281541Srgrimes		rt->rt_llinfo = (caddr_t)la;
2291541Srgrimes		if (la == 0) {
230120727Ssam			log(LOG_DEBUG, "%s: malloc failed\n", __func__);
2311541Srgrimes			break;
2321541Srgrimes		}
233120727Ssam		arp_allocated++;
2341541Srgrimes		la->la_rt = rt;
2351541Srgrimes		rt->rt_flags |= RTF_LLINFO;
236109996Shsu		RADIX_NODE_HEAD_LOCK_ASSERT(rt_tables[AF_INET]);
23711225Swollman		LIST_INSERT_HEAD(&llinfo_arp, la, la_le);
23813926Swollman
23932350Seivind#ifdef INET
24013926Swollman		/*
24113926Swollman		 * This keeps the multicast addresses from showing up
24213926Swollman		 * in `arp -a' listings as unresolved.  It's not actually
24313926Swollman		 * functional.  Then the same for broadcast.
24413926Swollman		 */
24587776Sjlemon		if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr)) &&
24687776Sjlemon		    rt->rt_ifp->if_type != IFT_ARCNET) {
24713926Swollman			ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr,
24813926Swollman					       LLADDR(SDL(gate)));
24913926Swollman			SDL(gate)->sdl_alen = 6;
25016576Speter			rt->rt_expire = 0;
25113926Swollman		}
25213926Swollman		if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {
25384931Sfjoe			memcpy(LLADDR(SDL(gate)), rt->rt_ifp->if_broadcastaddr,
25484931Sfjoe			       rt->rt_ifp->if_addrlen);
25584931Sfjoe			SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen;
25616576Speter			rt->rt_expire = 0;
25713926Swollman		}
25832350Seivind#endif
25913926Swollman
260138615Smlaier		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
261138615Smlaier			if (ia->ia_ifp == rt->rt_ifp &&
262138615Smlaier			    SIN(rt_key(rt))->sin_addr.s_addr ==
263138615Smlaier			    (IA_SIN(ia))->sin_addr.s_addr)
264138615Smlaier				break;
265138615Smlaier		}
266138615Smlaier		if (ia) {
2671541Srgrimes		    /*
2681541Srgrimes		     * This test used to be
2691541Srgrimes		     *	if (loif.if_flags & IFF_UP)
2701541Srgrimes		     * It allowed local traffic to be forced
2711541Srgrimes		     * through the hardware by configuring the loopback down.
2721541Srgrimes		     * However, it causes problems during network configuration
2731541Srgrimes		     * for boards that can't receive packets they send.
2741541Srgrimes		     * It is now necessary to clear "useloopback" and remove
2751541Srgrimes		     * the route to force traffic out to the hardware.
2761541Srgrimes		     */
2771541Srgrimes			rt->rt_expire = 0;
278128398Sluigi			bcopy(IF_LLADDR(rt->rt_ifp), LLADDR(SDL(gate)),
27984931Sfjoe			      SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen);
2801541Srgrimes			if (useloopback)
2818090Spst				rt->rt_ifp = loif;
2821541Srgrimes
283138615Smlaier		    /*
284138615Smlaier		     * make sure to set rt->rt_ifa to the interface
285138615Smlaier		     * address we are using, otherwise we will have trouble
286138615Smlaier		     * with source address selection.
287138615Smlaier		     */
288138615Smlaier			ifa = &ia->ia_ifa;
289138615Smlaier			if (ifa != rt->rt_ifa) {
290138615Smlaier				IFAFREE(rt->rt_ifa);
291138615Smlaier				IFAREF(ifa);
292138615Smlaier				rt->rt_ifa = ifa;
293138615Smlaier			}
2941541Srgrimes		}
2951541Srgrimes		break;
2961541Srgrimes
2971541Srgrimes	case RTM_DELETE:
2981541Srgrimes		if (la == 0)
2991541Srgrimes			break;
300109996Shsu		RADIX_NODE_HEAD_LOCK_ASSERT(rt_tables[AF_INET]);
30111225Swollman		LIST_REMOVE(la, la_le);
3021541Srgrimes		rt->rt_llinfo = 0;
3031541Srgrimes		rt->rt_flags &= ~RTF_LLINFO;
3041541Srgrimes		if (la->la_hold)
3051541Srgrimes			m_freem(la->la_hold);
3061541Srgrimes		Free((caddr_t)la);
3071541Srgrimes	}
3081541Srgrimes}
3091541Srgrimes
3101541Srgrimes/*
3111541Srgrimes * Broadcast an ARP request. Caller specifies:
3121541Srgrimes *	- arp header source ip address
3131541Srgrimes *	- arp header target ip address
3141541Srgrimes *	- arp header source ethernet address
3151541Srgrimes */
3161541Srgrimesstatic void
31784931Sfjoearprequest(ifp, sip, tip, enaddr)
318126936Smdodd	struct ifnet *ifp;
319126936Smdodd	struct in_addr *sip, *tip;
320126936Smdodd	u_char *enaddr;
3211541Srgrimes{
322126936Smdodd	struct mbuf *m;
323126936Smdodd	struct arphdr *ah;
3241541Srgrimes	struct sockaddr sa;
3251541Srgrimes
326111119Simp	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
3271541Srgrimes		return;
328127261Smdodd	m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
329127261Smdodd		2*ifp->if_data.ifi_addrlen;
330127277Smdodd	m->m_pkthdr.len = m->m_len;
331127277Smdodd	MH_ALIGN(m, m->m_len);
332127277Smdodd	ah = mtod(m, struct arphdr *);
333127261Smdodd	bzero((caddr_t)ah, m->m_len);
334101090Srwatson#ifdef MAC
335101090Srwatson	mac_create_mbuf_linklayer(ifp, m);
336101090Srwatson#endif
33784931Sfjoe	ah->ar_pro = htons(ETHERTYPE_IP);
33884931Sfjoe	ah->ar_hln = ifp->if_addrlen;		/* hardware address length */
33984931Sfjoe	ah->ar_pln = sizeof(struct in_addr);	/* protocol address length */
34084931Sfjoe	ah->ar_op = htons(ARPOP_REQUEST);
341127261Smdodd	bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln);
342127261Smdodd	bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln);
343127261Smdodd	bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln);
344127261Smdodd	sa.sa_family = AF_ARP;
345127261Smdodd	sa.sa_len = 2;
346127261Smdodd	m->m_flags |= M_BCAST;
347127261Smdodd	(*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
34884931Sfjoe
349127261Smdodd	return;
3501541Srgrimes}
3511541Srgrimes
3521541Srgrimes/*
353128636Sluigi * Resolve an IP address into an ethernet address.
354128636Sluigi * On input:
355128636Sluigi *    ifp is the interface we use
356128636Sluigi *    dst is the next hop,
357128636Sluigi *    rt0 is the route to the final destination (possibly useless)
358128636Sluigi *    m is the mbuf
359128636Sluigi *    desten is where we want the address.
360128636Sluigi *
361128636Sluigi * On success, desten is filled in and the function returns 0;
362128636Sluigi * If the packet must be held pending resolution, we return EWOULDBLOCK
363128636Sluigi * On other errors, we return the corresponding error code.
3641541Srgrimes */
3651541Srgrimesint
366128636Sluigiarpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
367127828Sluigi	struct sockaddr *dst, u_char *desten)
3681541Srgrimes{
36978295Sjlemon	struct llinfo_arp *la = 0;
3701541Srgrimes	struct sockaddr_dl *sdl;
371128636Sluigi	int error;
372128636Sluigi	struct rtentry *rt;
3731541Srgrimes
374128636Sluigi	error = rt_check(&rt, &rt0, dst);
375128636Sluigi	if (error) {
376128636Sluigi		m_freem(m);
377128636Sluigi		return error;
378128636Sluigi	}
379128636Sluigi
3801541Srgrimes	if (m->m_flags & M_BCAST) {	/* broadcast */
38184931Sfjoe		(void)memcpy(desten, ifp->if_broadcastaddr, ifp->if_addrlen);
382128636Sluigi		return (0);
3831541Srgrimes	}
38484931Sfjoe	if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) {/* multicast */
3851541Srgrimes		ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
386128636Sluigi		return (0);
3871541Srgrimes	}
3881541Srgrimes	if (rt)
3891541Srgrimes		la = (struct llinfo_arp *)rt->rt_llinfo;
39042775Sfenner	if (la == 0) {
3913311Sphk		la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0);
3923311Sphk		if (la)
3931541Srgrimes			rt = la->la_rt;
3941541Srgrimes	}
3951541Srgrimes	if (la == 0 || rt == 0) {
39636308Sphk		log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n",
39736308Sphk			inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "",
39836308Sphk				rt ? "rt" : "");
3991541Srgrimes		m_freem(m);
400128636Sluigi		return (EINVAL); /* XXX */
4011541Srgrimes	}
4021541Srgrimes	sdl = SDL(rt->rt_gateway);
4031541Srgrimes	/*
4041541Srgrimes	 * Check the address family and length is valid, the address
4051541Srgrimes	 * is resolved; otherwise, try to resolve.
4061541Srgrimes	 */
40734961Sphk	if ((rt->rt_expire == 0 || rt->rt_expire > time_second) &&
4081541Srgrimes	    sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
40992802Sorion		/*
41092802Sorion		 * If entry has an expiry time and it is approaching,
41192802Sorion		 * see if we need to send an ARP request within this
41292802Sorion		 * arpt_down interval.
41392802Sorion		 */
41492802Sorion		if ((rt->rt_expire != 0) &&
415110544Sorion		    (time_second + la->la_preempt > rt->rt_expire)) {
41692802Sorion			arprequest(ifp,
41792802Sorion				   &SIN(rt->rt_ifa->ifa_addr)->sin_addr,
41892802Sorion				   &SIN(dst)->sin_addr,
41992802Sorion				   IF_LLADDR(ifp));
420110544Sorion			la->la_preempt--;
42192802Sorion		}
42292802Sorion
42316206Sbde		bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
424128636Sluigi		return (0);
4251541Srgrimes	}
4261541Srgrimes	/*
427120626Sru	 * If ARP is disabled or static on this interface, stop.
42878295Sjlemon	 * XXX
42978295Sjlemon	 * Probably should not allocate empty llinfo struct if we are
43078295Sjlemon	 * not going to be sending out an arp request.
43178295Sjlemon	 */
432120626Sru	if (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) {
43387410Sru		m_freem(m);
434128636Sluigi		return (EINVAL);
43587410Sru	}
43678295Sjlemon	/*
4371541Srgrimes	 * There is an arptab entry, but no ethernet address
4381541Srgrimes	 * response yet.  Replace the held mbuf with this
4391541Srgrimes	 * latest one.
4401541Srgrimes	 */
4411541Srgrimes	if (la->la_hold)
4421541Srgrimes		m_freem(la->la_hold);
4431541Srgrimes	la->la_hold = m;
4441541Srgrimes	if (rt->rt_expire) {
445120727Ssam		RT_LOCK(rt);
4461541Srgrimes		rt->rt_flags &= ~RTF_REJECT;
44734961Sphk		if (la->la_asked == 0 || rt->rt_expire != time_second) {
44834961Sphk			rt->rt_expire = time_second;
449110308Sorion			if (la->la_asked++ < arp_maxtries) {
450110308Sorion				arprequest(ifp,
451110308Sorion					   &SIN(rt->rt_ifa->ifa_addr)->sin_addr,
452110308Sorion					   &SIN(dst)->sin_addr,
453110308Sorion					   IF_LLADDR(ifp));
454110308Sorion			} else {
4551541Srgrimes				rt->rt_flags |= RTF_REJECT;
4561541Srgrimes				rt->rt_expire += arpt_down;
457110544Sorion				la->la_asked = 0;
458110544Sorion				la->la_preempt = arp_maxtries;
4591541Srgrimes			}
4601541Srgrimes
4611541Srgrimes		}
462120727Ssam		RT_UNLOCK(rt);
4631541Srgrimes	}
464128636Sluigi	return (EWOULDBLOCK);
4651541Srgrimes}
4661541Srgrimes
4671541Srgrimes/*
4681541Srgrimes * Common length and type checks are done here,
4691541Srgrimes * then the protocol-specific routine is called.
4701541Srgrimes */
47112693Sphkstatic void
472111888Sjlemonarpintr(struct mbuf *m)
4731541Srgrimes{
474111888Sjlemon	struct arphdr *ar;
4751541Srgrimes
476111888Sjlemon	if (m->m_len < sizeof(struct arphdr) &&
477111888Sjlemon	    ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {
478111888Sjlemon		log(LOG_ERR, "arp: runt packet -- m_pullup failed\n");
479111888Sjlemon		return;
480111888Sjlemon	}
481111888Sjlemon	ar = mtod(m, struct arphdr *);
4821541Srgrimes
483111888Sjlemon	if (ntohs(ar->ar_hrd) != ARPHRD_ETHER &&
484111888Sjlemon	    ntohs(ar->ar_hrd) != ARPHRD_IEEE802 &&
485130407Sdfr	    ntohs(ar->ar_hrd) != ARPHRD_ARCNET &&
486130407Sdfr	    ntohs(ar->ar_hrd) != ARPHRD_IEEE1394) {
487111888Sjlemon		log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n",
488111888Sjlemon		    (unsigned char *)&ar->ar_hrd, "");
489111888Sjlemon		m_freem(m);
490111888Sjlemon		return;
491111888Sjlemon	}
4921541Srgrimes
493123768Sru	if (m->m_len < arphdr_len(ar)) {
494123765Sru		if ((m = m_pullup(m, arphdr_len(ar))) == NULL) {
495123765Sru			log(LOG_ERR, "arp: runt packet\n");
496123765Sru			m_freem(m);
497123765Sru			return;
498123765Sru		}
499123765Sru		ar = mtod(m, struct arphdr *);
500111888Sjlemon	}
50157900Srwatson
502111888Sjlemon	switch (ntohs(ar->ar_pro)) {
50332350Seivind#ifdef INET
504111888Sjlemon	case ETHERTYPE_IP:
505111888Sjlemon		in_arpinput(m);
506111888Sjlemon		return;
50732350Seivind#endif
5081541Srgrimes	}
509111888Sjlemon	m_freem(m);
5101541Srgrimes}
5111541Srgrimes
51232350Seivind#ifdef INET
5131541Srgrimes/*
5141541Srgrimes * ARP for Internet protocols on 10 Mb/s Ethernet.
5151541Srgrimes * Algorithm is that given in RFC 826.
5161541Srgrimes * In addition, a sanity check is performed on the sender
5171541Srgrimes * protocol address, to catch impersonators.
5181541Srgrimes * We no longer handle negotiations for use of trailer protocol:
5191541Srgrimes * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
5201541Srgrimes * along with IP replies if we wanted trailers sent to us,
5211541Srgrimes * and also sent them in response to IP replies.
5221541Srgrimes * This allowed either end to announce the desire to receive
5231541Srgrimes * trailer packets.
5241541Srgrimes * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
5251541Srgrimes * but formerly didn't normally send requests.
5261541Srgrimes */
52770699Salfredstatic int log_arp_wrong_iface = 1;
52882893Salfredstatic int log_arp_movements = 1;
52970699Salfred
53070699SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW,
53170699Salfred	&log_arp_wrong_iface, 0,
53270699Salfred	"log arp packets arriving on the wrong interface");
53382893SalfredSYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_movements, CTLFLAG_RW,
53482893Salfred        &log_arp_movements, 0,
53582966Salfred        "log arp replies from MACs different than the one in the cache");
53670699Salfred
53782893Salfred
5381541Srgrimesstatic void
5391541Srgrimesin_arpinput(m)
5401541Srgrimes	struct mbuf *m;
5411541Srgrimes{
542126936Smdodd	struct arphdr *ah;
543126936Smdodd	struct ifnet *ifp = m->m_pkthdr.rcvif;
54444627Sjulian	struct iso88025_header *th = (struct iso88025_header *)0;
54596184Skbyanc	struct iso88025_sockaddr_dl_data *trld;
546126936Smdodd	struct llinfo_arp *la = 0;
547126936Smdodd	struct rtentry *rt;
54884102Sjlemon	struct ifaddr *ifa;
54984102Sjlemon	struct in_ifaddr *ia;
5501541Srgrimes	struct sockaddr_dl *sdl;
5511541Srgrimes	struct sockaddr sa;
5521541Srgrimes	struct in_addr isaddr, itaddr, myaddr;
553142215Sglebius	u_int8_t *enaddr = NULL;
55458313Slile	int op, rif_len;
55584931Sfjoe	int req_len;
5561541Srgrimes
55784931Sfjoe	req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
55884931Sfjoe	if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) {
55974851Syar		log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n");
56074851Syar		return;
56174851Syar	}
56274851Syar
56384931Sfjoe	ah = mtod(m, struct arphdr *);
56484931Sfjoe	op = ntohs(ah->ar_op);
56584931Sfjoe	(void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr));
56684931Sfjoe	(void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr));
567134991Sglebius
56884102Sjlemon	/*
56984102Sjlemon	 * For a bridge, we want to check the address irrespective
57084102Sjlemon	 * of the receive interface. (This will change slightly
57184102Sjlemon	 * when we have clusters of interfaces).
572142215Sglebius	 * If the interface does not match, but the recieving interface
573142215Sglebius	 * is part of carp, we call carp_iamatch to see if this is a
574142215Sglebius	 * request for the virtual host ip.
575142215Sglebius	 * XXX: This is really ugly!
57684102Sjlemon	 */
57784102Sjlemon	LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash)
578142215Sglebius		if ((do_bridge || (ia->ia_ifp == ifp)
579142215Sglebius#ifdef DEV_CARP
580142215Sglebius		    || (ifp->if_carp
581142215Sglebius		    && carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr))
582142215Sglebius#endif
583142215Sglebius		    ) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
58484102Sjlemon			goto match;
58584102Sjlemon	LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash)
586134991Sglebius		if ((do_bridge || (ia->ia_ifp == ifp)) &&
58784102Sjlemon		    isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
58884102Sjlemon			goto match;
58984102Sjlemon	/*
59085223Sjlemon	 * No match, use the first inet address on the receive interface
59184102Sjlemon	 * as a dummy address for the rest of the function.
59284102Sjlemon	 */
59385223Sjlemon	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
59485466Sjlemon		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
59585466Sjlemon			ia = ifatoia(ifa);
59685466Sjlemon			goto match;
59785466Sjlemon		}
59885466Sjlemon	/*
59985466Sjlemon	 * If bridging, fall back to using any inet address.
60085466Sjlemon	 */
601134991Sglebius	if (!do_bridge || (ia = TAILQ_FIRST(&in_ifaddrhead)) == NULL)
602128645Sluigi		goto drop;
60384102Sjlemonmatch:
604142215Sglebius	if (!enaddr)
605142215Sglebius		enaddr = (u_int8_t *)IF_LLADDR(ifp);
60684102Sjlemon	myaddr = ia->ia_addr.sin_addr;
607142215Sglebius	if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen))
608128645Sluigi		goto drop;	/* it's from me, ignore it. */
60984931Sfjoe	if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) {
6101541Srgrimes		log(LOG_ERR,
61184931Sfjoe		    "arp: link address is broadcast for IP address %s!\n",
6127088Swollman		    inet_ntoa(isaddr));
613128645Sluigi		goto drop;
6141541Srgrimes	}
615136441Srwatson	/*
616136441Srwatson	 * Warn if another host is using the same IP address, but only if the
617136441Srwatson	 * IP address isn't 0.0.0.0, which is used for DHCP only, in which
618136441Srwatson	 * case we suppress the warning to avoid false positive complaints of
619136441Srwatson	 * potential misconfiguration.
620136441Srwatson	 */
621136441Srwatson	if (isaddr.s_addr == myaddr.s_addr && myaddr.s_addr != 0) {
6221541Srgrimes		log(LOG_ERR,
62384931Sfjoe		   "arp: %*D is using my IP address %s!\n",
62484931Sfjoe		   ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
62584931Sfjoe		   inet_ntoa(isaddr));
6261541Srgrimes		itaddr = myaddr;
6271541Srgrimes		goto reply;
6281541Srgrimes	}
629120626Sru	if (ifp->if_flags & IFF_STATICARP)
630120626Sru		goto reply;
6311541Srgrimes	la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
6321541Srgrimes	if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
63372270Sluigi		/* the following is not an error when doing bridging */
634134991Sglebius		if (!do_bridge && rt->rt_ifp != ifp) {
63572270Sluigi			if (log_arp_wrong_iface)
636121816Sbrooks				log(LOG_ERR, "arp: %s is on %s but got reply from %*D on %s\n",
63771963Sjulian				    inet_ntoa(isaddr),
638121816Sbrooks				    rt->rt_ifp->if_xname,
63984931Sfjoe				    ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
640121816Sbrooks				    ifp->if_xname);
64172270Sluigi			goto reply;
64239389Sfenner		}
6431541Srgrimes		if (sdl->sdl_alen &&
64484931Sfjoe		    bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) {
64582893Salfred			if (rt->rt_expire) {
64682893Salfred			    if (log_arp_movements)
647121816Sbrooks			        log(LOG_INFO, "arp: %s moved from %*D to %*D on %s\n",
64884931Sfjoe				    inet_ntoa(isaddr),
64984931Sfjoe				    ifp->if_addrlen, (u_char *)LLADDR(sdl), ":",
65084931Sfjoe				    ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
651121816Sbrooks				    ifp->if_xname);
65282893Salfred			} else {
65339389Sfenner			    log(LOG_ERR,
654121816Sbrooks				"arp: %*D attempts to modify permanent entry for %s on %s\n",
65584931Sfjoe				ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
656121816Sbrooks				inet_ntoa(isaddr), ifp->if_xname);
65739389Sfenner			    goto reply;
65839389Sfenner			}
65946568Speter		}
66084931Sfjoe		/*
66184931Sfjoe		 * sanity check for the address length.
66284931Sfjoe		 * XXX this does not work for protocols with variable address
66384931Sfjoe		 * length. -is
66484931Sfjoe		 */
66584931Sfjoe		if (sdl->sdl_alen &&
66684931Sfjoe		    sdl->sdl_alen != ah->ar_hln) {
66784931Sfjoe			log(LOG_WARNING,
66884931Sfjoe			    "arp from %*D: new addr len %d, was %d",
66984931Sfjoe			    ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
67084931Sfjoe			    ah->ar_hln, sdl->sdl_alen);
67184931Sfjoe		}
67284931Sfjoe		if (ifp->if_addrlen != ah->ar_hln) {
67384931Sfjoe			log(LOG_WARNING,
67484931Sfjoe			    "arp from %*D: addr len: new %d, i/f %d (ignored)",
67584931Sfjoe			    ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
67684931Sfjoe			    ah->ar_hln, ifp->if_addrlen);
67784931Sfjoe			goto reply;
67884931Sfjoe		}
67984931Sfjoe		(void)memcpy(LLADDR(sdl), ar_sha(ah),
68084931Sfjoe		    sdl->sdl_alen = ah->ar_hln);
68145705Seivind		/*
68245705Seivind		 * If we receive an arp from a token-ring station over
68345705Seivind		 * a token-ring nic then try to save the source
68445705Seivind		 * routing info.
68545705Seivind		 */
68684931Sfjoe		if (ifp->if_type == IFT_ISO88025) {
68744627Sjulian			th = (struct iso88025_header *)m->m_pkthdr.header;
68896184Skbyanc			trld = SDL_ISO88025(sdl);
68958313Slile			rif_len = TR_RCF_RIFLEN(th->rcf);
69058313Slile			if ((th->iso88025_shost[0] & TR_RII) &&
69158313Slile			    (rif_len > 2)) {
69296184Skbyanc				trld->trld_rcf = th->rcf;
69396184Skbyanc				trld->trld_rcf ^= htons(TR_RCF_DIR);
69496184Skbyanc				memcpy(trld->trld_route, th->rd, rif_len - 2);
69596184Skbyanc				trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK);
69651320Slile				/*
69751320Slile				 * Set up source routing information for
69851320Slile				 * reply packet (XXX)
69951320Slile				 */
70058313Slile				m->m_data -= rif_len;
70158313Slile				m->m_len  += rif_len;
70258313Slile				m->m_pkthdr.len += rif_len;
70344627Sjulian			} else {
70458313Slile				th->iso88025_shost[0] &= ~TR_RII;
70596624Skbyanc				trld->trld_rcf = 0;
70644627Sjulian			}
70750512Slile			m->m_data -= 8;
70850512Slile			m->m_len  += 8;
70950512Slile			m->m_pkthdr.len += 8;
71096184Skbyanc			th->rcf = trld->trld_rcf;
71144627Sjulian		}
712120727Ssam		RT_LOCK(rt);
7131541Srgrimes		if (rt->rt_expire)
71434961Sphk			rt->rt_expire = time_second + arpt_keep;
7151541Srgrimes		rt->rt_flags &= ~RTF_REJECT;
716120727Ssam		RT_UNLOCK(rt);
717110544Sorion		la->la_asked = 0;
718110544Sorion		la->la_preempt = arp_maxtries;
7191541Srgrimes		if (la->la_hold) {
720127277Smdodd			(*ifp->if_output)(ifp, la->la_hold, rt_key(rt), rt);
7211541Srgrimes			la->la_hold = 0;
7221541Srgrimes		}
7231541Srgrimes	}
7241541Srgrimesreply:
725128645Sluigi	if (op != ARPOP_REQUEST)
726128645Sluigi		goto drop;
7271541Srgrimes	if (itaddr.s_addr == myaddr.s_addr) {
7281541Srgrimes		/* I am the target */
72984931Sfjoe		(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
730142215Sglebius		(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
7311541Srgrimes	} else {
7321541Srgrimes		la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
7333282Swollman		if (la == NULL) {
7343282Swollman			struct sockaddr_in sin;
7353282Swollman
736128645Sluigi			if (!arp_proxyall)
737128645Sluigi				goto drop;
7383282Swollman
7393282Swollman			bzero(&sin, sizeof sin);
7403282Swollman			sin.sin_family = AF_INET;
7413282Swollman			sin.sin_len = sizeof sin;
7423282Swollman			sin.sin_addr = itaddr;
7433282Swollman
7445101Swollman			rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
745128645Sluigi			if (!rt)
746128645Sluigi				goto drop;
7473282Swollman			/*
7483282Swollman			 * Don't send proxies for nodes on the same interface
7493282Swollman			 * as this one came out of, or we'll get into a fight
7503282Swollman			 * over who claims what Ether address.
7513282Swollman			 */
75284931Sfjoe			if (rt->rt_ifp == ifp) {
7533282Swollman				rtfree(rt);
754128645Sluigi				goto drop;
7553282Swollman			}
75684931Sfjoe			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
757142215Sglebius			(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
7583282Swollman			rtfree(rt);
75963080Sdwmalone
76063080Sdwmalone			/*
76163080Sdwmalone			 * Also check that the node which sent the ARP packet
76263080Sdwmalone			 * is on the the interface we expect it to be on. This
76363080Sdwmalone			 * avoids ARP chaos if an interface is connected to the
76463080Sdwmalone			 * wrong network.
76563080Sdwmalone			 */
76663080Sdwmalone			sin.sin_addr = isaddr;
76763080Sdwmalone
76863080Sdwmalone			rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
769128645Sluigi			if (!rt)
770128645Sluigi				goto drop;
77184931Sfjoe			if (rt->rt_ifp != ifp) {
77263080Sdwmalone				log(LOG_INFO, "arp_proxy: ignoring request"
773121816Sbrooks				    " from %s via %s, expecting %s\n",
774121816Sbrooks				    inet_ntoa(isaddr), ifp->if_xname,
775121816Sbrooks				    rt->rt_ifp->if_xname);
77663080Sdwmalone				rtfree(rt);
777128645Sluigi				goto drop;
77863080Sdwmalone			}
77963080Sdwmalone			rtfree(rt);
78063080Sdwmalone
7814069Swollman#ifdef DEBUG_PROXY
7828876Srgrimes			printf("arp: proxying for %s\n",
7837088Swollman			       inet_ntoa(itaddr));
7844069Swollman#endif
7853282Swollman		} else {
7863282Swollman			rt = la->la_rt;
78784931Sfjoe			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
7883282Swollman			sdl = SDL(rt->rt_gateway);
78984931Sfjoe			(void)memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln);
7903282Swollman		}
7911541Srgrimes	}
7921541Srgrimes
79384931Sfjoe	(void)memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
79484931Sfjoe	(void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
79584931Sfjoe	ah->ar_op = htons(ARPOP_REPLY);
79684931Sfjoe	ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */
797127261Smdodd	m->m_flags &= ~(M_BCAST|M_MCAST); /* never reply by broadcast */
798127261Smdodd	m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln);
799127261Smdodd	m->m_pkthdr.len = m->m_len;
800127261Smdodd	sa.sa_family = AF_ARP;
801127261Smdodd	sa.sa_len = 2;
80284931Sfjoe	(*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
8031541Srgrimes	return;
804128645Sluigi
805128645Sluigidrop:
806128645Sluigi	m_freem(m);
8071541Srgrimes}
80832350Seivind#endif
8091541Srgrimes
8101541Srgrimes/*
8111541Srgrimes * Free an arp entry.
8121541Srgrimes */
8131541Srgrimesstatic void
8141541Srgrimesarptfree(la)
815126936Smdodd	struct llinfo_arp *la;
8161541Srgrimes{
817126936Smdodd	struct rtentry *rt = la->la_rt;
818126936Smdodd	struct sockaddr_dl *sdl;
819120727Ssam
8201541Srgrimes	if (rt == 0)
8211541Srgrimes		panic("arptfree");
8221541Srgrimes	if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
8231541Srgrimes	    sdl->sdl_family == AF_LINK) {
8241541Srgrimes		sdl->sdl_alen = 0;
825110308Sorion		la->la_preempt = la->la_asked = 0;
826120727Ssam		RT_LOCK(rt);		/* XXX needed or move higher? */
8271541Srgrimes		rt->rt_flags &= ~RTF_REJECT;
828120727Ssam		RT_UNLOCK(rt);
8291541Srgrimes		return;
8301541Srgrimes	}
8311541Srgrimes	rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
8321541Srgrimes			0, (struct rtentry **)0);
8331541Srgrimes}
8341541Srgrimes/*
8351541Srgrimes * Lookup or enter a new address in arptab.
8361541Srgrimes */
8371541Srgrimesstatic struct llinfo_arp *
8381541Srgrimesarplookup(addr, create, proxy)
8391541Srgrimes	u_long addr;
8401541Srgrimes	int create, proxy;
8411541Srgrimes{
842126936Smdodd	struct rtentry *rt;
843120727Ssam	struct sockaddr_inarp sin;
8444069Swollman	const char *why = 0;
8451541Srgrimes
846120727Ssam	bzero(&sin, sizeof(sin));
847120727Ssam	sin.sin_len = sizeof(sin);
848120727Ssam	sin.sin_family = AF_INET;
8491541Srgrimes	sin.sin_addr.s_addr = addr;
850120727Ssam	if (proxy)
851120727Ssam		sin.sin_other = SIN_PROXY;
8525101Swollman	rt = rtalloc1((struct sockaddr *)&sin, create, 0UL);
8531541Srgrimes	if (rt == 0)
8541541Srgrimes		return (0);
8554069Swollman
85612693Sphk	if (rt->rt_flags & RTF_GATEWAY)
8574069Swollman		why = "host is not on local network";
85812693Sphk	else if ((rt->rt_flags & RTF_LLINFO) == 0)
8594069Swollman		why = "could not allocate llinfo";
86012693Sphk	else if (rt->rt_gateway->sa_family != AF_LINK)
8614069Swollman		why = "gateway route is not ours";
8624069Swollman
863120383Sbms	if (why) {
864120727Ssam#define	ISDYNCLONE(_rt) \
865120727Ssam	(((_rt)->rt_flags & (RTF_STATIC | RTF_WASCLONED)) == RTF_WASCLONED)
866120727Ssam		if (create)
867120383Sbms			log(LOG_DEBUG, "arplookup %s failed: %s\n",
868120383Sbms			    inet_ntoa(sin.sin_addr), why);
869120727Ssam		/*
870120727Ssam		 * If there are no references to this Layer 2 route,
871120727Ssam		 * and it is a cloned route, and not static, and
872120727Ssam		 * arplookup() is creating the route, then purge
873120727Ssam		 * it from the routing table as it is probably bogus.
874120727Ssam		 */
875121770Ssam		if (rt->rt_refcnt == 1 && ISDYNCLONE(rt))
876121770Ssam			rtexpunge(rt);
877121770Ssam		RTFREE_LOCKED(rt);
878120383Sbms		return (0);
879120727Ssam#undef ISDYNCLONE
880120727Ssam	} else {
881122334Ssam		RT_REMREF(rt);
882120727Ssam		RT_UNLOCK(rt);
883120727Ssam		return ((struct llinfo_arp *)rt->rt_llinfo);
8841541Srgrimes	}
8851541Srgrimes}
8861541Srgrimes
8875195Swollmanvoid
88884931Sfjoearp_ifinit(ifp, ifa)
88984931Sfjoe	struct ifnet *ifp;
8905195Swollman	struct ifaddr *ifa;
8915195Swollman{
89225822Stegge	if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY)
89384931Sfjoe		arprequest(ifp, &IA_SIN(ifa)->sin_addr,
89484931Sfjoe				&IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp));
8955195Swollman	ifa->ifa_rtrequest = arp_rtrequest;
8965195Swollman	ifa->ifa_flags |= RTF_CLONING;
8975195Swollman}
89869152Sjlemon
899142215Sglebiusvoid
900142215Sglebiusarp_ifinit2(ifp, ifa, enaddr)
901142215Sglebius	struct ifnet *ifp;
902142215Sglebius	struct ifaddr *ifa;
903142215Sglebius	u_char *enaddr;
904142215Sglebius{
905142215Sglebius	if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY)
906142215Sglebius		arprequest(ifp, &IA_SIN(ifa)->sin_addr,
907142215Sglebius				&IA_SIN(ifa)->sin_addr, enaddr);
908142215Sglebius	ifa->ifa_rtrequest = arp_rtrequest;
909142215Sglebius	ifa->ifa_flags |= RTF_CLONING;
910142215Sglebius}
911142215Sglebius
91269152Sjlemonstatic void
91369152Sjlemonarp_init(void)
91469152Sjlemon{
91569152Sjlemon
91669152Sjlemon	arpintrq.ifq_maxlen = 50;
91793818Sjhb	mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF);
91898459Speter	LIST_INIT(&llinfo_arp);
919120727Ssam	callout_init(&arp_callout, CALLOUT_MPSAFE);
920122320Ssam	netisr_register(NETISR_ARP, arpintr, &arpintrq, NETISR_MPSAFE);
921128641Sluigi	callout_reset(&arp_callout, hz, arptimer, NULL);
92269152Sjlemon}
92369152SjlemonSYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
924