in.c revision 170855
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
3150477Speter * $FreeBSD: head/sys/netinet/in.c 170855 2007-06-17 00:31:24Z mjacob $
321541Srgrimes */
331541Srgrimes
34143868Sglebius#include "opt_carp.h"
35143868Sglebius
361541Srgrimes#include <sys/param.h>
371549Srgrimes#include <sys/systm.h>
3824204Sbde#include <sys/sockio.h>
391541Srgrimes#include <sys/malloc.h>
40164033Srwatson#include <sys/priv.h>
411541Srgrimes#include <sys/socket.h>
4212704Sphk#include <sys/kernel.h>
4312704Sphk#include <sys/sysctl.h>
441541Srgrimes
451541Srgrimes#include <net/if.h>
4655009Sshin#include <net/if_types.h>
471541Srgrimes#include <net/route.h>
481541Srgrimes
491541Srgrimes#include <netinet/in.h>
501541Srgrimes#include <netinet/in_var.h>
5181127Sume#include <netinet/in_pcb.h>
52170613Sbms#include <netinet/ip_var.h>
531541Srgrimes
5492723Salfredstatic int in_mask2len(struct in_addr *);
5592723Salfredstatic void in_len2mask(struct in_addr *, int);
5692723Salfredstatic int in_lifaddr_ioctl(struct socket *, u_long, caddr_t,
5792723Salfred	struct ifnet *, struct thread *);
5855009Sshin
59137628Smlaierstatic int	in_addprefix(struct in_ifaddr *, int);
60137628Smlaierstatic int	in_scrubprefix(struct in_ifaddr *);
6192723Salfredstatic void	in_socktrim(struct sockaddr_in *);
6292723Salfredstatic int	in_ifinit(struct ifnet *,
6392723Salfred	    struct in_ifaddr *, struct sockaddr_in *, int);
64167729Sbmsstatic void	in_purgemaddrs(struct ifnet *);
651541Srgrimes
6618193Swollmanstatic int subnetsarelocal = 0;
67133874SrwatsonSYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
68123998Sru	&subnetsarelocal, 0, "Treat all subnets as directly connected");
69149221Sglebiusstatic int sameprefixcarponly = 0;
70149221SglebiusSYSCTL_INT(_net_inet_ip, OID_AUTO, same_prefix_carp_only, CTLFLAG_RW,
71149221Sglebius	&sameprefixcarponly, 0,
72149221Sglebius	"Refuse to create same prefixes on different interfaces");
7321666Swollman
7481127Sumeextern struct inpcbinfo ripcbinfo;
7581127Sumeextern struct inpcbinfo udbinfo;
7681127Sume
771541Srgrimes/*
781541Srgrimes * Return 1 if an internet address is for a ``local'' host
791541Srgrimes * (one to which we have a connection).  If subnetsarelocal
801541Srgrimes * is true, this includes other subnets of the local net.
811541Srgrimes * Otherwise, it includes only the directly-connected (sub)nets.
821541Srgrimes */
831549Srgrimesint
84169454Srwatsonin_localaddr(struct in_addr in)
851541Srgrimes{
861541Srgrimes	register u_long i = ntohl(in.s_addr);
871541Srgrimes	register struct in_ifaddr *ia;
881541Srgrimes
891541Srgrimes	if (subnetsarelocal) {
9074362Sphk		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
911541Srgrimes			if ((i & ia->ia_netmask) == ia->ia_net)
921541Srgrimes				return (1);
931541Srgrimes	} else {
9472012Sphk		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
951541Srgrimes			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
961541Srgrimes				return (1);
971541Srgrimes	}
981541Srgrimes	return (0);
991541Srgrimes}
1001541Srgrimes
1011541Srgrimes/*
102133486Sandre * Return 1 if an internet address is for the local host and configured
103133486Sandre * on one of its interfaces.
104133486Sandre */
105133486Sandreint
106169454Srwatsonin_localip(struct in_addr in)
107133486Sandre{
108133486Sandre	struct in_ifaddr *ia;
109133486Sandre
110133486Sandre	LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) {
111133486Sandre		if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr)
112133486Sandre			return 1;
113133486Sandre	}
114133486Sandre	return 0;
115133486Sandre}
116133486Sandre
117133486Sandre/*
1181541Srgrimes * Determine whether an IP address is in a reserved set of addresses
1191541Srgrimes * that may not be forwarded, or whether datagrams to that destination
1201541Srgrimes * may be forwarded.
1211541Srgrimes */
1221549Srgrimesint
123169454Srwatsonin_canforward(struct in_addr in)
1241541Srgrimes{
1251541Srgrimes	register u_long i = ntohl(in.s_addr);
1261541Srgrimes	register u_long net;
1271541Srgrimes
128166450Sbms	if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i) || IN_LINKLOCAL(i))
1291541Srgrimes		return (0);
1301541Srgrimes	if (IN_CLASSA(i)) {
1311541Srgrimes		net = i & IN_CLASSA_NET;
1321541Srgrimes		if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
1331541Srgrimes			return (0);
1341541Srgrimes	}
1351541Srgrimes	return (1);
1361541Srgrimes}
1371541Srgrimes
1381541Srgrimes/*
1391541Srgrimes * Trim a mask in a sockaddr
1401541Srgrimes */
14112296Sphkstatic void
142169454Srwatsonin_socktrim(struct sockaddr_in *ap)
1431541Srgrimes{
1441541Srgrimes    register char *cplim = (char *) &ap->sin_addr;
1451541Srgrimes    register char *cp = (char *) (&ap->sin_addr + 1);
1461541Srgrimes
1471541Srgrimes    ap->sin_len = 0;
1484127Swollman    while (--cp >= cplim)
149133874Srwatson	if (*cp) {
1501541Srgrimes	    (ap)->sin_len = cp - (char *) (ap) + 1;
1511541Srgrimes	    break;
1521541Srgrimes	}
1531541Srgrimes}
1541541Srgrimes
15555009Sshinstatic int
15655009Sshinin_mask2len(mask)
15755009Sshin	struct in_addr *mask;
15855009Sshin{
15955009Sshin	int x, y;
16055009Sshin	u_char *p;
16155009Sshin
16255009Sshin	p = (u_char *)mask;
16355009Sshin	for (x = 0; x < sizeof(*mask); x++) {
16455009Sshin		if (p[x] != 0xff)
16555009Sshin			break;
16655009Sshin	}
16755009Sshin	y = 0;
16855009Sshin	if (x < sizeof(*mask)) {
16955009Sshin		for (y = 0; y < 8; y++) {
17055009Sshin			if ((p[x] & (0x80 >> y)) == 0)
17155009Sshin				break;
17255009Sshin		}
17355009Sshin	}
17455009Sshin	return x * 8 + y;
17555009Sshin}
17655009Sshin
17755009Sshinstatic void
178169454Srwatsonin_len2mask(struct in_addr *mask, int len)
17955009Sshin{
18055009Sshin	int i;
18155009Sshin	u_char *p;
18255009Sshin
18355009Sshin	p = (u_char *)mask;
18455009Sshin	bzero(mask, sizeof(*mask));
18555009Sshin	for (i = 0; i < len / 8; i++)
18655009Sshin		p[i] = 0xff;
18755009Sshin	if (len % 8)
18855009Sshin		p[i] = (0xff00 >> (len % 8)) & 0xff;
18955009Sshin}
19055009Sshin
1911541Srgrimes/*
1921541Srgrimes * Generic internet control operations (ioctl's).
1931541Srgrimes * Ifp is 0 if not an interface-specific ioctl.
1941541Srgrimes */
1951541Srgrimes/* ARGSUSED */
1961549Srgrimesint
197169454Srwatsonin_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
198169454Srwatson    struct thread *td)
1991541Srgrimes{
2001541Srgrimes	register struct ifreq *ifr = (struct ifreq *)data;
20114632Sfenner	register struct in_ifaddr *ia = 0, *iap;
2021541Srgrimes	register struct ifaddr *ifa;
203168032Sbms	struct in_addr allhosts_addr;
20484102Sjlemon	struct in_addr dst;
2051541Srgrimes	struct in_ifaddr *oia;
2061541Srgrimes	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
2071541Srgrimes	struct sockaddr_in oldaddr;
20887124Sbrian	int error, hostIsNew, iaIsNew, maskIsNew, s;
209168032Sbms	int iaIsFirst;
2101541Srgrimes
211168032Sbms	iaIsFirst = 0;
21287124Sbrian	iaIsNew = 0;
213168032Sbms	allhosts_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
21487124Sbrian
21555009Sshin	switch (cmd) {
21655009Sshin	case SIOCALIFADDR:
217164033Srwatson		if (td != NULL) {
218164033Srwatson			error = priv_check(td, PRIV_NET_ADDIFADDR);
219164033Srwatson			if (error)
220164033Srwatson				return (error);
221164033Srwatson		}
222164033Srwatson		if (!ifp)
223164033Srwatson			return EINVAL;
224164033Srwatson		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
225164033Srwatson
22655009Sshin	case SIOCDLIFADDR:
227164033Srwatson		if (td != NULL) {
228164033Srwatson			error = priv_check(td, PRIV_NET_DELIFADDR);
229164033Srwatson			if (error)
230164033Srwatson				return (error);
231164033Srwatson		}
232164033Srwatson		if (!ifp)
233164033Srwatson			return EINVAL;
234164033Srwatson		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
235164033Srwatson
23655009Sshin	case SIOCGLIFADDR:
23755009Sshin		if (!ifp)
23855009Sshin			return EINVAL;
23983366Sjulian		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
24055009Sshin	}
24155009Sshin
2421541Srgrimes	/*
2431541Srgrimes	 * Find address for this interface, if it exists.
24414632Sfenner	 *
24514632Sfenner	 * If an alias address was specified, find that one instead of
24684102Sjlemon	 * the first one on the interface, if possible.
2471541Srgrimes	 */
24884102Sjlemon	if (ifp) {
24984102Sjlemon		dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
25084102Sjlemon		LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash)
25184102Sjlemon			if (iap->ia_ifp == ifp &&
25284102Sjlemon			    iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
25384102Sjlemon				ia = iap;
25484102Sjlemon				break;
25584102Sjlemon			}
25684102Sjlemon		if (ia == NULL)
25784102Sjlemon			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
25884102Sjlemon				iap = ifatoia(ifa);
25984102Sjlemon				if (iap->ia_addr.sin_family == AF_INET) {
26014632Sfenner					ia = iap;
26114632Sfenner					break;
26214632Sfenner				}
26314632Sfenner			}
264168032Sbms		if (ia == NULL)
265168032Sbms			iaIsFirst = 1;
26684102Sjlemon	}
2671541Srgrimes
2681541Srgrimes	switch (cmd) {
2691541Srgrimes
2701541Srgrimes	case SIOCAIFADDR:
2711541Srgrimes	case SIOCDIFADDR:
27241575Seivind		if (ifp == 0)
27341575Seivind			return (EADDRNOTAVAIL);
2748071Swollman		if (ifra->ifra_addr.sin_family == AF_INET) {
27571999Sphk			for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
2768071Swollman				if (ia->ia_ifp == ifp  &&
2778071Swollman				    ia->ia_addr.sin_addr.s_addr ==
2788071Swollman				    ifra->ifra_addr.sin_addr.s_addr)
2798071Swollman					break;
2808071Swollman			}
2818876Srgrimes			if ((ifp->if_flags & IFF_POINTOPOINT)
2828071Swollman			    && (cmd == SIOCAIFADDR)
2838071Swollman			    && (ifra->ifra_dstaddr.sin_addr.s_addr
2848071Swollman				== INADDR_ANY)) {
2859563Swollman				return EDESTADDRREQ;
2868071Swollman			}
2871541Srgrimes		}
2881541Srgrimes		if (cmd == SIOCDIFADDR && ia == 0)
2891541Srgrimes			return (EADDRNOTAVAIL);
2901541Srgrimes		/* FALLTHROUGH */
2911541Srgrimes	case SIOCSIFADDR:
2921541Srgrimes	case SIOCSIFNETMASK:
2931541Srgrimes	case SIOCSIFDSTADDR:
294164033Srwatson		if (td != NULL) {
295164033Srwatson			error = priv_check(td, PRIV_NET_ADDIFADDR);
296164033Srwatson			if (error)
297164033Srwatson				return (error);
298164033Srwatson		}
2991541Srgrimes
3001541Srgrimes		if (ifp == 0)
30141575Seivind			return (EADDRNOTAVAIL);
3021541Srgrimes		if (ia == (struct in_ifaddr *)0) {
30320407Swollman			ia = (struct in_ifaddr *)
304111119Simp				malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
30520407Swollman			if (ia == (struct in_ifaddr *)NULL)
3061541Srgrimes				return (ENOBUFS);
30715092Sdg			/*
30815092Sdg			 * Protect from ipintr() traversing address list
30915092Sdg			 * while we're modifying it.
31015092Sdg			 */
31115092Sdg			s = splnet();
31220407Swollman			ifa = &ia->ia_ifa;
313108033Shsu			IFA_LOCK_INIT(ifa);
31420407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
31520407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
31620407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
317108033Shsu			ifa->ifa_refcnt = 1;
318108033Shsu			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
319108033Shsu
3201541Srgrimes			ia->ia_sockmask.sin_len = 8;
32185740Sdes			ia->ia_sockmask.sin_family = AF_INET;
3221541Srgrimes			if (ifp->if_flags & IFF_BROADCAST) {
3231541Srgrimes				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
3241541Srgrimes				ia->ia_broadaddr.sin_family = AF_INET;
3251541Srgrimes			}
3261541Srgrimes			ia->ia_ifp = ifp;
327151824Sglebius
328151824Sglebius			TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
32915092Sdg			splx(s);
33087124Sbrian			iaIsNew = 1;
3311541Srgrimes		}
3321541Srgrimes		break;
3331541Srgrimes
3341541Srgrimes	case SIOCSIFBRDADDR:
335164033Srwatson		if (td != NULL) {
336164033Srwatson			error = priv_check(td, PRIV_NET_ADDIFADDR);
337164033Srwatson			if (error)
338164033Srwatson				return (error);
339164033Srwatson		}
3401541Srgrimes		/* FALLTHROUGH */
3411541Srgrimes
3421541Srgrimes	case SIOCGIFADDR:
3431541Srgrimes	case SIOCGIFNETMASK:
3441541Srgrimes	case SIOCGIFDSTADDR:
3451541Srgrimes	case SIOCGIFBRDADDR:
3461541Srgrimes		if (ia == (struct in_ifaddr *)0)
3471541Srgrimes			return (EADDRNOTAVAIL);
3481541Srgrimes		break;
3491541Srgrimes	}
3501541Srgrimes	switch (cmd) {
3511541Srgrimes
3521541Srgrimes	case SIOCGIFADDR:
3531541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
35487124Sbrian		return (0);
3551541Srgrimes
3561541Srgrimes	case SIOCGIFBRDADDR:
3571541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) == 0)
3581541Srgrimes			return (EINVAL);
3591541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
36087124Sbrian		return (0);
3611541Srgrimes
3621541Srgrimes	case SIOCGIFDSTADDR:
3631541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
3641541Srgrimes			return (EINVAL);
3651541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
36687124Sbrian		return (0);
3671541Srgrimes
3681541Srgrimes	case SIOCGIFNETMASK:
3691541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
37087124Sbrian		return (0);
3711541Srgrimes
3721541Srgrimes	case SIOCSIFDSTADDR:
3731541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
3741541Srgrimes			return (EINVAL);
3751541Srgrimes		oldaddr = ia->ia_dstaddr;
3761541Srgrimes		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
377146883Siedowse		if (ifp->if_ioctl) {
378146883Siedowse			IFF_LOCKGIANT(ifp);
379146883Siedowse			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR,
380146883Siedowse			    (caddr_t)ia);
381146883Siedowse			IFF_UNLOCKGIANT(ifp);
382146883Siedowse			if (error) {
383146883Siedowse				ia->ia_dstaddr = oldaddr;
384146883Siedowse				return (error);
385146883Siedowse			}
3861541Srgrimes		}
3871541Srgrimes		if (ia->ia_flags & IFA_ROUTE) {
3881541Srgrimes			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
3891541Srgrimes			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
3901541Srgrimes			ia->ia_ifa.ifa_dstaddr =
3911541Srgrimes					(struct sockaddr *)&ia->ia_dstaddr;
3921541Srgrimes			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
3931541Srgrimes		}
39487124Sbrian		return (0);
3951541Srgrimes
3961541Srgrimes	case SIOCSIFBRDADDR:
3971541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) == 0)
3981541Srgrimes			return (EINVAL);
3991541Srgrimes		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
40087124Sbrian		return (0);
4011541Srgrimes
4021541Srgrimes	case SIOCSIFADDR:
40387124Sbrian		error = in_ifinit(ifp, ia,
40487124Sbrian		    (struct sockaddr_in *) &ifr->ifr_addr, 1);
40587124Sbrian		if (error != 0 && iaIsNew)
40687124Sbrian			break;
407168032Sbms		if (error == 0) {
408168032Sbms			if (iaIsFirst && (ifp->if_flags & IFF_MULTICAST) != 0)
409168032Sbms				in_addmulti(&allhosts_addr, ifp);
410126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
411168032Sbms		}
41287124Sbrian		return (0);
4131541Srgrimes
4141541Srgrimes	case SIOCSIFNETMASK:
41585740Sdes		ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
41685740Sdes		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
41787124Sbrian		return (0);
4181541Srgrimes
4191541Srgrimes	case SIOCAIFADDR:
4201541Srgrimes		maskIsNew = 0;
4211541Srgrimes		hostIsNew = 1;
4221541Srgrimes		error = 0;
4231541Srgrimes		if (ia->ia_addr.sin_family == AF_INET) {
4241541Srgrimes			if (ifra->ifra_addr.sin_len == 0) {
4251541Srgrimes				ifra->ifra_addr = ia->ia_addr;
4261541Srgrimes				hostIsNew = 0;
4271541Srgrimes			} else if (ifra->ifra_addr.sin_addr.s_addr ==
4281541Srgrimes					       ia->ia_addr.sin_addr.s_addr)
4291541Srgrimes				hostIsNew = 0;
4301541Srgrimes		}
4311541Srgrimes		if (ifra->ifra_mask.sin_len) {
4321541Srgrimes			in_ifscrub(ifp, ia);
4331541Srgrimes			ia->ia_sockmask = ifra->ifra_mask;
43485740Sdes			ia->ia_sockmask.sin_family = AF_INET;
4351541Srgrimes			ia->ia_subnetmask =
4361541Srgrimes			     ntohl(ia->ia_sockmask.sin_addr.s_addr);
4371541Srgrimes			maskIsNew = 1;
4381541Srgrimes		}
4391541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) &&
4401541Srgrimes		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
4411541Srgrimes			in_ifscrub(ifp, ia);
4421541Srgrimes			ia->ia_dstaddr = ifra->ifra_dstaddr;
4431541Srgrimes			maskIsNew  = 1; /* We lie; but the effect's the same */
4441541Srgrimes		}
4451541Srgrimes		if (ifra->ifra_addr.sin_family == AF_INET &&
4461541Srgrimes		    (hostIsNew || maskIsNew))
4471541Srgrimes			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
44887124Sbrian		if (error != 0 && iaIsNew)
44987124Sbrian			break;
45087124Sbrian
4511541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) &&
4521541Srgrimes		    (ifra->ifra_broadaddr.sin_family == AF_INET))
4531541Srgrimes			ia->ia_broadaddr = ifra->ifra_broadaddr;
454168032Sbms		if (error == 0) {
455168032Sbms			if (iaIsFirst && (ifp->if_flags & IFF_MULTICAST) != 0)
456168032Sbms				in_addmulti(&allhosts_addr, ifp);
457126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
458168032Sbms		}
4591541Srgrimes		return (error);
4601541Srgrimes
4611541Srgrimes	case SIOCDIFADDR:
46274299Sru		/*
46374299Sru		 * in_ifscrub kills the interface route.
46474299Sru		 */
4651541Srgrimes		in_ifscrub(ifp, ia);
46615092Sdg		/*
46774299Sru		 * in_ifadown gets rid of all the rest of
46874299Sru		 * the routes.  This is not quite the right
46974299Sru		 * thing to do, but at least if we are running
47074299Sru		 * a routing process they will come back.
47174299Sru		 */
47276469Sru		in_ifadown(&ia->ia_ifa, 1);
473126264Smlaier		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
47487124Sbrian		error = 0;
4751541Srgrimes		break;
4761541Srgrimes
4771541Srgrimes	default:
4781541Srgrimes		if (ifp == 0 || ifp->if_ioctl == 0)
4791541Srgrimes			return (EOPNOTSUPP);
480146883Siedowse		IFF_LOCKGIANT(ifp);
481146883Siedowse		error = (*ifp->if_ioctl)(ifp, cmd, data);
482146883Siedowse		IFF_UNLOCKGIANT(ifp);
483146883Siedowse		return (error);
4841541Srgrimes	}
48587124Sbrian
48687124Sbrian	/*
48787124Sbrian	 * Protect from ipintr() traversing address list while we're modifying
48887124Sbrian	 * it.
48987124Sbrian	 */
49087124Sbrian	s = splnet();
49187124Sbrian	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
49287124Sbrian	TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
493168032Sbms	if (ia->ia_addr.sin_family == AF_INET) {
494154777Sandre		LIST_REMOVE(ia, ia_hash);
495168032Sbms		/*
496168032Sbms		 * If this is the last IPv4 address configured on this
497168032Sbms		 * interface, leave the all-hosts group.
498168032Sbms		 * XXX: This is quite ugly because of locking and structure.
499168032Sbms		 */
500168032Sbms		oia = NULL;
501168032Sbms		IFP_TO_IA(ifp, oia);
502168032Sbms		if (oia == NULL) {
503168032Sbms			struct in_multi *inm;
504168032Sbms
505168032Sbms			IFF_LOCKGIANT(ifp);
506168032Sbms			IN_MULTI_LOCK();
507168032Sbms			IN_LOOKUP_MULTI(allhosts_addr, ifp, inm);
508168032Sbms			if (inm != NULL)
509168032Sbms				in_delmulti_locked(inm);
510168032Sbms			IN_MULTI_UNLOCK();
511168032Sbms			IFF_UNLOCKGIANT(ifp);
512168032Sbms		}
513168032Sbms	}
51487124Sbrian	IFAFREE(&ia->ia_ifa);
51587124Sbrian	splx(s);
51687124Sbrian
51787124Sbrian	return (error);
5181541Srgrimes}
5191541Srgrimes
5201541Srgrimes/*
52155009Sshin * SIOC[GAD]LIFADDR.
52255009Sshin *	SIOCGLIFADDR: get first address. (?!?)
52355009Sshin *	SIOCGLIFADDR with IFLR_PREFIX:
52455009Sshin *		get first address that matches the specified prefix.
52555009Sshin *	SIOCALIFADDR: add the specified address.
52655009Sshin *	SIOCALIFADDR with IFLR_PREFIX:
52755009Sshin *		EINVAL since we can't deduce hostid part of the address.
52855009Sshin *	SIOCDLIFADDR: delete the specified address.
52955009Sshin *	SIOCDLIFADDR with IFLR_PREFIX:
53055009Sshin *		delete the first address that matches the specified prefix.
53155009Sshin * return values:
53255009Sshin *	EINVAL on invalid parameters
53355009Sshin *	EADDRNOTAVAIL on prefix match failed/specified address not found
53455009Sshin *	other values may be returned from in_ioctl()
53555009Sshin */
53655009Sshinstatic int
537169454Srwatsonin_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
538169454Srwatson    struct ifnet *ifp, struct thread *td)
53955009Sshin{
54055009Sshin	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
54155009Sshin	struct ifaddr *ifa;
54255009Sshin
54355009Sshin	/* sanity checks */
54455009Sshin	if (!data || !ifp) {
54555009Sshin		panic("invalid argument to in_lifaddr_ioctl");
54655009Sshin		/*NOTRECHED*/
54755009Sshin	}
54855009Sshin
54955009Sshin	switch (cmd) {
55055009Sshin	case SIOCGLIFADDR:
55155009Sshin		/* address must be specified on GET with IFLR_PREFIX */
55255009Sshin		if ((iflr->flags & IFLR_PREFIX) == 0)
55355009Sshin			break;
55455009Sshin		/*FALLTHROUGH*/
55555009Sshin	case SIOCALIFADDR:
55655009Sshin	case SIOCDLIFADDR:
55755009Sshin		/* address must be specified on ADD and DELETE */
55855917Sshin		if (iflr->addr.ss_family != AF_INET)
55955009Sshin			return EINVAL;
56055917Sshin		if (iflr->addr.ss_len != sizeof(struct sockaddr_in))
56155009Sshin			return EINVAL;
56255009Sshin		/* XXX need improvement */
56355917Sshin		if (iflr->dstaddr.ss_family
56455917Sshin		 && iflr->dstaddr.ss_family != AF_INET)
56555009Sshin			return EINVAL;
56655917Sshin		if (iflr->dstaddr.ss_family
56755917Sshin		 && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in))
56855009Sshin			return EINVAL;
56955009Sshin		break;
57055009Sshin	default: /*shouldn't happen*/
57155009Sshin		return EOPNOTSUPP;
57255009Sshin	}
57355009Sshin	if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
57455009Sshin		return EINVAL;
57555009Sshin
57655009Sshin	switch (cmd) {
57755009Sshin	case SIOCALIFADDR:
57855009Sshin	    {
57955009Sshin		struct in_aliasreq ifra;
58055009Sshin
58155009Sshin		if (iflr->flags & IFLR_PREFIX)
58255009Sshin			return EINVAL;
58355009Sshin
58455009Sshin		/* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
58555009Sshin		bzero(&ifra, sizeof(ifra));
58655009Sshin		bcopy(iflr->iflr_name, ifra.ifra_name,
58755009Sshin			sizeof(ifra.ifra_name));
58855009Sshin
58955917Sshin		bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
59055009Sshin
59155917Sshin		if (iflr->dstaddr.ss_family) {	/*XXX*/
59255009Sshin			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
59355917Sshin				iflr->dstaddr.ss_len);
59455009Sshin		}
59555009Sshin
59655009Sshin		ifra.ifra_mask.sin_family = AF_INET;
59755009Sshin		ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
59855009Sshin		in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
59955009Sshin
60083366Sjulian		return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td);
60155009Sshin	    }
60255009Sshin	case SIOCGLIFADDR:
60355009Sshin	case SIOCDLIFADDR:
60455009Sshin	    {
60555009Sshin		struct in_ifaddr *ia;
60655009Sshin		struct in_addr mask, candidate, match;
60755009Sshin		struct sockaddr_in *sin;
60855009Sshin
60955009Sshin		bzero(&mask, sizeof(mask));
610170855Smjacob		bzero(&match, sizeof(match));
61155009Sshin		if (iflr->flags & IFLR_PREFIX) {
61255009Sshin			/* lookup a prefix rather than address. */
61355009Sshin			in_len2mask(&mask, iflr->prefixlen);
61455009Sshin
61555009Sshin			sin = (struct sockaddr_in *)&iflr->addr;
61655009Sshin			match.s_addr = sin->sin_addr.s_addr;
61755009Sshin			match.s_addr &= mask.s_addr;
61855009Sshin
61955009Sshin			/* if you set extra bits, that's wrong */
62055009Sshin			if (match.s_addr != sin->sin_addr.s_addr)
62155009Sshin				return EINVAL;
62255009Sshin
62355009Sshin		} else {
624170855Smjacob			/* on getting an address, take the 1st match */
625170855Smjacob			/* on deleting an address, do exact match */
626170855Smjacob			if (cmd != SIOCGLIFADDR) {
62755009Sshin				in_len2mask(&mask, 32);
62855009Sshin				sin = (struct sockaddr_in *)&iflr->addr;
62955009Sshin				match.s_addr = sin->sin_addr.s_addr;
63055009Sshin			}
63155009Sshin		}
63255009Sshin
63355009Sshin		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)	{
63455009Sshin			if (ifa->ifa_addr->sa_family != AF_INET6)
63555009Sshin				continue;
636170855Smjacob			if (match.s_addr == 0)
63755009Sshin				break;
63855009Sshin			candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
63955009Sshin			candidate.s_addr &= mask.s_addr;
64055009Sshin			if (candidate.s_addr == match.s_addr)
64155009Sshin				break;
64255009Sshin		}
64355009Sshin		if (!ifa)
64455009Sshin			return EADDRNOTAVAIL;
64555009Sshin		ia = (struct in_ifaddr *)ifa;
64655009Sshin
64755009Sshin		if (cmd == SIOCGLIFADDR) {
64855009Sshin			/* fill in the if_laddrreq structure */
64955009Sshin			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
65055009Sshin
65155009Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
65255009Sshin				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
65355009Sshin					ia->ia_dstaddr.sin_len);
65455009Sshin			} else
65555009Sshin				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
65655009Sshin
65755009Sshin			iflr->prefixlen =
65855009Sshin				in_mask2len(&ia->ia_sockmask.sin_addr);
65955009Sshin
66055009Sshin			iflr->flags = 0;	/*XXX*/
66155009Sshin
66255009Sshin			return 0;
66355009Sshin		} else {
66455009Sshin			struct in_aliasreq ifra;
66555009Sshin
66655009Sshin			/* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
66755009Sshin			bzero(&ifra, sizeof(ifra));
66855009Sshin			bcopy(iflr->iflr_name, ifra.ifra_name,
66955009Sshin				sizeof(ifra.ifra_name));
67055009Sshin
67155009Sshin			bcopy(&ia->ia_addr, &ifra.ifra_addr,
67255009Sshin				ia->ia_addr.sin_len);
67355009Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
67455009Sshin				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
67555009Sshin					ia->ia_dstaddr.sin_len);
67655009Sshin			}
67755009Sshin			bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
67855009Sshin				ia->ia_sockmask.sin_len);
67955009Sshin
68055009Sshin			return in_control(so, SIOCDIFADDR, (caddr_t)&ifra,
68183366Sjulian					  ifp, td);
68255009Sshin		}
68355009Sshin	    }
68455009Sshin	}
68555009Sshin
68655009Sshin	return EOPNOTSUPP;	/*just for safety*/
68755009Sshin}
68855009Sshin
68955009Sshin/*
6901541Srgrimes * Delete any existing route for an interface.
6911541Srgrimes */
69222672Swollmanvoid
693169454Srwatsonin_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
6941541Srgrimes{
695169454Srwatson
696137628Smlaier	in_scrubprefix(ia);
6971541Srgrimes}
6981541Srgrimes
6991541Srgrimes/*
7001541Srgrimes * Initialize an interface's internet address
7011541Srgrimes * and routing table entry.
7021541Srgrimes */
70312296Sphkstatic int
704169454Srwatsonin_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
705169454Srwatson    int scrub)
7061541Srgrimes{
7071541Srgrimes	register u_long i = ntohl(sin->sin_addr.s_addr);
7081541Srgrimes	struct sockaddr_in oldaddr;
70994326Sbrian	int s = splimp(), flags = RTF_UP, error = 0;
7101541Srgrimes
7111541Srgrimes	oldaddr = ia->ia_addr;
712105748Ssuz	if (oldaddr.sin_family == AF_INET)
713105748Ssuz		LIST_REMOVE(ia, ia_hash);
7141541Srgrimes	ia->ia_addr = *sin;
715105748Ssuz	if (ia->ia_addr.sin_family == AF_INET)
716105748Ssuz		LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
717105748Ssuz		    ia, ia_hash);
7181541Srgrimes	/*
7191541Srgrimes	 * Give the interface a chance to initialize
7201541Srgrimes	 * if this is its first address,
7211541Srgrimes	 * and to validate the address if necessary.
7221541Srgrimes	 */
723146883Siedowse	if (ifp->if_ioctl) {
724146883Siedowse		IFF_LOCKGIANT(ifp);
725146883Siedowse		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
726146883Siedowse		IFF_UNLOCKGIANT(ifp);
727146883Siedowse		if (error) {
728146883Siedowse			splx(s);
729146883Siedowse			/* LIST_REMOVE(ia, ia_hash) is done in in_control */
730146883Siedowse			ia->ia_addr = oldaddr;
731146883Siedowse			if (ia->ia_addr.sin_family == AF_INET)
732146883Siedowse				LIST_INSERT_HEAD(INADDR_HASH(
733146883Siedowse				    ia->ia_addr.sin_addr.s_addr), ia, ia_hash);
734146883Siedowse			return (error);
735146883Siedowse		}
7361541Srgrimes	}
7371541Srgrimes	splx(s);
7381541Srgrimes	if (scrub) {
7391541Srgrimes		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
7401541Srgrimes		in_ifscrub(ifp, ia);
7411541Srgrimes		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
7421541Srgrimes	}
7431541Srgrimes	if (IN_CLASSA(i))
7441541Srgrimes		ia->ia_netmask = IN_CLASSA_NET;
7451541Srgrimes	else if (IN_CLASSB(i))
7461541Srgrimes		ia->ia_netmask = IN_CLASSB_NET;
7471541Srgrimes	else
7481541Srgrimes		ia->ia_netmask = IN_CLASSC_NET;
7491541Srgrimes	/*
7501541Srgrimes	 * The subnet mask usually includes at least the standard network part,
7511541Srgrimes	 * but may may be smaller in the case of supernetting.
7521541Srgrimes	 * If it is set, we believe it.
7531541Srgrimes	 */
7541541Srgrimes	if (ia->ia_subnetmask == 0) {
7551541Srgrimes		ia->ia_subnetmask = ia->ia_netmask;
7561541Srgrimes		ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
7571541Srgrimes	} else
7581541Srgrimes		ia->ia_netmask &= ia->ia_subnetmask;
7591541Srgrimes	ia->ia_net = i & ia->ia_netmask;
7601541Srgrimes	ia->ia_subnet = i & ia->ia_subnetmask;
7611541Srgrimes	in_socktrim(&ia->ia_sockmask);
762143868Sglebius#ifdef DEV_CARP
7631541Srgrimes	/*
764143868Sglebius	 * XXX: carp(4) does not have interface route
765143868Sglebius	 */
766143868Sglebius	if (ifp->if_type == IFT_CARP)
767143868Sglebius		return (0);
768143868Sglebius#endif
769143868Sglebius	/*
7701541Srgrimes	 * Add route for the network.
7711541Srgrimes	 */
7721541Srgrimes	ia->ia_ifa.ifa_metric = ifp->if_metric;
7731541Srgrimes	if (ifp->if_flags & IFF_BROADCAST) {
7741541Srgrimes		ia->ia_broadaddr.sin_addr.s_addr =
7751541Srgrimes			htonl(ia->ia_subnet | ~ia->ia_subnetmask);
7761541Srgrimes		ia->ia_netbroadcast.s_addr =
7771541Srgrimes			htonl(ia->ia_net | ~ ia->ia_netmask);
7781541Srgrimes	} else if (ifp->if_flags & IFF_LOOPBACK) {
779137833Smlaier		ia->ia_dstaddr = ia->ia_addr;
7801541Srgrimes		flags |= RTF_HOST;
7811541Srgrimes	} else if (ifp->if_flags & IFF_POINTOPOINT) {
7821541Srgrimes		if (ia->ia_dstaddr.sin_family != AF_INET)
7831541Srgrimes			return (0);
7841541Srgrimes		flags |= RTF_HOST;
7851541Srgrimes	}
786137628Smlaier	if ((error = in_addprefix(ia, flags)) != 0)
787137628Smlaier		return (error);
78894326Sbrian
7891541Srgrimes	return (error);
7901541Srgrimes}
7911541Srgrimes
792137628Smlaier#define rtinitflags(x) \
793137628Smlaier	((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
794137628Smlaier	    ? RTF_HOST : 0)
795137628Smlaier/*
796170855Smjacob * Check if we have a route for the given prefix already or add one accordingly.
797137628Smlaier */
798137628Smlaierstatic int
799169454Srwatsonin_addprefix(struct in_ifaddr *target, int flags)
800137628Smlaier{
801137628Smlaier	struct in_ifaddr *ia;
802151555Sglebius	struct in_addr prefix, mask, p, m;
803137628Smlaier	int error;
8041541Srgrimes
805170855Smjacob	if ((flags & RTF_HOST) != 0) {
806137628Smlaier		prefix = target->ia_dstaddr.sin_addr;
807170855Smjacob		mask.s_addr = 0;
808170855Smjacob	} else {
809137628Smlaier		prefix = target->ia_addr.sin_addr;
810137628Smlaier		mask = target->ia_sockmask.sin_addr;
811137628Smlaier		prefix.s_addr &= mask.s_addr;
812137628Smlaier	}
813137628Smlaier
814137628Smlaier	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
815151555Sglebius		if (rtinitflags(ia)) {
816137628Smlaier			p = ia->ia_addr.sin_addr;
817151555Sglebius
818151555Sglebius			if (prefix.s_addr != p.s_addr)
819151555Sglebius				continue;
820151555Sglebius		} else {
821151555Sglebius			p = ia->ia_addr.sin_addr;
822151555Sglebius			m = ia->ia_sockmask.sin_addr;
823151555Sglebius			p.s_addr &= m.s_addr;
824151555Sglebius
825151555Sglebius			if (prefix.s_addr != p.s_addr ||
826151555Sglebius			    mask.s_addr != m.s_addr)
827151555Sglebius				continue;
828137628Smlaier		}
829137628Smlaier
830137628Smlaier		/*
831137628Smlaier		 * If we got a matching prefix route inserted by other
832137628Smlaier		 * interface address, we are done here.
833137628Smlaier		 */
834149221Sglebius		if (ia->ia_flags & IFA_ROUTE) {
835149221Sglebius			if (sameprefixcarponly &&
836149221Sglebius			    target->ia_ifp->if_type != IFT_CARP &&
837149221Sglebius			    ia->ia_ifp->if_type != IFT_CARP)
838149221Sglebius				return (EEXIST);
839149221Sglebius			else
840149221Sglebius				return (0);
841149221Sglebius		}
842137628Smlaier	}
843137628Smlaier
844137628Smlaier	/*
845137628Smlaier	 * No-one seem to have this prefix route, so we try to insert it.
846137628Smlaier	 */
847137628Smlaier	error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
848137628Smlaier	if (!error)
849137628Smlaier		target->ia_flags |= IFA_ROUTE;
850137628Smlaier	return error;
851137628Smlaier}
852137628Smlaier
8531541Srgrimes/*
854137628Smlaier * If there is no other address in the system that can serve a route to the
855137628Smlaier * same prefix, remove the route.  Hand over the route to the new address
856137628Smlaier * otherwise.
857137628Smlaier */
858137628Smlaierstatic int
859169454Srwatsonin_scrubprefix(struct in_ifaddr *target)
860137628Smlaier{
861137628Smlaier	struct in_ifaddr *ia;
862137628Smlaier	struct in_addr prefix, mask, p;
863137628Smlaier	int error;
864137628Smlaier
865137628Smlaier	if ((target->ia_flags & IFA_ROUTE) == 0)
866137628Smlaier		return 0;
867137628Smlaier
868137628Smlaier	if (rtinitflags(target))
869137628Smlaier		prefix = target->ia_dstaddr.sin_addr;
870137628Smlaier	else {
871137628Smlaier		prefix = target->ia_addr.sin_addr;
872137628Smlaier		mask = target->ia_sockmask.sin_addr;
873137628Smlaier		prefix.s_addr &= mask.s_addr;
874137628Smlaier	}
875137628Smlaier
876137628Smlaier	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
877137628Smlaier		if (rtinitflags(ia))
878137628Smlaier			p = ia->ia_dstaddr.sin_addr;
879137628Smlaier		else {
880137628Smlaier			p = ia->ia_addr.sin_addr;
881137628Smlaier			p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
882137628Smlaier		}
883137628Smlaier
884137628Smlaier		if (prefix.s_addr != p.s_addr)
885137628Smlaier			continue;
886137628Smlaier
887137628Smlaier		/*
888137628Smlaier		 * If we got a matching prefix address, move IFA_ROUTE and
889137628Smlaier		 * the route itself to it.  Make sure that routing daemons
890137628Smlaier		 * get a heads-up.
891143868Sglebius		 *
892143868Sglebius		 * XXX: a special case for carp(4) interface
893137628Smlaier		 */
894143868Sglebius		if ((ia->ia_flags & IFA_ROUTE) == 0
895143868Sglebius#ifdef DEV_CARP
896143868Sglebius		    && (ia->ia_ifp->if_type != IFT_CARP)
897143868Sglebius#endif
898143868Sglebius							) {
899137628Smlaier			rtinit(&(target->ia_ifa), (int)RTM_DELETE,
900137628Smlaier			    rtinitflags(target));
901137628Smlaier			target->ia_flags &= ~IFA_ROUTE;
902137628Smlaier
903137628Smlaier			error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
904137628Smlaier			    rtinitflags(ia) | RTF_UP);
905137628Smlaier			if (error == 0)
906137628Smlaier				ia->ia_flags |= IFA_ROUTE;
907137628Smlaier			return error;
908137628Smlaier		}
909137628Smlaier	}
910137628Smlaier
911137628Smlaier	/*
912137628Smlaier	 * As no-one seem to have this prefix, we can remove the route.
913137628Smlaier	 */
914137628Smlaier	rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
915137628Smlaier	target->ia_flags &= ~IFA_ROUTE;
916137628Smlaier	return 0;
917137628Smlaier}
918137628Smlaier
919137628Smlaier#undef rtinitflags
920137628Smlaier
921137628Smlaier/*
9221541Srgrimes * Return 1 if the address might be a local broadcast address.
9231541Srgrimes */
9241549Srgrimesint
925169454Srwatsonin_broadcast(struct in_addr in, struct ifnet *ifp)
9261541Srgrimes{
9271541Srgrimes	register struct ifaddr *ifa;
9281541Srgrimes	u_long t;
9291541Srgrimes
9301541Srgrimes	if (in.s_addr == INADDR_BROADCAST ||
9311541Srgrimes	    in.s_addr == INADDR_ANY)
9321541Srgrimes		return 1;
9331541Srgrimes	if ((ifp->if_flags & IFF_BROADCAST) == 0)
9341541Srgrimes		return 0;
9351541Srgrimes	t = ntohl(in.s_addr);
9361541Srgrimes	/*
9371541Srgrimes	 * Look through the list of addresses for a match
9381541Srgrimes	 * with a broadcast address.
9391541Srgrimes	 */
9401541Srgrimes#define ia ((struct in_ifaddr *)ifa)
94174362Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
9421541Srgrimes		if (ifa->ifa_addr->sa_family == AF_INET &&
9431541Srgrimes		    (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
9441541Srgrimes		     in.s_addr == ia->ia_netbroadcast.s_addr ||
9451541Srgrimes		     /*
9461541Srgrimes		      * Check for old-style (host 0) broadcast.
9471541Srgrimes		      */
94813351Sguido		     t == ia->ia_subnet || t == ia->ia_net) &&
94913351Sguido		     /*
95013351Sguido		      * Check for an all one subnetmask. These
95113351Sguido		      * only exist when an interface gets a secondary
95213351Sguido		      * address.
95313351Sguido		      */
95413351Sguido		     ia->ia_subnetmask != (u_long)0xffffffff)
9551541Srgrimes			    return 1;
9561541Srgrimes	return (0);
9571541Srgrimes#undef ia
9581541Srgrimes}
959167729Sbms
9601541Srgrimes/*
961167729Sbms * Delete all IPv4 multicast address records, and associated link-layer
962167729Sbms * multicast address records, associated with ifp.
963162718Sbms */
964167729Sbmsstatic void
965167729Sbmsin_purgemaddrs(struct ifnet *ifp)
966162718Sbms{
967162718Sbms	struct in_multi *inm;
968162718Sbms	struct in_multi *oinm;
969162718Sbms
970168032Sbms#ifdef DIAGNOSTIC
971168032Sbms	printf("%s: purging ifp %p\n", __func__, ifp);
972168032Sbms#endif
973162718Sbms	IFF_LOCKGIANT(ifp);
974162718Sbms	IN_MULTI_LOCK();
975162718Sbms	LIST_FOREACH_SAFE(inm, &in_multihead, inm_link, oinm) {
976162718Sbms		if (inm->inm_ifp == ifp)
977162718Sbms			in_delmulti_locked(inm);
978162718Sbms	}
979150853Srwatson	IN_MULTI_UNLOCK();
980150852Srwatson	IFF_UNLOCKGIANT(ifp);
9811541Srgrimes}
982150296Srwatson
983150296Srwatson/*
984150296Srwatson * On interface removal, clean up IPv4 data structures hung off of the ifnet.
985150296Srwatson */
986150296Srwatsonvoid
987169454Srwatsonin_ifdetach(struct ifnet *ifp)
988150296Srwatson{
989150296Srwatson
990150296Srwatson	in_pcbpurgeif0(&ripcbinfo, ifp);
991150296Srwatson	in_pcbpurgeif0(&udbinfo, ifp);
992167729Sbms	in_purgemaddrs(ifp);
993150296Srwatson}
994