in.c revision 249742
1139823Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
4137668Smlaier * Copyright (C) 2001 WIDE Project.  All rights reserved.
51541Srgrimes *
61541Srgrimes * Redistribution and use in source and binary forms, with or without
71541Srgrimes * modification, are permitted provided that the following conditions
81541Srgrimes * are met:
91541Srgrimes * 1. Redistributions of source code must retain the above copyright
101541Srgrimes *    notice, this list of conditions and the following disclaimer.
111541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer in the
131541Srgrimes *    documentation and/or other materials provided with the distribution.
141541Srgrimes * 4. Neither the name of the University nor the names of its contributors
151541Srgrimes *    may be used to endorse or promote products derived from this software
161541Srgrimes *    without specific prior written permission.
171541Srgrimes *
181541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
191541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
201541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
221541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
241541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
251541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
261541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
271541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281541Srgrimes * SUCH DAMAGE.
291541Srgrimes *
3010939Swollman *	@(#)in.c	8.4 (Berkeley) 1/9/95
311541Srgrimes */
321541Srgrimes
33172467Ssilby#include <sys/cdefs.h>
34172467Ssilby__FBSDID("$FreeBSD: head/sys/netinet/in.c 249742 2013-04-21 21:28:38Z oleg $");
35172467Ssilby
36204902Sqingli#include "opt_mpath.h"
37143868Sglebius
381541Srgrimes#include <sys/param.h>
391549Srgrimes#include <sys/systm.h>
4024204Sbde#include <sys/sockio.h>
411541Srgrimes#include <sys/malloc.h>
42164033Srwatson#include <sys/priv.h>
431541Srgrimes#include <sys/socket.h>
44186948Sbz#include <sys/jail.h>
4512704Sphk#include <sys/kernel.h>
46186948Sbz#include <sys/proc.h>
4712704Sphk#include <sys/sysctl.h>
48192011Sqingli#include <sys/syslog.h>
491541Srgrimes
501541Srgrimes#include <net/if.h>
51195914Sqingli#include <net/if_var.h>
52215207Sgnn#include <net/if_arp.h>
53192011Sqingli#include <net/if_dl.h>
54186119Sqingli#include <net/if_llatbl.h>
5555009Sshin#include <net/if_types.h>
561541Srgrimes#include <net/route.h>
57192011Sqingli#include <net/vnet.h>
581541Srgrimes
59228571Sglebius#include <netinet/if_ether.h>
601541Srgrimes#include <netinet/in.h>
611541Srgrimes#include <netinet/in_var.h>
6281127Sume#include <netinet/in_pcb.h>
63170613Sbms#include <netinet/ip_var.h>
64228571Sglebius#include <netinet/ip_carp.h>
65189592Sbms#include <netinet/igmp_var.h>
66195699Srwatson#include <netinet/udp.h>
67195699Srwatson#include <netinet/udp_var.h>
681541Srgrimes
6992723Salfredstatic int in_mask2len(struct in_addr *);
7092723Salfredstatic void in_len2mask(struct in_addr *, int);
7192723Salfredstatic int in_lifaddr_ioctl(struct socket *, u_long, caddr_t,
7292723Salfred	struct ifnet *, struct thread *);
7355009Sshin
7492723Salfredstatic void	in_socktrim(struct sockaddr_in *);
75228571Sglebiusstatic int	in_ifinit(struct ifnet *, struct in_ifaddr *,
76230207Sglebius		    struct sockaddr_in *, int, int);
77167729Sbmsstatic void	in_purgemaddrs(struct ifnet *);
781541Srgrimes
79228571Sglebiusstatic VNET_DEFINE(int, nosameprefix);
80228571Sglebius#define	V_nosameprefix			VNET(nosameprefix)
81228571SglebiusSYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, no_same_prefix, CTLFLAG_RW,
82228571Sglebius	&VNET_NAME(nosameprefix), 0,
83149221Sglebius	"Refuse to create same prefixes on different interfaces");
8421666Swollman
85207369SbzVNET_DECLARE(struct inpcbinfo, ripcbinfo);
86207369Sbz#define	V_ripcbinfo			VNET(ripcbinfo)
87207369Sbz
88215207SgnnVNET_DECLARE(struct arpstat, arpstat);  /* ARP statistics, see if_arp.h */
89215207Sgnn#define	V_arpstat		VNET(arpstat)
90215207Sgnn
911541Srgrimes/*
921541Srgrimes * Return 1 if an internet address is for a ``local'' host
93226401Sglebius * (one to which we have a connection).
941541Srgrimes */
951549Srgrimesint
96169454Srwatsonin_localaddr(struct in_addr in)
971541Srgrimes{
981541Srgrimes	register u_long i = ntohl(in.s_addr);
991541Srgrimes	register struct in_ifaddr *ia;
1001541Srgrimes
101194951Srwatson	IN_IFADDR_RLOCK();
102226401Sglebius	TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
103226401Sglebius		if ((i & ia->ia_subnetmask) == ia->ia_subnet) {
104226401Sglebius			IN_IFADDR_RUNLOCK();
105226401Sglebius			return (1);
106194951Srwatson		}
1071541Srgrimes	}
108194951Srwatson	IN_IFADDR_RUNLOCK();
1091541Srgrimes	return (0);
1101541Srgrimes}
1111541Srgrimes
1121541Srgrimes/*
113133486Sandre * Return 1 if an internet address is for the local host and configured
114133486Sandre * on one of its interfaces.
115133486Sandre */
116133486Sandreint
117169454Srwatsonin_localip(struct in_addr in)
118133486Sandre{
119133486Sandre	struct in_ifaddr *ia;
120133486Sandre
121194951Srwatson	IN_IFADDR_RLOCK();
122133486Sandre	LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) {
123194951Srwatson		if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr) {
124194951Srwatson			IN_IFADDR_RUNLOCK();
125184295Sbz			return (1);
126194951Srwatson		}
127133486Sandre	}
128194951Srwatson	IN_IFADDR_RUNLOCK();
129184295Sbz	return (0);
130133486Sandre}
131133486Sandre
132133486Sandre/*
1331541Srgrimes * Determine whether an IP address is in a reserved set of addresses
1341541Srgrimes * that may not be forwarded, or whether datagrams to that destination
1351541Srgrimes * may be forwarded.
1361541Srgrimes */
1371549Srgrimesint
138169454Srwatsonin_canforward(struct in_addr in)
1391541Srgrimes{
1401541Srgrimes	register u_long i = ntohl(in.s_addr);
1411541Srgrimes	register u_long net;
1421541Srgrimes
143166450Sbms	if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i) || IN_LINKLOCAL(i))
1441541Srgrimes		return (0);
1451541Srgrimes	if (IN_CLASSA(i)) {
1461541Srgrimes		net = i & IN_CLASSA_NET;
1471541Srgrimes		if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
1481541Srgrimes			return (0);
1491541Srgrimes	}
1501541Srgrimes	return (1);
1511541Srgrimes}
1521541Srgrimes
1531541Srgrimes/*
1541541Srgrimes * Trim a mask in a sockaddr
1551541Srgrimes */
15612296Sphkstatic void
157169454Srwatsonin_socktrim(struct sockaddr_in *ap)
1581541Srgrimes{
1591541Srgrimes    register char *cplim = (char *) &ap->sin_addr;
1601541Srgrimes    register char *cp = (char *) (&ap->sin_addr + 1);
1611541Srgrimes
1621541Srgrimes    ap->sin_len = 0;
1634127Swollman    while (--cp >= cplim)
164133874Srwatson	if (*cp) {
1651541Srgrimes	    (ap)->sin_len = cp - (char *) (ap) + 1;
1661541Srgrimes	    break;
1671541Srgrimes	}
1681541Srgrimes}
1691541Srgrimes
17055009Sshinstatic int
17155009Sshinin_mask2len(mask)
17255009Sshin	struct in_addr *mask;
17355009Sshin{
17455009Sshin	int x, y;
17555009Sshin	u_char *p;
17655009Sshin
17755009Sshin	p = (u_char *)mask;
17855009Sshin	for (x = 0; x < sizeof(*mask); x++) {
17955009Sshin		if (p[x] != 0xff)
18055009Sshin			break;
18155009Sshin	}
18255009Sshin	y = 0;
18355009Sshin	if (x < sizeof(*mask)) {
18455009Sshin		for (y = 0; y < 8; y++) {
18555009Sshin			if ((p[x] & (0x80 >> y)) == 0)
18655009Sshin				break;
18755009Sshin		}
18855009Sshin	}
189184295Sbz	return (x * 8 + y);
19055009Sshin}
19155009Sshin
19255009Sshinstatic void
193169454Srwatsonin_len2mask(struct in_addr *mask, int len)
19455009Sshin{
19555009Sshin	int i;
19655009Sshin	u_char *p;
19755009Sshin
19855009Sshin	p = (u_char *)mask;
19955009Sshin	bzero(mask, sizeof(*mask));
20055009Sshin	for (i = 0; i < len / 8; i++)
20155009Sshin		p[i] = 0xff;
20255009Sshin	if (len % 8)
20355009Sshin		p[i] = (0xff00 >> (len % 8)) & 0xff;
20455009Sshin}
20555009Sshin
2061541Srgrimes/*
2071541Srgrimes * Generic internet control operations (ioctl's).
208191443Srwatson *
209191443Srwatson * ifp is NULL if not an interface-specific ioctl.
2101541Srgrimes */
2111541Srgrimes/* ARGSUSED */
2121549Srgrimesint
213169454Srwatsonin_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
214169454Srwatson    struct thread *td)
2151541Srgrimes{
2161541Srgrimes	register struct ifreq *ifr = (struct ifreq *)data;
217184295Sbz	register struct in_ifaddr *ia, *iap;
2181541Srgrimes	register struct ifaddr *ifa;
219168032Sbms	struct in_addr allhosts_addr;
22084102Sjlemon	struct in_addr dst;
221189592Sbms	struct in_ifinfo *ii;
2221541Srgrimes	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
223194951Srwatson	int error, hostIsNew, iaIsNew, maskIsNew;
224168032Sbms	int iaIsFirst;
225228768Sglebius	u_long ocmd = cmd;
2261541Srgrimes
227228768Sglebius	/*
228228768Sglebius	 * Pre-10.x compat: OSIOCAIFADDR passes a shorter
229228768Sglebius	 * struct in_aliasreq, without ifra_vhid.
230228768Sglebius	 */
231228768Sglebius	if (cmd == OSIOCAIFADDR)
232228768Sglebius		cmd = SIOCAIFADDR;
233228768Sglebius
234184295Sbz	ia = NULL;
235168032Sbms	iaIsFirst = 0;
23687124Sbrian	iaIsNew = 0;
237168032Sbms	allhosts_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
23887124Sbrian
239191443Srwatson	/*
240191443Srwatson	 * Filter out ioctls we implement directly; forward the rest on to
241191443Srwatson	 * in_lifaddr_ioctl() and ifp->if_ioctl().
242191443Srwatson	 */
24355009Sshin	switch (cmd) {
244191443Srwatson	case SIOCGIFADDR:
245191443Srwatson	case SIOCGIFBRDADDR:
246191443Srwatson	case SIOCGIFDSTADDR:
247191443Srwatson	case SIOCGIFNETMASK:
248227791Sglebius	case SIOCDIFADDR:
249227791Sglebius		break;
250227791Sglebius	case SIOCAIFADDR:
251227791Sglebius		/*
252227791Sglebius		 * ifra_addr must be present and be of INET family.
253227791Sglebius		 * ifra_broadaddr and ifra_mask are optional.
254227791Sglebius		 */
255227791Sglebius		if (ifra->ifra_addr.sin_len != sizeof(struct sockaddr_in) ||
256227791Sglebius		    ifra->ifra_addr.sin_family != AF_INET)
257227791Sglebius			return (EINVAL);
258227791Sglebius		if (ifra->ifra_broadaddr.sin_len != 0 &&
259227831Sglebius		    (ifra->ifra_broadaddr.sin_len !=
260227831Sglebius		    sizeof(struct sockaddr_in) ||
261227791Sglebius		    ifra->ifra_broadaddr.sin_family != AF_INET))
262227791Sglebius			return (EINVAL);
263228768Sglebius#if 0
264228768Sglebius		/*
265228768Sglebius		 * ifconfig(8) in pre-10.x doesn't set sin_family for the
266228768Sglebius		 * mask. The code is disabled for the 10.x timeline, to
267228768Sglebius		 * make SIOCAIFADDR compatible with 9.x ifconfig(8).
268228768Sglebius		 * The code should be enabled in 11.x
269228768Sglebius		 */
270227791Sglebius		if (ifra->ifra_mask.sin_len != 0 &&
271227791Sglebius		    (ifra->ifra_mask.sin_len != sizeof(struct sockaddr_in) ||
272227791Sglebius		    ifra->ifra_mask.sin_family != AF_INET))
273227791Sglebius			return (EINVAL);
274228768Sglebius#endif
275227791Sglebius		break;
276191443Srwatson	case SIOCSIFADDR:
277191443Srwatson	case SIOCSIFBRDADDR:
278191443Srwatson	case SIOCSIFDSTADDR:
279191443Srwatson	case SIOCSIFNETMASK:
280230207Sglebius		/* We no longer support that old commands. */
281230207Sglebius		return (EINVAL);
282191443Srwatson
28355009Sshin	case SIOCALIFADDR:
284164033Srwatson		if (td != NULL) {
285164033Srwatson			error = priv_check(td, PRIV_NET_ADDIFADDR);
286164033Srwatson			if (error)
287164033Srwatson				return (error);
288164033Srwatson		}
289184295Sbz		if (ifp == NULL)
290184295Sbz			return (EINVAL);
291164033Srwatson		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
292164033Srwatson
29355009Sshin	case SIOCDLIFADDR:
294164033Srwatson		if (td != NULL) {
295164033Srwatson			error = priv_check(td, PRIV_NET_DELIFADDR);
296164033Srwatson			if (error)
297164033Srwatson				return (error);
298164033Srwatson		}
299184295Sbz		if (ifp == NULL)
300184295Sbz			return (EINVAL);
301164033Srwatson		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
302164033Srwatson
30355009Sshin	case SIOCGLIFADDR:
304184295Sbz		if (ifp == NULL)
305184295Sbz			return (EINVAL);
30683366Sjulian		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
307191443Srwatson
308191443Srwatson	default:
309191443Srwatson		if (ifp == NULL || ifp->if_ioctl == NULL)
310191443Srwatson			return (EOPNOTSUPP);
311191443Srwatson		return ((*ifp->if_ioctl)(ifp, cmd, data));
31255009Sshin	}
31355009Sshin
314191443Srwatson	if (ifp == NULL)
315191443Srwatson		return (EADDRNOTAVAIL);
316191443Srwatson
3171541Srgrimes	/*
318191456Srwatson	 * Security checks before we get involved in any work.
319191456Srwatson	 */
320191456Srwatson	switch (cmd) {
321191456Srwatson	case SIOCAIFADDR:
322191456Srwatson		if (td != NULL) {
323191456Srwatson			error = priv_check(td, PRIV_NET_ADDIFADDR);
324191456Srwatson			if (error)
325191456Srwatson				return (error);
326191456Srwatson		}
327191456Srwatson		break;
328191456Srwatson
329191456Srwatson	case SIOCDIFADDR:
330191456Srwatson		if (td != NULL) {
331191456Srwatson			error = priv_check(td, PRIV_NET_DELIFADDR);
332191456Srwatson			if (error)
333191456Srwatson				return (error);
334191456Srwatson		}
335191456Srwatson		break;
336191456Srwatson	}
337191456Srwatson
338191456Srwatson	/*
3391541Srgrimes	 * Find address for this interface, if it exists.
34014632Sfenner	 *
341191443Srwatson	 * If an alias address was specified, find that one instead of the
342191443Srwatson	 * first one on the interface, if possible.
3431541Srgrimes	 */
344191443Srwatson	dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
345194951Srwatson	IN_IFADDR_RLOCK();
346191443Srwatson	LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) {
347191443Srwatson		if (iap->ia_ifp == ifp &&
348191443Srwatson		    iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
349191443Srwatson			if (td == NULL || prison_check_ip4(td->td_ucred,
350191443Srwatson			    &dst) == 0)
351191443Srwatson				ia = iap;
352191443Srwatson			break;
353191443Srwatson		}
354191443Srwatson	}
355194760Srwatson	if (ia != NULL)
356194760Srwatson		ifa_ref(&ia->ia_ifa);
357194951Srwatson	IN_IFADDR_RUNLOCK();
358191443Srwatson	if (ia == NULL) {
359229621Sjhb		IF_ADDR_RLOCK(ifp);
360191443Srwatson		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
361191443Srwatson			iap = ifatoia(ifa);
362191443Srwatson			if (iap->ia_addr.sin_family == AF_INET) {
363191443Srwatson				if (td != NULL &&
364191443Srwatson				    prison_check_ip4(td->td_ucred,
365191443Srwatson				    &iap->ia_addr.sin_addr) != 0)
366191443Srwatson					continue;
367191443Srwatson				ia = iap;
36884102Sjlemon				break;
36984102Sjlemon			}
370191443Srwatson		}
371194760Srwatson		if (ia != NULL)
372194760Srwatson			ifa_ref(&ia->ia_ifa);
373229621Sjhb		IF_ADDR_RUNLOCK(ifp);
37484102Sjlemon	}
375191443Srwatson	if (ia == NULL)
376191443Srwatson		iaIsFirst = 1;
3771541Srgrimes
378191500Srwatson	error = 0;
3791541Srgrimes	switch (cmd) {
3801541Srgrimes	case SIOCAIFADDR:
3811541Srgrimes	case SIOCDIFADDR:
382227958Sglebius		if (ifra->ifra_addr.sin_family == AF_INET) {
383194760Srwatson			struct in_ifaddr *oia;
384194760Srwatson
385194951Srwatson			IN_IFADDR_RLOCK();
38671999Sphk			for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
3878071Swollman				if (ia->ia_ifp == ifp  &&
3888071Swollman				    ia->ia_addr.sin_addr.s_addr ==
3898071Swollman				    ifra->ifra_addr.sin_addr.s_addr)
3908071Swollman					break;
3918071Swollman			}
392194760Srwatson			if (ia != NULL && ia != oia)
393194760Srwatson				ifa_ref(&ia->ia_ifa);
394194760Srwatson			if (oia != NULL && ia != oia)
395194760Srwatson				ifa_free(&oia->ia_ifa);
396194951Srwatson			IN_IFADDR_RUNLOCK();
3978876Srgrimes			if ((ifp->if_flags & IFF_POINTOPOINT)
3988071Swollman			    && (cmd == SIOCAIFADDR)
3998071Swollman			    && (ifra->ifra_dstaddr.sin_addr.s_addr
4008071Swollman				== INADDR_ANY)) {
401191500Srwatson				error = EDESTADDRREQ;
402194760Srwatson				goto out;
4038071Swollman			}
4041541Srgrimes		}
405191500Srwatson		if (cmd == SIOCDIFADDR && ia == NULL) {
406191500Srwatson			error = EADDRNOTAVAIL;
407194760Srwatson			goto out;
408191500Srwatson		}
409184295Sbz		if (ia == NULL) {
41020407Swollman			ia = (struct in_ifaddr *)
411191500Srwatson				malloc(sizeof *ia, M_IFADDR, M_NOWAIT |
412191500Srwatson				    M_ZERO);
413191500Srwatson			if (ia == NULL) {
414191500Srwatson				error = ENOBUFS;
415194760Srwatson				goto out;
416191500Srwatson			}
417191500Srwatson
41820407Swollman			ifa = &ia->ia_ifa;
419194602Srwatson			ifa_init(ifa);
42020407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
42120407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
42220407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
423108033Shsu
4241541Srgrimes			ia->ia_sockmask.sin_len = 8;
42585740Sdes			ia->ia_sockmask.sin_family = AF_INET;
4261541Srgrimes			if (ifp->if_flags & IFF_BROADCAST) {
4271541Srgrimes				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
4281541Srgrimes				ia->ia_broadaddr.sin_family = AF_INET;
4291541Srgrimes			}
4301541Srgrimes			ia->ia_ifp = ifp;
431151824Sglebius
432194760Srwatson			ifa_ref(ifa);			/* if_addrhead */
433229621Sjhb			IF_ADDR_WLOCK(ifp);
434191285Srwatson			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
435229621Sjhb			IF_ADDR_WUNLOCK(ifp);
436194760Srwatson			ifa_ref(ifa);			/* in_ifaddrhead */
437194951Srwatson			IN_IFADDR_WLOCK();
438181803Sbz			TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link);
439194951Srwatson			IN_IFADDR_WUNLOCK();
44087124Sbrian			iaIsNew = 1;
4411541Srgrimes		}
4421541Srgrimes		break;
4431541Srgrimes
4441541Srgrimes	case SIOCGIFADDR:
4451541Srgrimes	case SIOCGIFNETMASK:
4461541Srgrimes	case SIOCGIFDSTADDR:
4471541Srgrimes	case SIOCGIFBRDADDR:
448191500Srwatson		if (ia == NULL) {
449191500Srwatson			error = EADDRNOTAVAIL;
450194760Srwatson			goto out;
451191500Srwatson		}
4521541Srgrimes		break;
4531541Srgrimes	}
454191500Srwatson
455191500Srwatson	/*
456194760Srwatson	 * Most paths in this switch return directly or via out.  Only paths
457194760Srwatson	 * that remove the address break in order to hit common removal code.
458191500Srwatson	 */
4591541Srgrimes	switch (cmd) {
4601541Srgrimes	case SIOCGIFADDR:
4611541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
462194760Srwatson		goto out;
4631541Srgrimes
4641541Srgrimes	case SIOCGIFBRDADDR:
465191500Srwatson		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
466191500Srwatson			error = EINVAL;
467194760Srwatson			goto out;
468191500Srwatson		}
4691541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
470194760Srwatson		goto out;
4711541Srgrimes
4721541Srgrimes	case SIOCGIFDSTADDR:
473191500Srwatson		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
474191500Srwatson			error = EINVAL;
475194760Srwatson			goto out;
476191500Srwatson		}
4771541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
478194760Srwatson		goto out;
4791541Srgrimes
4801541Srgrimes	case SIOCGIFNETMASK:
4811541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
482194760Srwatson		goto out;
4831541Srgrimes
4841541Srgrimes	case SIOCAIFADDR:
4851541Srgrimes		maskIsNew = 0;
4861541Srgrimes		hostIsNew = 1;
4871541Srgrimes		error = 0;
488227959Sglebius		if (ifra->ifra_addr.sin_addr.s_addr ==
489227791Sglebius			    ia->ia_addr.sin_addr.s_addr)
490227791Sglebius			hostIsNew = 0;
4911541Srgrimes		if (ifra->ifra_mask.sin_len) {
492238945Sglebius			/*
493197210Sqingli			 * QL: XXX
494197210Sqingli			 * Need to scrub the prefix here in case
495197210Sqingli			 * the issued command is SIOCAIFADDR with
496197210Sqingli			 * the same address, but with a different
497197210Sqingli			 * prefix length. And if the prefix length
498238945Sglebius			 * is the same as before, then the call is
499197210Sqingli			 * un-necessarily executed here.
500197210Sqingli			 */
501222438Sqingli			in_ifscrub(ifp, ia, LLE_STATIC);
5021541Srgrimes			ia->ia_sockmask = ifra->ifra_mask;
50385740Sdes			ia->ia_sockmask.sin_family = AF_INET;
5041541Srgrimes			ia->ia_subnetmask =
505238945Sglebius			    ntohl(ia->ia_sockmask.sin_addr.s_addr);
5061541Srgrimes			maskIsNew = 1;
5071541Srgrimes		}
5081541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) &&
5091541Srgrimes		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
510222438Sqingli			in_ifscrub(ifp, ia, LLE_STATIC);
5111541Srgrimes			ia->ia_dstaddr = ifra->ifra_dstaddr;
5121541Srgrimes			maskIsNew  = 1; /* We lie; but the effect's the same */
5131541Srgrimes		}
514227801Sglebius		if (hostIsNew || maskIsNew)
515230207Sglebius			error = in_ifinit(ifp, ia, &ifra->ifra_addr, maskIsNew,
516230207Sglebius			    (ocmd == cmd ? ifra->ifra_vhid : 0));
51787124Sbrian		if (error != 0 && iaIsNew)
518201811Sqingli			break;
51987124Sbrian
5201541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) &&
521227791Sglebius		    ifra->ifra_broadaddr.sin_len)
5221541Srgrimes			ia->ia_broadaddr = ifra->ifra_broadaddr;
523168032Sbms		if (error == 0) {
524189603Sbms			ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
525189592Sbms			if (iaIsFirst &&
526189592Sbms			    (ifp->if_flags & IFF_MULTICAST) != 0) {
527189592Sbms				error = in_joingroup(ifp, &allhosts_addr,
528189592Sbms				    NULL, &ii->ii_allhosts);
529189592Sbms			}
530126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
531168032Sbms		}
532194760Srwatson		goto out;
5331541Srgrimes
5341541Srgrimes	case SIOCDIFADDR:
53574299Sru		/*
53674299Sru		 * in_ifscrub kills the interface route.
53774299Sru		 */
538222143Sqingli		in_ifscrub(ifp, ia, LLE_STATIC);
539191500Srwatson
54015092Sdg		/*
54174299Sru		 * in_ifadown gets rid of all the rest of
54274299Sru		 * the routes.  This is not quite the right
54374299Sru		 * thing to do, but at least if we are running
54474299Sru		 * a routing process they will come back.
54574299Sru		 */
54676469Sru		in_ifadown(&ia->ia_ifa, 1);
547126264Smlaier		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
54887124Sbrian		error = 0;
5491541Srgrimes		break;
5501541Srgrimes
5511541Srgrimes	default:
552191443Srwatson		panic("in_control: unsupported ioctl");
5531541Srgrimes	}
55487124Sbrian
555228571Sglebius	if (ia->ia_ifa.ifa_carp)
556228571Sglebius		(*carp_detach_p)(&ia->ia_ifa);
557228571Sglebius
558229621Sjhb	IF_ADDR_WLOCK(ifp);
559213932Sbz	/* Re-check that ia is still part of the list. */
560213932Sbz	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
561213932Sbz		if (ifa == &ia->ia_ifa)
562213932Sbz			break;
563213932Sbz	}
564213932Sbz	if (ifa == NULL) {
565213932Sbz		/*
566213932Sbz		 * If we lost the race with another thread, there is no need to
567213932Sbz		 * try it again for the next loop as there is no other exit
568213932Sbz		 * path between here and out.
569213932Sbz		 */
570229621Sjhb		IF_ADDR_WUNLOCK(ifp);
571213932Sbz		error = EADDRNOTAVAIL;
572213932Sbz		goto out;
573213932Sbz	}
574191285Srwatson	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
575229621Sjhb	IF_ADDR_WUNLOCK(ifp);
576239395Srrs	ifa_free(&ia->ia_ifa);		      /* if_addrhead */
577194951Srwatson
578194951Srwatson	IN_IFADDR_WLOCK();
579181803Sbz	TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link);
580194760Srwatson
581227791Sglebius	LIST_REMOVE(ia, ia_hash);
582227791Sglebius	IN_IFADDR_WUNLOCK();
583227791Sglebius	/*
584227791Sglebius	 * If this is the last IPv4 address configured on this
585227791Sglebius	 * interface, leave the all-hosts group.
586227791Sglebius	 * No state-change report need be transmitted.
587227791Sglebius	 */
588227791Sglebius	IFP_TO_IA(ifp, iap);
589227791Sglebius	if (iap == NULL) {
590227791Sglebius		ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
591227791Sglebius		IN_MULTI_LOCK();
592227791Sglebius		if (ii->ii_allhosts) {
593227791Sglebius			(void)in_leavegroup_locked(ii->ii_allhosts, NULL);
594227791Sglebius			ii->ii_allhosts = NULL;
595227791Sglebius		}
596227791Sglebius		IN_MULTI_UNLOCK();
597194951Srwatson	} else
598227791Sglebius		ifa_free(&iap->ia_ifa);
599227791Sglebius
600194951Srwatson	ifa_free(&ia->ia_ifa);				/* in_ifaddrhead */
601194760Srwatsonout:
602194760Srwatson	if (ia != NULL)
603194760Srwatson		ifa_free(&ia->ia_ifa);
60487124Sbrian	return (error);
6051541Srgrimes}
6061541Srgrimes
6071541Srgrimes/*
60855009Sshin * SIOC[GAD]LIFADDR.
60955009Sshin *	SIOCGLIFADDR: get first address. (?!?)
61055009Sshin *	SIOCGLIFADDR with IFLR_PREFIX:
61155009Sshin *		get first address that matches the specified prefix.
61255009Sshin *	SIOCALIFADDR: add the specified address.
61355009Sshin *	SIOCALIFADDR with IFLR_PREFIX:
61455009Sshin *		EINVAL since we can't deduce hostid part of the address.
61555009Sshin *	SIOCDLIFADDR: delete the specified address.
61655009Sshin *	SIOCDLIFADDR with IFLR_PREFIX:
61755009Sshin *		delete the first address that matches the specified prefix.
61855009Sshin * return values:
61955009Sshin *	EINVAL on invalid parameters
62055009Sshin *	EADDRNOTAVAIL on prefix match failed/specified address not found
62155009Sshin *	other values may be returned from in_ioctl()
62255009Sshin */
62355009Sshinstatic int
624169454Srwatsonin_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
625169454Srwatson    struct ifnet *ifp, struct thread *td)
62655009Sshin{
62755009Sshin	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
62855009Sshin	struct ifaddr *ifa;
62955009Sshin
63055009Sshin	/* sanity checks */
631184295Sbz	if (data == NULL || ifp == NULL) {
63255009Sshin		panic("invalid argument to in_lifaddr_ioctl");
63355009Sshin		/*NOTRECHED*/
63455009Sshin	}
63555009Sshin
63655009Sshin	switch (cmd) {
63755009Sshin	case SIOCGLIFADDR:
63855009Sshin		/* address must be specified on GET with IFLR_PREFIX */
63955009Sshin		if ((iflr->flags & IFLR_PREFIX) == 0)
64055009Sshin			break;
64155009Sshin		/*FALLTHROUGH*/
64255009Sshin	case SIOCALIFADDR:
64355009Sshin	case SIOCDLIFADDR:
64455009Sshin		/* address must be specified on ADD and DELETE */
64555917Sshin		if (iflr->addr.ss_family != AF_INET)
646184295Sbz			return (EINVAL);
64755917Sshin		if (iflr->addr.ss_len != sizeof(struct sockaddr_in))
648184295Sbz			return (EINVAL);
64955009Sshin		/* XXX need improvement */
65055917Sshin		if (iflr->dstaddr.ss_family
65155917Sshin		 && iflr->dstaddr.ss_family != AF_INET)
652184295Sbz			return (EINVAL);
65355917Sshin		if (iflr->dstaddr.ss_family
65455917Sshin		 && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in))
655184295Sbz			return (EINVAL);
65655009Sshin		break;
65755009Sshin	default: /*shouldn't happen*/
658184295Sbz		return (EOPNOTSUPP);
65955009Sshin	}
66055009Sshin	if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
661184295Sbz		return (EINVAL);
66255009Sshin
66355009Sshin	switch (cmd) {
66455009Sshin	case SIOCALIFADDR:
66555009Sshin	    {
66655009Sshin		struct in_aliasreq ifra;
66755009Sshin
66855009Sshin		if (iflr->flags & IFLR_PREFIX)
669184295Sbz			return (EINVAL);
67055009Sshin
671229476Sjhb		/* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR). */
67255009Sshin		bzero(&ifra, sizeof(ifra));
67355009Sshin		bcopy(iflr->iflr_name, ifra.ifra_name,
67455009Sshin			sizeof(ifra.ifra_name));
67555009Sshin
67655917Sshin		bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
67755009Sshin
67855917Sshin		if (iflr->dstaddr.ss_family) {	/*XXX*/
67955009Sshin			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
68055917Sshin				iflr->dstaddr.ss_len);
68155009Sshin		}
68255009Sshin
68355009Sshin		ifra.ifra_mask.sin_family = AF_INET;
68455009Sshin		ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
68555009Sshin		in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
68655009Sshin
687184295Sbz		return (in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td));
68855009Sshin	    }
68955009Sshin	case SIOCGLIFADDR:
69055009Sshin	case SIOCDLIFADDR:
69155009Sshin	    {
69255009Sshin		struct in_ifaddr *ia;
69355009Sshin		struct in_addr mask, candidate, match;
69455009Sshin		struct sockaddr_in *sin;
69555009Sshin
69655009Sshin		bzero(&mask, sizeof(mask));
697170855Smjacob		bzero(&match, sizeof(match));
69855009Sshin		if (iflr->flags & IFLR_PREFIX) {
69955009Sshin			/* lookup a prefix rather than address. */
70055009Sshin			in_len2mask(&mask, iflr->prefixlen);
70155009Sshin
70255009Sshin			sin = (struct sockaddr_in *)&iflr->addr;
70355009Sshin			match.s_addr = sin->sin_addr.s_addr;
70455009Sshin			match.s_addr &= mask.s_addr;
70555009Sshin
70655009Sshin			/* if you set extra bits, that's wrong */
70755009Sshin			if (match.s_addr != sin->sin_addr.s_addr)
708184295Sbz				return (EINVAL);
70955009Sshin
71055009Sshin		} else {
711170855Smjacob			/* on getting an address, take the 1st match */
712170855Smjacob			/* on deleting an address, do exact match */
713170855Smjacob			if (cmd != SIOCGLIFADDR) {
71455009Sshin				in_len2mask(&mask, 32);
71555009Sshin				sin = (struct sockaddr_in *)&iflr->addr;
71655009Sshin				match.s_addr = sin->sin_addr.s_addr;
71755009Sshin			}
71855009Sshin		}
71955009Sshin
720229621Sjhb		IF_ADDR_RLOCK(ifp);
72155009Sshin		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)	{
722229476Sjhb			if (ifa->ifa_addr->sa_family != AF_INET)
72355009Sshin				continue;
724170855Smjacob			if (match.s_addr == 0)
72555009Sshin				break;
726229478Sjhb			sin = (struct sockaddr_in *)&ifa->ifa_addr;
727229478Sjhb			candidate.s_addr = sin->sin_addr.s_addr;
72855009Sshin			candidate.s_addr &= mask.s_addr;
72955009Sshin			if (candidate.s_addr == match.s_addr)
73055009Sshin				break;
73155009Sshin		}
732229477Sjhb		if (ifa != NULL)
733229477Sjhb			ifa_ref(ifa);
734229621Sjhb		IF_ADDR_RUNLOCK(ifp);
735184295Sbz		if (ifa == NULL)
736184295Sbz			return (EADDRNOTAVAIL);
73755009Sshin		ia = (struct in_ifaddr *)ifa;
73855009Sshin
73955009Sshin		if (cmd == SIOCGLIFADDR) {
74055009Sshin			/* fill in the if_laddrreq structure */
74155009Sshin			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
74255009Sshin
74355009Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
74455009Sshin				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
74555009Sshin					ia->ia_dstaddr.sin_len);
74655009Sshin			} else
74755009Sshin				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
74855009Sshin
74955009Sshin			iflr->prefixlen =
75055009Sshin				in_mask2len(&ia->ia_sockmask.sin_addr);
75155009Sshin
75255009Sshin			iflr->flags = 0;	/*XXX*/
753229477Sjhb			ifa_free(ifa);
75455009Sshin
755184295Sbz			return (0);
75655009Sshin		} else {
75755009Sshin			struct in_aliasreq ifra;
75855009Sshin
759229476Sjhb			/* fill in_aliasreq and do ioctl(SIOCDIFADDR) */
76055009Sshin			bzero(&ifra, sizeof(ifra));
76155009Sshin			bcopy(iflr->iflr_name, ifra.ifra_name,
76255009Sshin				sizeof(ifra.ifra_name));
76355009Sshin
76455009Sshin			bcopy(&ia->ia_addr, &ifra.ifra_addr,
76555009Sshin				ia->ia_addr.sin_len);
76655009Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
76755009Sshin				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
76855009Sshin					ia->ia_dstaddr.sin_len);
76955009Sshin			}
77055009Sshin			bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
77155009Sshin				ia->ia_sockmask.sin_len);
772229477Sjhb			ifa_free(ifa);
77355009Sshin
774184295Sbz			return (in_control(so, SIOCDIFADDR, (caddr_t)&ifra,
775184295Sbz			    ifp, td));
77655009Sshin		}
77755009Sshin	    }
77855009Sshin	}
77955009Sshin
780184295Sbz	return (EOPNOTSUPP);	/*just for safety*/
78155009Sshin}
78255009Sshin
78355009Sshin/*
7841541Srgrimes * Delete any existing route for an interface.
7851541Srgrimes */
78622672Swollmanvoid
787222143Sqingliin_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia, u_int flags)
7881541Srgrimes{
789169454Srwatson
790222143Sqingli	in_scrubprefix(ia, flags);
7911541Srgrimes}
7921541Srgrimes
7931541Srgrimes/*
7941541Srgrimes * Initialize an interface's internet address
7951541Srgrimes * and routing table entry.
7961541Srgrimes */
79712296Sphkstatic int
798169454Srwatsonin_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
799230207Sglebius    int masksupplied, int vhid)
8001541Srgrimes{
8011541Srgrimes	register u_long i = ntohl(sin->sin_addr.s_addr);
802244665Sglebius	int flags, error = 0;
8031541Srgrimes
804227791Sglebius	IN_IFADDR_WLOCK();
805227791Sglebius	if (ia->ia_addr.sin_family == AF_INET)
806105748Ssuz		LIST_REMOVE(ia, ia_hash);
8071541Srgrimes	ia->ia_addr = *sin;
808227791Sglebius	LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
809227791Sglebius	    ia, ia_hash);
810227791Sglebius	IN_IFADDR_WUNLOCK();
811227791Sglebius
812228571Sglebius	if (vhid > 0) {
813228571Sglebius		if (carp_attach_p != NULL)
814228571Sglebius			error = (*carp_attach_p)(&ia->ia_ifa, vhid);
815228571Sglebius		else
816228571Sglebius			error = EPROTONOSUPPORT;
817228571Sglebius	}
818228571Sglebius	if (error)
819228571Sglebius		return (error);
820228571Sglebius
8211541Srgrimes	/*
822244989Speter	 * Give the interface a chance to initialize
823244989Speter	 * if this is its first address,
824244989Speter	 * and to validate the address if necessary.
8251541Srgrimes	 */
826227791Sglebius	if (ifp->if_ioctl != NULL &&
827227791Sglebius	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) != 0)
828146883Siedowse			/* LIST_REMOVE(ia, ia_hash) is done in in_control */
829146883Siedowse			return (error);
830227791Sglebius
8311541Srgrimes	/*
832226401Sglebius	 * Be compatible with network classes, if netmask isn't supplied,
833226401Sglebius	 * guess it based on classes.
8341541Srgrimes	 */
835228313Sglebius	if (!masksupplied) {
836226401Sglebius		if (IN_CLASSA(i))
837226401Sglebius			ia->ia_subnetmask = IN_CLASSA_NET;
838226401Sglebius		else if (IN_CLASSB(i))
839226401Sglebius			ia->ia_subnetmask = IN_CLASSB_NET;
840226401Sglebius		else
841226401Sglebius			ia->ia_subnetmask = IN_CLASSC_NET;
8421541Srgrimes		ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
843226401Sglebius	}
8441541Srgrimes	ia->ia_subnet = i & ia->ia_subnetmask;
8451541Srgrimes	in_socktrim(&ia->ia_sockmask);
846244665Sglebius
8471541Srgrimes	/*
8481541Srgrimes	 * Add route for the network.
8491541Srgrimes	 */
850244665Sglebius	flags = RTF_UP;
8511541Srgrimes	ia->ia_ifa.ifa_metric = ifp->if_metric;
8521541Srgrimes	if (ifp->if_flags & IFF_BROADCAST) {
853226402Sglebius		if (ia->ia_subnetmask == IN_RFC3021_MASK)
854226402Sglebius			ia->ia_broadaddr.sin_addr.s_addr = INADDR_BROADCAST;
855226402Sglebius		else
856226402Sglebius			ia->ia_broadaddr.sin_addr.s_addr =
857226402Sglebius			    htonl(ia->ia_subnet | ~ia->ia_subnetmask);
8581541Srgrimes	} else if (ifp->if_flags & IFF_LOOPBACK) {
859137833Smlaier		ia->ia_dstaddr = ia->ia_addr;
8601541Srgrimes		flags |= RTF_HOST;
8611541Srgrimes	} else if (ifp->if_flags & IFF_POINTOPOINT) {
8621541Srgrimes		if (ia->ia_dstaddr.sin_family != AF_INET)
8631541Srgrimes			return (0);
8641541Srgrimes		flags |= RTF_HOST;
8651541Srgrimes	}
866228571Sglebius	if (!vhid && (error = in_addprefix(ia, flags)) != 0)
867137628Smlaier		return (error);
86894326Sbrian
869192085Sqingli	if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY)
870192085Sqingli		return (0);
871192085Sqingli
872227791Sglebius	if (ifp->if_flags & IFF_POINTOPOINT &&
873227791Sglebius	    ia->ia_dstaddr.sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr)
874203401Sqingli			return (0);
875203401Sqingli
876192011Sqingli	/*
877192011Sqingli	 * add a loopback route to self
878192011Sqingli	 */
879228571Sglebius	if (V_useloopback && !vhid && !(ifp->if_flags & IFF_LOOPBACK)) {
880201282Sqingli		struct route ia_ro;
881201282Sqingli
882201282Sqingli		bzero(&ia_ro, sizeof(ia_ro));
883201282Sqingli		*((struct sockaddr_in *)(&ia_ro.ro_dst)) = ia->ia_addr;
884231852Sbz		rtalloc_ign_fib(&ia_ro, 0, RT_DEFAULT_FIB);
885201282Sqingli		if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
886201282Sqingli		    (ia_ro.ro_rt->rt_ifp == V_loif)) {
887201282Sqingli			RT_LOCK(ia_ro.ro_rt);
888201282Sqingli			RT_ADDREF(ia_ro.ro_rt);
889201282Sqingli			RTFREE_LOCKED(ia_ro.ro_rt);
890201282Sqingli		} else
891238945Sglebius			error = ifa_add_loopback_route((struct ifaddr *)ia,
892238945Sglebius			    (struct sockaddr *)&ia->ia_addr);
893201282Sqingli		if (error == 0)
894201282Sqingli			ia->ia_flags |= IFA_RTSELF;
895201282Sqingli		if (ia_ro.ro_rt != NULL)
896201282Sqingli			RTFREE(ia_ro.ro_rt);
897201282Sqingli	}
898192011Sqingli
8991541Srgrimes	return (error);
9001541Srgrimes}
9011541Srgrimes
902137628Smlaier#define rtinitflags(x) \
903137628Smlaier	((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
904137628Smlaier	    ? RTF_HOST : 0)
905201285Sqingli
906137628Smlaier/*
907238945Sglebius * Generate a routing message when inserting or deleting
908201285Sqingli * an interface address alias.
909201285Sqingli */
910238945Sglebiusstatic void in_addralias_rtmsg(int cmd, struct in_addr *prefix,
911201285Sqingli    struct in_ifaddr *target)
912201285Sqingli{
913201285Sqingli	struct route pfx_ro;
914201285Sqingli	struct sockaddr_in *pfx_addr;
915201285Sqingli	struct rtentry msg_rt;
916201285Sqingli
917201285Sqingli	/* QL: XXX
918201285Sqingli	 * This is a bit questionable because there is no
919201285Sqingli	 * additional route entry added/deleted for an address
920201285Sqingli	 * alias. Therefore this route report is inaccurate.
921201285Sqingli	 */
922201285Sqingli	bzero(&pfx_ro, sizeof(pfx_ro));
923201285Sqingli	pfx_addr = (struct sockaddr_in *)(&pfx_ro.ro_dst);
924201285Sqingli	pfx_addr->sin_len = sizeof(*pfx_addr);
925201285Sqingli	pfx_addr->sin_family = AF_INET;
926201285Sqingli	pfx_addr->sin_addr = *prefix;
927201285Sqingli	rtalloc_ign_fib(&pfx_ro, 0, 0);
928201285Sqingli	if (pfx_ro.ro_rt != NULL) {
929201285Sqingli		msg_rt = *pfx_ro.ro_rt;
930201285Sqingli
931201285Sqingli		/* QL: XXX
932201285Sqingli		 * Point the gateway to the new interface
933238945Sglebius		 * address as if a new prefix route entry has
934238945Sglebius		 * been added through the new address alias.
935238945Sglebius		 * All other parts of the rtentry is accurate,
936201285Sqingli		 * e.g., rt_key, rt_mask, rt_ifp etc.
937201285Sqingli		 */
938238945Sglebius		msg_rt.rt_gateway = (struct sockaddr *)&target->ia_addr;
939238945Sglebius		rt_newaddrmsg(cmd, (struct ifaddr *)target, 0, &msg_rt);
940201285Sqingli		RTFREE(pfx_ro.ro_rt);
941201285Sqingli	}
942201285Sqingli	return;
943201285Sqingli}
944201285Sqingli
945201285Sqingli/*
946170855Smjacob * Check if we have a route for the given prefix already or add one accordingly.
947137628Smlaier */
948228571Sglebiusint
949169454Srwatsonin_addprefix(struct in_ifaddr *target, int flags)
950137628Smlaier{
951137628Smlaier	struct in_ifaddr *ia;
952151555Sglebius	struct in_addr prefix, mask, p, m;
953137628Smlaier	int error;
9541541Srgrimes
955170855Smjacob	if ((flags & RTF_HOST) != 0) {
956137628Smlaier		prefix = target->ia_dstaddr.sin_addr;
957170855Smjacob		mask.s_addr = 0;
958170855Smjacob	} else {
959137628Smlaier		prefix = target->ia_addr.sin_addr;
960137628Smlaier		mask = target->ia_sockmask.sin_addr;
961137628Smlaier		prefix.s_addr &= mask.s_addr;
962137628Smlaier	}
963137628Smlaier
964194951Srwatson	IN_IFADDR_RLOCK();
965181803Sbz	TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
966151555Sglebius		if (rtinitflags(ia)) {
967224747Skevlo			p = ia->ia_dstaddr.sin_addr;
968151555Sglebius
969151555Sglebius			if (prefix.s_addr != p.s_addr)
970151555Sglebius				continue;
971151555Sglebius		} else {
972151555Sglebius			p = ia->ia_addr.sin_addr;
973151555Sglebius			m = ia->ia_sockmask.sin_addr;
974151555Sglebius			p.s_addr &= m.s_addr;
975151555Sglebius
976151555Sglebius			if (prefix.s_addr != p.s_addr ||
977151555Sglebius			    mask.s_addr != m.s_addr)
978151555Sglebius				continue;
979137628Smlaier		}
980137628Smlaier
981137628Smlaier		/*
982137628Smlaier		 * If we got a matching prefix route inserted by other
983137628Smlaier		 * interface address, we are done here.
984137628Smlaier		 */
985149221Sglebius		if (ia->ia_flags & IFA_ROUTE) {
986204902Sqingli#ifdef RADIX_MPATH
987238945Sglebius			if (ia->ia_addr.sin_addr.s_addr ==
988212209Sbz			    target->ia_addr.sin_addr.s_addr) {
989212209Sbz				IN_IFADDR_RUNLOCK();
990204902Sqingli				return (EEXIST);
991212209Sbz			} else
992204902Sqingli				break;
993204902Sqingli#endif
994228571Sglebius			if (V_nosameprefix) {
995194951Srwatson				IN_IFADDR_RUNLOCK();
996149221Sglebius				return (EEXIST);
997194951Srwatson			} else {
998201285Sqingli				in_addralias_rtmsg(RTM_ADD, &prefix, target);
999194951Srwatson				IN_IFADDR_RUNLOCK();
1000149221Sglebius				return (0);
1001194951Srwatson			}
1002149221Sglebius		}
1003137628Smlaier	}
1004194951Srwatson	IN_IFADDR_RUNLOCK();
1005137628Smlaier
1006137628Smlaier	/*
1007137628Smlaier	 * No-one seem to have this prefix route, so we try to insert it.
1008137628Smlaier	 */
1009137628Smlaier	error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
1010137628Smlaier	if (!error)
1011137628Smlaier		target->ia_flags |= IFA_ROUTE;
1012184295Sbz	return (error);
1013137628Smlaier}
1014137628Smlaier
10151541Srgrimes/*
1016137628Smlaier * If there is no other address in the system that can serve a route to the
1017137628Smlaier * same prefix, remove the route.  Hand over the route to the new address
1018137628Smlaier * otherwise.
1019137628Smlaier */
1020228571Sglebiusint
1021222143Sqingliin_scrubprefix(struct in_ifaddr *target, u_int flags)
1022137628Smlaier{
1023137628Smlaier	struct in_ifaddr *ia;
1024228454Sglebius	struct in_addr prefix, mask, p, m;
1025201282Sqingli	int error = 0;
1026192476Sqingli	struct sockaddr_in prefix0, mask0;
1027137628Smlaier
1028195914Sqingli	/*
1029195914Sqingli	 * Remove the loopback route to the interface address.
1030195914Sqingli	 * The "useloopback" setting is not consulted because if the
1031195914Sqingli	 * user configures an interface address, turns off this
1032195914Sqingli	 * setting, and then tries to delete that interface address,
1033195914Sqingli	 * checking the current setting of "useloopback" would leave
1034195914Sqingli	 * that interface address loopback route untouched, which
1035195914Sqingli	 * would be wrong. Therefore the interface address loopback route
1036195914Sqingli	 * deletion is unconditional.
1037195914Sqingli	 */
1038192085Sqingli	if ((target->ia_addr.sin_addr.s_addr != INADDR_ANY) &&
1039201282Sqingli	    !(target->ia_ifp->if_flags & IFF_LOOPBACK) &&
1040201282Sqingli	    (target->ia_flags & IFA_RTSELF)) {
1041201282Sqingli		struct route ia_ro;
1042201282Sqingli		int freeit = 0;
1043201282Sqingli
1044201282Sqingli		bzero(&ia_ro, sizeof(ia_ro));
1045201282Sqingli		*((struct sockaddr_in *)(&ia_ro.ro_dst)) = target->ia_addr;
1046201282Sqingli		rtalloc_ign_fib(&ia_ro, 0, 0);
1047201282Sqingli		if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
1048201282Sqingli		    (ia_ro.ro_rt->rt_ifp == V_loif)) {
1049201282Sqingli			RT_LOCK(ia_ro.ro_rt);
1050201282Sqingli			if (ia_ro.ro_rt->rt_refcnt <= 1)
1051201282Sqingli				freeit = 1;
1052226114Sqingli			else if (flags & LLE_STATIC) {
1053201282Sqingli				RT_REMREF(ia_ro.ro_rt);
1054226114Sqingli				target->ia_flags &= ~IFA_RTSELF;
1055226114Sqingli			}
1056201282Sqingli			RTFREE_LOCKED(ia_ro.ro_rt);
1057201282Sqingli		}
1058222143Sqingli		if (freeit && (flags & LLE_STATIC)) {
1059201282Sqingli			error = ifa_del_loopback_route((struct ifaddr *)target,
1060238945Sglebius			    (struct sockaddr *)&target->ia_addr);
1061222143Sqingli			if (error == 0)
1062222143Sqingli				target->ia_flags &= ~IFA_RTSELF;
1063222143Sqingli		}
1064226120Sqingli		if ((flags & LLE_STATIC) &&
1065226120Sqingli			!(target->ia_ifp->if_flags & IFF_NOARP))
1066222143Sqingli			/* remove arp cache */
1067222143Sqingli			arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr);
1068192011Sqingli	}
1069192011Sqingli
1070228454Sglebius	if (rtinitflags(target)) {
1071137628Smlaier		prefix = target->ia_dstaddr.sin_addr;
1072228454Sglebius		mask.s_addr = 0;
1073228454Sglebius	} else {
1074137628Smlaier		prefix = target->ia_addr.sin_addr;
1075137628Smlaier		mask = target->ia_sockmask.sin_addr;
1076137628Smlaier		prefix.s_addr &= mask.s_addr;
1077137628Smlaier	}
1078137628Smlaier
1079201285Sqingli	if ((target->ia_flags & IFA_ROUTE) == 0) {
1080201285Sqingli		in_addralias_rtmsg(RTM_DELETE, &prefix, target);
1081201285Sqingli		return (0);
1082201285Sqingli	}
1083201285Sqingli
1084194951Srwatson	IN_IFADDR_RLOCK();
1085181803Sbz	TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
1086228454Sglebius		if (rtinitflags(ia)) {
1087137628Smlaier			p = ia->ia_dstaddr.sin_addr;
1088228454Sglebius
1089228454Sglebius			if (prefix.s_addr != p.s_addr)
1090228454Sglebius				continue;
1091228454Sglebius		} else {
1092137628Smlaier			p = ia->ia_addr.sin_addr;
1093228454Sglebius			m = ia->ia_sockmask.sin_addr;
1094228454Sglebius			p.s_addr &= m.s_addr;
1095228454Sglebius
1096228454Sglebius			if (prefix.s_addr != p.s_addr ||
1097228454Sglebius			    mask.s_addr != m.s_addr)
1098228454Sglebius				continue;
1099137628Smlaier		}
1100137628Smlaier
1101228454Sglebius		if ((ia->ia_ifp->if_flags & IFF_UP) == 0)
1102137628Smlaier			continue;
1103137628Smlaier
1104137628Smlaier		/*
1105137628Smlaier		 * If we got a matching prefix address, move IFA_ROUTE and
1106137628Smlaier		 * the route itself to it.  Make sure that routing daemons
1107137628Smlaier		 * get a heads-up.
1108137628Smlaier		 */
1109228571Sglebius		if ((ia->ia_flags & IFA_ROUTE) == 0) {
1110219828Spluknet			ifa_ref(&ia->ia_ifa);
1111194951Srwatson			IN_IFADDR_RUNLOCK();
1112222438Sqingli			error = rtinit(&(target->ia_ifa), (int)RTM_DELETE,
1113137628Smlaier			    rtinitflags(target));
1114222438Sqingli			if (error == 0)
1115222438Sqingli				target->ia_flags &= ~IFA_ROUTE;
1116222438Sqingli			else
1117222438Sqingli				log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n",
1118222438Sqingli					error);
1119137628Smlaier			error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
1120137628Smlaier			    rtinitflags(ia) | RTF_UP);
1121137628Smlaier			if (error == 0)
1122137628Smlaier				ia->ia_flags |= IFA_ROUTE;
1123222438Sqingli			else
1124222438Sqingli				log(LOG_INFO, "in_scrubprefix: err=%d, new prefix add failed\n",
1125222438Sqingli					error);
1126219828Spluknet			ifa_free(&ia->ia_ifa);
1127184295Sbz			return (error);
1128137628Smlaier		}
1129137628Smlaier	}
1130194951Srwatson	IN_IFADDR_RUNLOCK();
1131137628Smlaier
1132137628Smlaier	/*
1133192476Sqingli	 * remove all L2 entries on the given prefix
1134192476Sqingli	 */
1135192476Sqingli	bzero(&prefix0, sizeof(prefix0));
1136192476Sqingli	prefix0.sin_len = sizeof(prefix0);
1137192476Sqingli	prefix0.sin_family = AF_INET;
1138192476Sqingli	prefix0.sin_addr.s_addr = target->ia_subnet;
1139192476Sqingli	bzero(&mask0, sizeof(mask0));
1140192476Sqingli	mask0.sin_len = sizeof(mask0);
1141192476Sqingli	mask0.sin_family = AF_INET;
1142192476Sqingli	mask0.sin_addr.s_addr = target->ia_subnetmask;
1143238945Sglebius	lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0,
1144238945Sglebius	    (struct sockaddr *)&mask0, flags);
1145192476Sqingli
1146192476Sqingli	/*
1147137628Smlaier	 * As no-one seem to have this prefix, we can remove the route.
1148137628Smlaier	 */
1149222438Sqingli	error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
1150222438Sqingli	if (error == 0)
1151222438Sqingli		target->ia_flags &= ~IFA_ROUTE;
1152222438Sqingli	else
1153222438Sqingli		log(LOG_INFO, "in_scrubprefix: err=%d, prefix delete failed\n", error);
1154222438Sqingli	return (error);
1155137628Smlaier}
1156137628Smlaier
1157137628Smlaier#undef rtinitflags
1158137628Smlaier
1159137628Smlaier/*
11601541Srgrimes * Return 1 if the address might be a local broadcast address.
11611541Srgrimes */
11621549Srgrimesint
1163169454Srwatsonin_broadcast(struct in_addr in, struct ifnet *ifp)
11641541Srgrimes{
11651541Srgrimes	register struct ifaddr *ifa;
11661541Srgrimes	u_long t;
11671541Srgrimes
11681541Srgrimes	if (in.s_addr == INADDR_BROADCAST ||
11691541Srgrimes	    in.s_addr == INADDR_ANY)
1170184295Sbz		return (1);
11711541Srgrimes	if ((ifp->if_flags & IFF_BROADCAST) == 0)
1172184295Sbz		return (0);
11731541Srgrimes	t = ntohl(in.s_addr);
11741541Srgrimes	/*
11751541Srgrimes	 * Look through the list of addresses for a match
11761541Srgrimes	 * with a broadcast address.
11771541Srgrimes	 */
11781541Srgrimes#define ia ((struct in_ifaddr *)ifa)
117974362Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
11801541Srgrimes		if (ifa->ifa_addr->sa_family == AF_INET &&
11811541Srgrimes		    (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
11821541Srgrimes		     /*
1183226402Sglebius		      * Check for old-style (host 0) broadcast, but
1184226402Sglebius		      * taking into account that RFC 3021 obsoletes it.
11851541Srgrimes		      */
1186238945Sglebius		    (ia->ia_subnetmask != IN_RFC3021_MASK &&
1187238945Sglebius		    t == ia->ia_subnet)) &&
118813351Sguido		     /*
118913351Sguido		      * Check for an all one subnetmask. These
119013351Sguido		      * only exist when an interface gets a secondary
119113351Sguido		      * address.
119213351Sguido		      */
1193238945Sglebius		    ia->ia_subnetmask != (u_long)0xffffffff)
1194184295Sbz			    return (1);
11951541Srgrimes	return (0);
11961541Srgrimes#undef ia
11971541Srgrimes}
1198167729Sbms
11991541Srgrimes/*
1200189592Sbms * On interface removal, clean up IPv4 data structures hung off of the ifnet.
1201189592Sbms */
1202189592Sbmsvoid
1203189592Sbmsin_ifdetach(struct ifnet *ifp)
1204189592Sbms{
1205189592Sbms
1206189592Sbms	in_pcbpurgeif0(&V_ripcbinfo, ifp);
1207189592Sbms	in_pcbpurgeif0(&V_udbinfo, ifp);
1208189592Sbms	in_purgemaddrs(ifp);
1209189592Sbms}
1210189592Sbms
1211189592Sbms/*
1212167729Sbms * Delete all IPv4 multicast address records, and associated link-layer
1213167729Sbms * multicast address records, associated with ifp.
1214189592Sbms * XXX It looks like domifdetach runs AFTER the link layer cleanup.
1215189931Sbms * XXX This should not race with ifma_protospec being set during
1216189931Sbms * a new allocation, if it does, we have bigger problems.
1217162718Sbms */
1218167729Sbmsstatic void
1219167729Sbmsin_purgemaddrs(struct ifnet *ifp)
1220162718Sbms{
1221189592Sbms	LIST_HEAD(,in_multi) purgeinms;
1222189592Sbms	struct in_multi		*inm, *tinm;
1223189592Sbms	struct ifmultiaddr	*ifma;
1224162718Sbms
1225189592Sbms	LIST_INIT(&purgeinms);
1226162718Sbms	IN_MULTI_LOCK();
1227189592Sbms
1228189592Sbms	/*
1229189592Sbms	 * Extract list of in_multi associated with the detaching ifp
1230189592Sbms	 * which the PF_INET layer is about to release.
1231189592Sbms	 * We need to do this as IF_ADDR_LOCK() may be re-acquired
1232189592Sbms	 * by code further down.
1233189592Sbms	 */
1234229621Sjhb	IF_ADDR_RLOCK(ifp);
1235189592Sbms	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1236189931Sbms		if (ifma->ifma_addr->sa_family != AF_INET ||
1237189931Sbms		    ifma->ifma_protospec == NULL)
1238189592Sbms			continue;
1239189931Sbms#if 0
1240189931Sbms		KASSERT(ifma->ifma_protospec != NULL,
1241189931Sbms		    ("%s: ifma_protospec is NULL", __func__));
1242189931Sbms#endif
1243189592Sbms		inm = (struct in_multi *)ifma->ifma_protospec;
1244189592Sbms		LIST_INSERT_HEAD(&purgeinms, inm, inm_link);
1245162718Sbms	}
1246229621Sjhb	IF_ADDR_RUNLOCK(ifp);
1247150296Srwatson
1248189592Sbms	LIST_FOREACH_SAFE(inm, &purgeinms, inm_link, tinm) {
1249191476Srwatson		LIST_REMOVE(inm, inm_link);
1250189592Sbms		inm_release_locked(inm);
1251189592Sbms	}
1252189592Sbms	igmp_ifdetach(ifp);
1253150296Srwatson
1254189592Sbms	IN_MULTI_UNLOCK();
1255150296Srwatson}
1256186119Sqingli
1257186119Sqinglistruct in_llentry {
1258186119Sqingli	struct llentry		base;
1259186119Sqingli	struct sockaddr_in	l3_addr4;
1260186119Sqingli};
1261186119Sqingli
1262232054Skmacy/*
1263232054Skmacy * Deletes an address from the address table.
1264232054Skmacy * This function is called by the timer functions
1265232054Skmacy * such as arptimer() and nd6_llinfo_timer(), and
1266232054Skmacy * the caller does the locking.
1267232054Skmacy */
1268232054Skmacystatic void
1269232054Skmacyin_lltable_free(struct lltable *llt, struct llentry *lle)
1270232054Skmacy{
1271232054Skmacy	LLE_WUNLOCK(lle);
1272232054Skmacy	LLE_LOCK_DESTROY(lle);
1273232054Skmacy	free(lle, M_LLTABLE);
1274232054Skmacy}
1275232054Skmacy
1276186119Sqinglistatic struct llentry *
1277186119Sqingliin_lltable_new(const struct sockaddr *l3addr, u_int flags)
1278186119Sqingli{
1279186119Sqingli	struct in_llentry *lle;
1280186119Sqingli
1281234087Sglebius	lle = malloc(sizeof(struct in_llentry), M_LLTABLE, M_NOWAIT | M_ZERO);
1282186119Sqingli	if (lle == NULL)		/* NB: caller generates msg */
1283186119Sqingli		return NULL;
1284186119Sqingli
1285186119Sqingli	/*
1286186119Sqingli	 * For IPv4 this will trigger "arpresolve" to generate
1287186119Sqingli	 * an ARP request.
1288186119Sqingli	 */
1289216075Sglebius	lle->base.la_expire = time_uptime; /* mark expired */
1290186119Sqingli	lle->l3_addr4 = *(const struct sockaddr_in *)l3addr;
1291186119Sqingli	lle->base.lle_refcnt = 1;
1292232054Skmacy	lle->base.lle_free = in_lltable_free;
1293186119Sqingli	LLE_LOCK_INIT(&lle->base);
1294238990Sglebius	callout_init_rw(&lle->base.la_timer, &lle->base.lle_lock,
1295238990Sglebius	    CALLOUT_RETURNUNLOCKED);
1296238990Sglebius
1297238990Sglebius	return (&lle->base);
1298186119Sqingli}
1299186119Sqingli
1300192476Sqingli#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m)	(			\
1301192476Sqingli	    (((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
1302192476Sqingli
1303192476Sqinglistatic void
1304238945Sglebiusin_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
1305238945Sglebius    const struct sockaddr *mask, u_int flags)
1306192476Sqingli{
1307192476Sqingli	const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
1308192476Sqingli	const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
1309192476Sqingli	struct llentry *lle, *next;
1310238945Sglebius	int i;
1311215207Sgnn	size_t pkts_dropped;
1312192476Sqingli
1313238990Sglebius	IF_AFDATA_WLOCK(llt->llt_ifp);
1314238945Sglebius	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
1315192476Sqingli		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
1316238945Sglebius			/*
1317222143Sqingli			 * (flags & LLE_STATIC) means deleting all entries
1318238945Sglebius			 * including static ARP entries.
1319222143Sqingli			 */
1320238945Sglebius			if (IN_ARE_MASKED_ADDR_EQUAL(satosin(L3_ADDR(lle)),
1321238945Sglebius			    pfx, msk) && ((flags & LLE_STATIC) ||
1322238945Sglebius			    !(lle->la_flags & LLE_STATIC))) {
1323192476Sqingli				LLE_WLOCK(lle);
1324238990Sglebius				if (callout_stop(&lle->la_timer))
1325206481Sbz					LLE_REMREF(lle);
1326215207Sgnn				pkts_dropped = llentry_free(lle);
1327215207Sgnn				ARPSTAT_ADD(dropped, pkts_dropped);
1328192476Sqingli			}
1329192476Sqingli		}
1330192476Sqingli	}
1331238990Sglebius	IF_AFDATA_WUNLOCK(llt->llt_ifp);
1332192476Sqingli}
1333192476Sqingli
1334192476Sqingli
1335186119Sqinglistatic int
1336201282Sqingliin_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr)
1337186119Sqingli{
1338186119Sqingli	struct rtentry *rt;
1339186119Sqingli
1340186119Sqingli	KASSERT(l3addr->sa_family == AF_INET,
1341186119Sqingli	    ("sin_family %d", l3addr->sa_family));
1342186119Sqingli
1343186119Sqingli	/* XXX rtalloc1 should take a const param */
1344186119Sqingli	rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
1345223862Szec
1346225946Sqingli	if (rt == NULL)
1347225946Sqingli		return (EINVAL);
1348225946Sqingli
1349223862Szec	/*
1350223862Szec	 * If the gateway for an existing host route matches the target L3
1351225946Sqingli	 * address, which is a special route inserted by some implementation
1352225946Sqingli	 * such as MANET, and the interface is of the correct type, then
1353225946Sqingli	 * allow for ARP to proceed.
1354223862Szec	 */
1355225947Sqingli	if (rt->rt_flags & RTF_GATEWAY) {
1356226224Sqingli		if (!(rt->rt_flags & RTF_HOST) || !rt->rt_ifp ||
1357238945Sglebius		    rt->rt_ifp->if_type != IFT_ETHER ||
1358238945Sglebius		    (rt->rt_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 ||
1359238945Sglebius		    memcmp(rt->rt_gateway->sa_data, l3addr->sa_data,
1360238945Sglebius		    sizeof(in_addr_t)) != 0) {
1361226224Sqingli			RTFREE_LOCKED(rt);
1362226224Sqingli			return (EINVAL);
1363226224Sqingli		}
1364225947Sqingli	}
1365225947Sqingli
1366225947Sqingli	/*
1367238945Sglebius	 * Make sure that at least the destination address is covered
1368238945Sglebius	 * by the route. This is for handling the case where 2 or more
1369225947Sqingli	 * interfaces have the same prefix. An incoming packet arrives
1370225947Sqingli	 * on one interface and the corresponding outgoing packet leaves
1371225947Sqingli	 * another interface.
1372225947Sqingli	 */
1373226713Sqingli	if (!(rt->rt_flags & RTF_HOST) && rt->rt_ifp != ifp) {
1374226224Sqingli		const char *sa, *mask, *addr, *lim;
1375225947Sqingli		int len;
1376225947Sqingli
1377226713Sqingli		mask = (const char *)rt_mask(rt);
1378226713Sqingli		/*
1379226713Sqingli		 * Just being extra cautious to avoid some custom
1380226713Sqingli		 * code getting into trouble.
1381226713Sqingli		 */
1382226713Sqingli		if (mask == NULL) {
1383226713Sqingli			RTFREE_LOCKED(rt);
1384226713Sqingli			return (EINVAL);
1385226713Sqingli		}
1386226713Sqingli
1387226224Sqingli		sa = (const char *)rt_key(rt);
1388226224Sqingli		addr = (const char *)l3addr;
1389226224Sqingli		len = ((const struct sockaddr_in *)l3addr)->sin_len;
1390225947Sqingli		lim = addr + len;
1391225947Sqingli
1392225947Sqingli		for ( ; addr < lim; sa++, mask++, addr++) {
1393225947Sqingli			if ((*sa ^ *addr) & *mask) {
1394198418Sqingli#ifdef DIAGNOSTIC
1395225947Sqingli				log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
1396225947Sqingli				    inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
1397197696Sqingli#endif
1398226224Sqingli				RTFREE_LOCKED(rt);
1399226224Sqingli				return (EINVAL);
1400225947Sqingli			}
1401225947Sqingli		}
1402186119Sqingli	}
1403225947Sqingli
1404186119Sqingli	RTFREE_LOCKED(rt);
1405226224Sqingli	return (0);
1406186119Sqingli}
1407186119Sqingli
1408186119Sqingli/*
1409186119Sqingli * Return NULL if not found or marked for deletion.
1410186119Sqingli * If found return lle read locked.
1411186119Sqingli */
1412186119Sqinglistatic struct llentry *
1413186119Sqingliin_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
1414186119Sqingli{
1415186119Sqingli	const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
1416186119Sqingli	struct ifnet *ifp = llt->llt_ifp;
1417186119Sqingli	struct llentry *lle;
1418186119Sqingli	struct llentries *lleh;
1419186119Sqingli	u_int hashkey;
1420186119Sqingli
1421186119Sqingli	IF_AFDATA_LOCK_ASSERT(ifp);
1422186119Sqingli	KASSERT(l3addr->sa_family == AF_INET,
1423186119Sqingli	    ("sin_family %d", l3addr->sa_family));
1424186119Sqingli
1425186119Sqingli	hashkey = sin->sin_addr.s_addr;
1426186119Sqingli	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
1427186119Sqingli	LIST_FOREACH(lle, lleh, lle_next) {
1428238945Sglebius		struct sockaddr_in *sa2 = satosin(L3_ADDR(lle));
1429186119Sqingli		if (lle->la_flags & LLE_DELETED)
1430186119Sqingli			continue;
1431186708Sqingli		if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr)
1432186119Sqingli			break;
1433186119Sqingli	}
1434186119Sqingli	if (lle == NULL) {
1435198418Sqingli#ifdef DIAGNOSTIC
1436186119Sqingli		if (flags & LLE_DELETE)
1437238967Sglebius			log(LOG_INFO, "interface address is missing from cache = %p  in delete\n", lle);
1438186119Sqingli#endif
1439186119Sqingli		if (!(flags & LLE_CREATE))
1440186119Sqingli			return (NULL);
1441186119Sqingli		/*
1442186119Sqingli		 * A route that covers the given address must have
1443186119Sqingli		 * been installed 1st because we are doing a resolution,
1444186119Sqingli		 * verify this.
1445186119Sqingli		 */
1446186119Sqingli		if (!(flags & LLE_IFADDR) &&
1447201282Sqingli		    in_lltable_rtcheck(ifp, flags, l3addr) != 0)
1448186119Sqingli			goto done;
1449186119Sqingli
1450186119Sqingli		lle = in_lltable_new(l3addr, flags);
1451186119Sqingli		if (lle == NULL) {
1452186119Sqingli			log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
1453186119Sqingli			goto done;
1454186119Sqingli		}
1455186119Sqingli		lle->la_flags = flags & ~LLE_CREATE;
1456186119Sqingli		if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
1457186119Sqingli			bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
1458186119Sqingli			lle->la_flags |= (LLE_VALID | LLE_STATIC);
1459186119Sqingli		}
1460186119Sqingli
1461186119Sqingli		lle->lle_tbl  = llt;
1462186119Sqingli		lle->lle_head = lleh;
1463238990Sglebius		lle->la_flags |= LLE_LINKED;
1464186119Sqingli		LIST_INSERT_HEAD(lleh, lle, lle_next);
1465186119Sqingli	} else if (flags & LLE_DELETE) {
1466186119Sqingli		if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
1467186119Sqingli			LLE_WLOCK(lle);
1468238990Sglebius			lle->la_flags |= LLE_DELETED;
1469237263Snp			EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
1470198418Sqingli#ifdef DIAGNOSTIC
1471249742Soleg			log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
1472186119Sqingli#endif
1473249742Soleg			if ((lle->la_flags &
1474249742Soleg			    (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
1475249742Soleg				llentry_free(lle);
1476249742Soleg			else
1477249742Soleg				LLE_WUNLOCK(lle);
1478186119Sqingli		}
1479186119Sqingli		lle = (void *)-1;
1480238967Sglebius
1481186119Sqingli	}
1482186544Sbz	if (LLE_IS_VALID(lle)) {
1483186119Sqingli		if (flags & LLE_EXCLUSIVE)
1484186119Sqingli			LLE_WLOCK(lle);
1485186119Sqingli		else
1486186119Sqingli			LLE_RLOCK(lle);
1487186119Sqingli	}
1488186119Sqinglidone:
1489186119Sqingli	return (lle);
1490186119Sqingli}
1491186119Sqingli
1492186119Sqinglistatic int
1493186119Sqingliin_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
1494186119Sqingli{
1495186119Sqingli#define	SIN(lle)	((struct sockaddr_in *) L3_ADDR(lle))
1496186119Sqingli	struct ifnet *ifp = llt->llt_ifp;
1497186119Sqingli	struct llentry *lle;
1498186119Sqingli	/* XXX stack use */
1499186119Sqingli	struct {
1500186119Sqingli		struct rt_msghdr	rtm;
1501246143Sglebius		struct sockaddr_in	sin;
1502186119Sqingli		struct sockaddr_dl	sdl;
1503186119Sqingli	} arpc;
1504186119Sqingli	int error, i;
1505186119Sqingli
1506196535Srwatson	LLTABLE_LOCK_ASSERT();
1507186119Sqingli
1508186119Sqingli	error = 0;
1509186119Sqingli	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
1510186119Sqingli		LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
1511186119Sqingli			struct sockaddr_dl *sdl;
1512238967Sglebius
1513186119Sqingli			/* skip deleted entries */
1514198111Sqingli			if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
1515186119Sqingli				continue;
1516186980Sbz			/* Skip if jailed and not a valid IP of the prison. */
1517188144Sjamie			if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0)
1518186980Sbz				continue;
1519186119Sqingli			/*
1520186119Sqingli			 * produce a msg made of:
1521186119Sqingli			 *  struct rt_msghdr;
1522246143Sglebius			 *  struct sockaddr_in; (IPv4)
1523186119Sqingli			 *  struct sockaddr_dl;
1524186119Sqingli			 */
1525186119Sqingli			bzero(&arpc, sizeof(arpc));
1526186119Sqingli			arpc.rtm.rtm_msglen = sizeof(arpc);
1527186935Sharti			arpc.rtm.rtm_version = RTM_VERSION;
1528186935Sharti			arpc.rtm.rtm_type = RTM_GET;
1529186935Sharti			arpc.rtm.rtm_flags = RTF_UP;
1530186935Sharti			arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
1531186119Sqingli			arpc.sin.sin_family = AF_INET;
1532186119Sqingli			arpc.sin.sin_len = sizeof(arpc.sin);
1533186119Sqingli			arpc.sin.sin_addr.s_addr = SIN(lle)->sin_addr.s_addr;
1534186119Sqingli
1535186119Sqingli			/* publish */
1536246143Sglebius			if (lle->la_flags & LLE_PUB)
1537186119Sqingli				arpc.rtm.rtm_flags |= RTF_ANNOUNCE;
1538186119Sqingli
1539186119Sqingli			sdl = &arpc.sdl;
1540186119Sqingli			sdl->sdl_family = AF_LINK;
1541186119Sqingli			sdl->sdl_len = sizeof(*sdl);
1542186119Sqingli			sdl->sdl_index = ifp->if_index;
1543186119Sqingli			sdl->sdl_type = ifp->if_type;
1544198111Sqingli			if ((lle->la_flags & LLE_VALID) == LLE_VALID) {
1545198111Sqingli				sdl->sdl_alen = ifp->if_addrlen;
1546198111Sqingli				bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
1547198111Sqingli			} else {
1548198111Sqingli				sdl->sdl_alen = 0;
1549198111Sqingli				bzero(LLADDR(sdl), ifp->if_addrlen);
1550198111Sqingli			}
1551186119Sqingli
1552186119Sqingli			arpc.rtm.rtm_rmx.rmx_expire =
1553186119Sqingli			    lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
1554186500Sqingli			arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
1555186119Sqingli			if (lle->la_flags & LLE_STATIC)
1556186119Sqingli				arpc.rtm.rtm_flags |= RTF_STATIC;
1557186119Sqingli			arpc.rtm.rtm_index = ifp->if_index;
1558186119Sqingli			error = SYSCTL_OUT(wr, &arpc, sizeof(arpc));
1559186119Sqingli			if (error)
1560186119Sqingli				break;
1561186119Sqingli		}
1562186119Sqingli	}
1563186119Sqingli	return error;
1564186119Sqingli#undef SIN
1565186119Sqingli}
1566186119Sqingli
1567186119Sqinglivoid *
1568186119Sqingliin_domifattach(struct ifnet *ifp)
1569189592Sbms{
1570189592Sbms	struct in_ifinfo *ii;
1571189592Sbms	struct lltable *llt;
1572189592Sbms
1573189592Sbms	ii = malloc(sizeof(struct in_ifinfo), M_IFADDR, M_WAITOK|M_ZERO);
1574189592Sbms
1575189592Sbms	llt = lltable_init(ifp, AF_INET);
1576186119Sqingli	if (llt != NULL) {
1577192476Sqingli		llt->llt_prefix_free = in_lltable_prefix_free;
1578186119Sqingli		llt->llt_lookup = in_lltable_lookup;
1579186119Sqingli		llt->llt_dump = in_lltable_dump;
1580186119Sqingli	}
1581189592Sbms	ii->ii_llt = llt;
1582189592Sbms
1583189592Sbms	ii->ii_igmp = igmp_domifattach(ifp);
1584189592Sbms
1585189592Sbms	return ii;
1586186119Sqingli}
1587186119Sqingli
1588186119Sqinglivoid
1589189592Sbmsin_domifdetach(struct ifnet *ifp, void *aux)
1590186119Sqingli{
1591189592Sbms	struct in_ifinfo *ii = (struct in_ifinfo *)aux;
1592186119Sqingli
1593189592Sbms	igmp_domifdetach(ifp);
1594189592Sbms	lltable_free(ii->ii_llt);
1595189592Sbms	free(ii, M_IFADDR);
1596186119Sqingli}
1597