in.c revision 137668
11541Srgrimes/*
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 137668 2004-11-13 17:05:40Z mlaier $
321541Srgrimes */
331541Srgrimes
341541Srgrimes#include <sys/param.h>
351549Srgrimes#include <sys/systm.h>
3624204Sbde#include <sys/sockio.h>
371541Srgrimes#include <sys/malloc.h>
381541Srgrimes#include <sys/socket.h>
3912704Sphk#include <sys/kernel.h>
4012704Sphk#include <sys/sysctl.h>
411541Srgrimes
421541Srgrimes#include <net/if.h>
4355009Sshin#include <net/if_types.h>
441541Srgrimes#include <net/route.h>
451541Srgrimes
461541Srgrimes#include <netinet/in.h>
471541Srgrimes#include <netinet/in_var.h>
4881127Sume#include <netinet/in_pcb.h>
491541Srgrimes
506363Sphk#include <netinet/igmp_var.h>
516363Sphk
5230354Sphkstatic MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
5330309Sphk
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);
641541Srgrimes
6518193Swollmanstatic int subnetsarelocal = 0;
66133874SrwatsonSYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
67123998Sru	&subnetsarelocal, 0, "Treat all subnets as directly connected");
6821666Swollman
6921666Swollmanstruct in_multihead in_multihead; /* XXX BSS initialization */
7021666Swollman
7181127Sumeextern struct inpcbinfo ripcbinfo;
7281127Sumeextern struct inpcbinfo udbinfo;
7381127Sume
741541Srgrimes/*
751541Srgrimes * Return 1 if an internet address is for a ``local'' host
761541Srgrimes * (one to which we have a connection).  If subnetsarelocal
771541Srgrimes * is true, this includes other subnets of the local net.
781541Srgrimes * Otherwise, it includes only the directly-connected (sub)nets.
791541Srgrimes */
801549Srgrimesint
811541Srgrimesin_localaddr(in)
821541Srgrimes	struct in_addr in;
831541Srgrimes{
841541Srgrimes	register u_long i = ntohl(in.s_addr);
851541Srgrimes	register struct in_ifaddr *ia;
861541Srgrimes
871541Srgrimes	if (subnetsarelocal) {
8874362Sphk		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
891541Srgrimes			if ((i & ia->ia_netmask) == ia->ia_net)
901541Srgrimes				return (1);
911541Srgrimes	} else {
9272012Sphk		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
931541Srgrimes			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
941541Srgrimes				return (1);
951541Srgrimes	}
961541Srgrimes	return (0);
971541Srgrimes}
981541Srgrimes
991541Srgrimes/*
100133486Sandre * Return 1 if an internet address is for the local host and configured
101133486Sandre * on one of its interfaces.
102133486Sandre */
103133486Sandreint
104133486Sandrein_localip(in)
105133486Sandre	struct in_addr in;
106133486Sandre{
107133486Sandre	struct in_ifaddr *ia;
108133486Sandre
109133486Sandre	LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) {
110133486Sandre		if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr)
111133486Sandre			return 1;
112133486Sandre	}
113133486Sandre	return 0;
114133486Sandre}
115133486Sandre
116133486Sandre/*
1171541Srgrimes * Determine whether an IP address is in a reserved set of addresses
1181541Srgrimes * that may not be forwarded, or whether datagrams to that destination
1191541Srgrimes * may be forwarded.
1201541Srgrimes */
1211549Srgrimesint
1221541Srgrimesin_canforward(in)
1231541Srgrimes	struct in_addr in;
1241541Srgrimes{
1251541Srgrimes	register u_long i = ntohl(in.s_addr);
1261541Srgrimes	register u_long net;
1271541Srgrimes
1281541Srgrimes	if (IN_EXPERIMENTAL(i) || IN_MULTICAST(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
1421541Srgrimesin_socktrim(ap)
1431541Srgrimesstruct sockaddr_in *ap;
1441541Srgrimes{
1451541Srgrimes    register char *cplim = (char *) &ap->sin_addr;
1461541Srgrimes    register char *cp = (char *) (&ap->sin_addr + 1);
1471541Srgrimes
1481541Srgrimes    ap->sin_len = 0;
1494127Swollman    while (--cp >= cplim)
150133874Srwatson	if (*cp) {
1511541Srgrimes	    (ap)->sin_len = cp - (char *) (ap) + 1;
1521541Srgrimes	    break;
1531541Srgrimes	}
1541541Srgrimes}
1551541Srgrimes
15655009Sshinstatic int
15755009Sshinin_mask2len(mask)
15855009Sshin	struct in_addr *mask;
15955009Sshin{
16055009Sshin	int x, y;
16155009Sshin	u_char *p;
16255009Sshin
16355009Sshin	p = (u_char *)mask;
16455009Sshin	for (x = 0; x < sizeof(*mask); x++) {
16555009Sshin		if (p[x] != 0xff)
16655009Sshin			break;
16755009Sshin	}
16855009Sshin	y = 0;
16955009Sshin	if (x < sizeof(*mask)) {
17055009Sshin		for (y = 0; y < 8; y++) {
17155009Sshin			if ((p[x] & (0x80 >> y)) == 0)
17255009Sshin				break;
17355009Sshin		}
17455009Sshin	}
17555009Sshin	return x * 8 + y;
17655009Sshin}
17755009Sshin
17855009Sshinstatic void
17955009Sshinin_len2mask(mask, len)
18055009Sshin	struct in_addr *mask;
18155009Sshin	int len;
18255009Sshin{
18355009Sshin	int i;
18455009Sshin	u_char *p;
18555009Sshin
18655009Sshin	p = (u_char *)mask;
18755009Sshin	bzero(mask, sizeof(*mask));
18855009Sshin	for (i = 0; i < len / 8; i++)
18955009Sshin		p[i] = 0xff;
19055009Sshin	if (len % 8)
19155009Sshin		p[i] = (0xff00 >> (len % 8)) & 0xff;
19255009Sshin}
19355009Sshin
1941541Srgrimes/*
1951541Srgrimes * Generic internet control operations (ioctl's).
1961541Srgrimes * Ifp is 0 if not an interface-specific ioctl.
1971541Srgrimes */
1981541Srgrimes/* ARGSUSED */
1991549Srgrimesint
20083366Sjulianin_control(so, cmd, data, ifp, td)
2011541Srgrimes	struct socket *so;
20236735Sdfr	u_long cmd;
2031541Srgrimes	caddr_t data;
2041541Srgrimes	register struct ifnet *ifp;
20583366Sjulian	struct thread *td;
2061541Srgrimes{
2071541Srgrimes	register struct ifreq *ifr = (struct ifreq *)data;
20814632Sfenner	register struct in_ifaddr *ia = 0, *iap;
2091541Srgrimes	register struct ifaddr *ifa;
21084102Sjlemon	struct in_addr dst;
2111541Srgrimes	struct in_ifaddr *oia;
2121541Srgrimes	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
2131541Srgrimes	struct sockaddr_in oldaddr;
21487124Sbrian	int error, hostIsNew, iaIsNew, maskIsNew, s;
2151541Srgrimes
21687124Sbrian	iaIsNew = 0;
21787124Sbrian
21855009Sshin	switch (cmd) {
21955009Sshin	case SIOCALIFADDR:
22055009Sshin	case SIOCDLIFADDR:
22193593Sjhb		if (td && (error = suser(td)) != 0)
22255009Sshin			return error;
22355009Sshin		/*fall through*/
22455009Sshin	case SIOCGLIFADDR:
22555009Sshin		if (!ifp)
22655009Sshin			return EINVAL;
22783366Sjulian		return in_lifaddr_ioctl(so, cmd, data, ifp, td);
22855009Sshin	}
22955009Sshin
2301541Srgrimes	/*
2311541Srgrimes	 * Find address for this interface, if it exists.
23214632Sfenner	 *
23314632Sfenner	 * If an alias address was specified, find that one instead of
23484102Sjlemon	 * the first one on the interface, if possible.
2351541Srgrimes	 */
23684102Sjlemon	if (ifp) {
23784102Sjlemon		dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
23884102Sjlemon		LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash)
23984102Sjlemon			if (iap->ia_ifp == ifp &&
24084102Sjlemon			    iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
24184102Sjlemon				ia = iap;
24284102Sjlemon				break;
24384102Sjlemon			}
24484102Sjlemon		if (ia == NULL)
24584102Sjlemon			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
24684102Sjlemon				iap = ifatoia(ifa);
24784102Sjlemon				if (iap->ia_addr.sin_family == AF_INET) {
24814632Sfenner					ia = iap;
24914632Sfenner					break;
25014632Sfenner				}
25114632Sfenner			}
25284102Sjlemon	}
2531541Srgrimes
2541541Srgrimes	switch (cmd) {
2551541Srgrimes
2561541Srgrimes	case SIOCAIFADDR:
2571541Srgrimes	case SIOCDIFADDR:
25841575Seivind		if (ifp == 0)
25941575Seivind			return (EADDRNOTAVAIL);
2608071Swollman		if (ifra->ifra_addr.sin_family == AF_INET) {
26171999Sphk			for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
2628071Swollman				if (ia->ia_ifp == ifp  &&
2638071Swollman				    ia->ia_addr.sin_addr.s_addr ==
2648071Swollman				    ifra->ifra_addr.sin_addr.s_addr)
2658071Swollman					break;
2668071Swollman			}
2678876Srgrimes			if ((ifp->if_flags & IFF_POINTOPOINT)
2688071Swollman			    && (cmd == SIOCAIFADDR)
2698071Swollman			    && (ifra->ifra_dstaddr.sin_addr.s_addr
2708071Swollman				== INADDR_ANY)) {
2719563Swollman				return EDESTADDRREQ;
2728071Swollman			}
2731541Srgrimes		}
2741541Srgrimes		if (cmd == SIOCDIFADDR && ia == 0)
2751541Srgrimes			return (EADDRNOTAVAIL);
2761541Srgrimes		/* FALLTHROUGH */
2771541Srgrimes	case SIOCSIFADDR:
2781541Srgrimes	case SIOCSIFNETMASK:
2791541Srgrimes	case SIOCSIFDSTADDR:
28093593Sjhb		if (td && (error = suser(td)) != 0)
28125201Swollman			return error;
2821541Srgrimes
2831541Srgrimes		if (ifp == 0)
28441575Seivind			return (EADDRNOTAVAIL);
2851541Srgrimes		if (ia == (struct in_ifaddr *)0) {
28620407Swollman			ia = (struct in_ifaddr *)
287111119Simp				malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
28820407Swollman			if (ia == (struct in_ifaddr *)NULL)
2891541Srgrimes				return (ENOBUFS);
29015092Sdg			/*
29115092Sdg			 * Protect from ipintr() traversing address list
29215092Sdg			 * while we're modifying it.
29315092Sdg			 */
29415092Sdg			s = splnet();
29520407Swollman			TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
296108033Shsu
29720407Swollman			ifa = &ia->ia_ifa;
298108033Shsu			IFA_LOCK_INIT(ifa);
29920407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
30020407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
30120407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
302108033Shsu			ifa->ifa_refcnt = 1;
303108033Shsu			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
304108033Shsu
3051541Srgrimes			ia->ia_sockmask.sin_len = 8;
30685740Sdes			ia->ia_sockmask.sin_family = AF_INET;
3071541Srgrimes			if (ifp->if_flags & IFF_BROADCAST) {
3081541Srgrimes				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
3091541Srgrimes				ia->ia_broadaddr.sin_family = AF_INET;
3101541Srgrimes			}
3111541Srgrimes			ia->ia_ifp = ifp;
31215092Sdg			splx(s);
31387124Sbrian			iaIsNew = 1;
3141541Srgrimes		}
3151541Srgrimes		break;
3161541Srgrimes
3171541Srgrimes	case SIOCSIFBRDADDR:
31893593Sjhb		if (td && (error = suser(td)) != 0)
31925201Swollman			return error;
3201541Srgrimes		/* FALLTHROUGH */
3211541Srgrimes
3221541Srgrimes	case SIOCGIFADDR:
3231541Srgrimes	case SIOCGIFNETMASK:
3241541Srgrimes	case SIOCGIFDSTADDR:
3251541Srgrimes	case SIOCGIFBRDADDR:
3261541Srgrimes		if (ia == (struct in_ifaddr *)0)
3271541Srgrimes			return (EADDRNOTAVAIL);
3281541Srgrimes		break;
3291541Srgrimes	}
3301541Srgrimes	switch (cmd) {
3311541Srgrimes
3321541Srgrimes	case SIOCGIFADDR:
3331541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
33487124Sbrian		return (0);
3351541Srgrimes
3361541Srgrimes	case SIOCGIFBRDADDR:
3371541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) == 0)
3381541Srgrimes			return (EINVAL);
3391541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
34087124Sbrian		return (0);
3411541Srgrimes
3421541Srgrimes	case SIOCGIFDSTADDR:
3431541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
3441541Srgrimes			return (EINVAL);
3451541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
34687124Sbrian		return (0);
3471541Srgrimes
3481541Srgrimes	case SIOCGIFNETMASK:
3491541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
35087124Sbrian		return (0);
3511541Srgrimes
3521541Srgrimes	case SIOCSIFDSTADDR:
3531541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
3541541Srgrimes			return (EINVAL);
3551541Srgrimes		oldaddr = ia->ia_dstaddr;
3561541Srgrimes		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
3571541Srgrimes		if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
3581541Srgrimes					(ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
3591541Srgrimes			ia->ia_dstaddr = oldaddr;
3601541Srgrimes			return (error);
3611541Srgrimes		}
3621541Srgrimes		if (ia->ia_flags & IFA_ROUTE) {
3631541Srgrimes			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
3641541Srgrimes			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
3651541Srgrimes			ia->ia_ifa.ifa_dstaddr =
3661541Srgrimes					(struct sockaddr *)&ia->ia_dstaddr;
3671541Srgrimes			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
3681541Srgrimes		}
36987124Sbrian		return (0);
3701541Srgrimes
3711541Srgrimes	case SIOCSIFBRDADDR:
3721541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) == 0)
3731541Srgrimes			return (EINVAL);
3741541Srgrimes		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
37587124Sbrian		return (0);
3761541Srgrimes
3771541Srgrimes	case SIOCSIFADDR:
37887124Sbrian		error = in_ifinit(ifp, ia,
37987124Sbrian		    (struct sockaddr_in *) &ifr->ifr_addr, 1);
38087124Sbrian		if (error != 0 && iaIsNew)
38187124Sbrian			break;
382126264Smlaier		if (error == 0)
383126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
38487124Sbrian		return (0);
3851541Srgrimes
3861541Srgrimes	case SIOCSIFNETMASK:
38785740Sdes		ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
38885740Sdes		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
38987124Sbrian		return (0);
3901541Srgrimes
3911541Srgrimes	case SIOCAIFADDR:
3921541Srgrimes		maskIsNew = 0;
3931541Srgrimes		hostIsNew = 1;
3941541Srgrimes		error = 0;
3951541Srgrimes		if (ia->ia_addr.sin_family == AF_INET) {
3961541Srgrimes			if (ifra->ifra_addr.sin_len == 0) {
3971541Srgrimes				ifra->ifra_addr = ia->ia_addr;
3981541Srgrimes				hostIsNew = 0;
3991541Srgrimes			} else if (ifra->ifra_addr.sin_addr.s_addr ==
4001541Srgrimes					       ia->ia_addr.sin_addr.s_addr)
4011541Srgrimes				hostIsNew = 0;
4021541Srgrimes		}
4031541Srgrimes		if (ifra->ifra_mask.sin_len) {
4041541Srgrimes			in_ifscrub(ifp, ia);
4051541Srgrimes			ia->ia_sockmask = ifra->ifra_mask;
40685740Sdes			ia->ia_sockmask.sin_family = AF_INET;
4071541Srgrimes			ia->ia_subnetmask =
4081541Srgrimes			     ntohl(ia->ia_sockmask.sin_addr.s_addr);
4091541Srgrimes			maskIsNew = 1;
4101541Srgrimes		}
4111541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) &&
4121541Srgrimes		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
4131541Srgrimes			in_ifscrub(ifp, ia);
4141541Srgrimes			ia->ia_dstaddr = ifra->ifra_dstaddr;
4151541Srgrimes			maskIsNew  = 1; /* We lie; but the effect's the same */
4161541Srgrimes		}
4171541Srgrimes		if (ifra->ifra_addr.sin_family == AF_INET &&
4181541Srgrimes		    (hostIsNew || maskIsNew))
4191541Srgrimes			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
42087124Sbrian		if (error != 0 && iaIsNew)
42187124Sbrian			break;
42287124Sbrian
4231541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) &&
4241541Srgrimes		    (ifra->ifra_broadaddr.sin_family == AF_INET))
4251541Srgrimes			ia->ia_broadaddr = ifra->ifra_broadaddr;
426126264Smlaier		if (error == 0)
427126264Smlaier			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
4281541Srgrimes		return (error);
4291541Srgrimes
4301541Srgrimes	case SIOCDIFADDR:
43174299Sru		/*
43274299Sru		 * in_ifscrub kills the interface route.
43374299Sru		 */
4341541Srgrimes		in_ifscrub(ifp, ia);
43515092Sdg		/*
43674299Sru		 * in_ifadown gets rid of all the rest of
43774299Sru		 * the routes.  This is not quite the right
43874299Sru		 * thing to do, but at least if we are running
43974299Sru		 * a routing process they will come back.
44074299Sru		 */
44176469Sru		in_ifadown(&ia->ia_ifa, 1);
44281127Sume		/*
44381127Sume		 * XXX horrible hack to detect that we are being called
44481127Sume		 * from if_detach()
44581127Sume		 */
446121922Ssam		if (ifaddr_byindex(ifp->if_index) == NULL) {
44798102Shsu			in_pcbpurgeif0(&ripcbinfo, ifp);
44898102Shsu			in_pcbpurgeif0(&udbinfo, ifp);
44981127Sume		}
450126264Smlaier		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
45187124Sbrian		error = 0;
4521541Srgrimes		break;
4531541Srgrimes
4541541Srgrimes	default:
4551541Srgrimes		if (ifp == 0 || ifp->if_ioctl == 0)
4561541Srgrimes			return (EOPNOTSUPP);
4571541Srgrimes		return ((*ifp->if_ioctl)(ifp, cmd, data));
4581541Srgrimes	}
45987124Sbrian
46087124Sbrian	/*
46187124Sbrian	 * Protect from ipintr() traversing address list while we're modifying
46287124Sbrian	 * it.
46387124Sbrian	 */
46487124Sbrian	s = splnet();
46587124Sbrian	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
46687124Sbrian	TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
46787124Sbrian	LIST_REMOVE(ia, ia_hash);
46887124Sbrian	IFAFREE(&ia->ia_ifa);
46987124Sbrian	splx(s);
47087124Sbrian
47187124Sbrian	return (error);
4721541Srgrimes}
4731541Srgrimes
4741541Srgrimes/*
47555009Sshin * SIOC[GAD]LIFADDR.
47655009Sshin *	SIOCGLIFADDR: get first address. (?!?)
47755009Sshin *	SIOCGLIFADDR with IFLR_PREFIX:
47855009Sshin *		get first address that matches the specified prefix.
47955009Sshin *	SIOCALIFADDR: add the specified address.
48055009Sshin *	SIOCALIFADDR with IFLR_PREFIX:
48155009Sshin *		EINVAL since we can't deduce hostid part of the address.
48255009Sshin *	SIOCDLIFADDR: delete the specified address.
48355009Sshin *	SIOCDLIFADDR with IFLR_PREFIX:
48455009Sshin *		delete the first address that matches the specified prefix.
48555009Sshin * return values:
48655009Sshin *	EINVAL on invalid parameters
48755009Sshin *	EADDRNOTAVAIL on prefix match failed/specified address not found
48855009Sshin *	other values may be returned from in_ioctl()
48955009Sshin */
49055009Sshinstatic int
49183366Sjulianin_lifaddr_ioctl(so, cmd, data, ifp, td)
49255009Sshin	struct socket *so;
49355009Sshin	u_long cmd;
49455009Sshin	caddr_t	data;
49555009Sshin	struct ifnet *ifp;
49683366Sjulian	struct thread *td;
49755009Sshin{
49855009Sshin	struct if_laddrreq *iflr = (struct if_laddrreq *)data;
49955009Sshin	struct ifaddr *ifa;
50055009Sshin
50155009Sshin	/* sanity checks */
50255009Sshin	if (!data || !ifp) {
50355009Sshin		panic("invalid argument to in_lifaddr_ioctl");
50455009Sshin		/*NOTRECHED*/
50555009Sshin	}
50655009Sshin
50755009Sshin	switch (cmd) {
50855009Sshin	case SIOCGLIFADDR:
50955009Sshin		/* address must be specified on GET with IFLR_PREFIX */
51055009Sshin		if ((iflr->flags & IFLR_PREFIX) == 0)
51155009Sshin			break;
51255009Sshin		/*FALLTHROUGH*/
51355009Sshin	case SIOCALIFADDR:
51455009Sshin	case SIOCDLIFADDR:
51555009Sshin		/* address must be specified on ADD and DELETE */
51655917Sshin		if (iflr->addr.ss_family != AF_INET)
51755009Sshin			return EINVAL;
51855917Sshin		if (iflr->addr.ss_len != sizeof(struct sockaddr_in))
51955009Sshin			return EINVAL;
52055009Sshin		/* XXX need improvement */
52155917Sshin		if (iflr->dstaddr.ss_family
52255917Sshin		 && iflr->dstaddr.ss_family != AF_INET)
52355009Sshin			return EINVAL;
52455917Sshin		if (iflr->dstaddr.ss_family
52555917Sshin		 && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in))
52655009Sshin			return EINVAL;
52755009Sshin		break;
52855009Sshin	default: /*shouldn't happen*/
52955009Sshin		return EOPNOTSUPP;
53055009Sshin	}
53155009Sshin	if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
53255009Sshin		return EINVAL;
53355009Sshin
53455009Sshin	switch (cmd) {
53555009Sshin	case SIOCALIFADDR:
53655009Sshin	    {
53755009Sshin		struct in_aliasreq ifra;
53855009Sshin
53955009Sshin		if (iflr->flags & IFLR_PREFIX)
54055009Sshin			return EINVAL;
54155009Sshin
54255009Sshin		/* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
54355009Sshin		bzero(&ifra, sizeof(ifra));
54455009Sshin		bcopy(iflr->iflr_name, ifra.ifra_name,
54555009Sshin			sizeof(ifra.ifra_name));
54655009Sshin
54755917Sshin		bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
54855009Sshin
54955917Sshin		if (iflr->dstaddr.ss_family) {	/*XXX*/
55055009Sshin			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
55155917Sshin				iflr->dstaddr.ss_len);
55255009Sshin		}
55355009Sshin
55455009Sshin		ifra.ifra_mask.sin_family = AF_INET;
55555009Sshin		ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
55655009Sshin		in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
55755009Sshin
55883366Sjulian		return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td);
55955009Sshin	    }
56055009Sshin	case SIOCGLIFADDR:
56155009Sshin	case SIOCDLIFADDR:
56255009Sshin	    {
56355009Sshin		struct in_ifaddr *ia;
56455009Sshin		struct in_addr mask, candidate, match;
56555009Sshin		struct sockaddr_in *sin;
56655009Sshin		int cmp;
56755009Sshin
56855009Sshin		bzero(&mask, sizeof(mask));
56955009Sshin		if (iflr->flags & IFLR_PREFIX) {
57055009Sshin			/* lookup a prefix rather than address. */
57155009Sshin			in_len2mask(&mask, iflr->prefixlen);
57255009Sshin
57355009Sshin			sin = (struct sockaddr_in *)&iflr->addr;
57455009Sshin			match.s_addr = sin->sin_addr.s_addr;
57555009Sshin			match.s_addr &= mask.s_addr;
57655009Sshin
57755009Sshin			/* if you set extra bits, that's wrong */
57855009Sshin			if (match.s_addr != sin->sin_addr.s_addr)
57955009Sshin				return EINVAL;
58055009Sshin
58155009Sshin			cmp = 1;
58255009Sshin		} else {
58355009Sshin			if (cmd == SIOCGLIFADDR) {
58455009Sshin				/* on getting an address, take the 1st match */
58555009Sshin				cmp = 0;	/*XXX*/
58655009Sshin			} else {
58755009Sshin				/* on deleting an address, do exact match */
58855009Sshin				in_len2mask(&mask, 32);
58955009Sshin				sin = (struct sockaddr_in *)&iflr->addr;
59055009Sshin				match.s_addr = sin->sin_addr.s_addr;
59155009Sshin
59255009Sshin				cmp = 1;
59355009Sshin			}
59455009Sshin		}
59555009Sshin
59655009Sshin		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)	{
59755009Sshin			if (ifa->ifa_addr->sa_family != AF_INET6)
59855009Sshin				continue;
59955009Sshin			if (!cmp)
60055009Sshin				break;
60155009Sshin			candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
60255009Sshin			candidate.s_addr &= mask.s_addr;
60355009Sshin			if (candidate.s_addr == match.s_addr)
60455009Sshin				break;
60555009Sshin		}
60655009Sshin		if (!ifa)
60755009Sshin			return EADDRNOTAVAIL;
60855009Sshin		ia = (struct in_ifaddr *)ifa;
60955009Sshin
61055009Sshin		if (cmd == SIOCGLIFADDR) {
61155009Sshin			/* fill in the if_laddrreq structure */
61255009Sshin			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
61355009Sshin
61455009Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
61555009Sshin				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
61655009Sshin					ia->ia_dstaddr.sin_len);
61755009Sshin			} else
61855009Sshin				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
61955009Sshin
62055009Sshin			iflr->prefixlen =
62155009Sshin				in_mask2len(&ia->ia_sockmask.sin_addr);
62255009Sshin
62355009Sshin			iflr->flags = 0;	/*XXX*/
62455009Sshin
62555009Sshin			return 0;
62655009Sshin		} else {
62755009Sshin			struct in_aliasreq ifra;
62855009Sshin
62955009Sshin			/* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
63055009Sshin			bzero(&ifra, sizeof(ifra));
63155009Sshin			bcopy(iflr->iflr_name, ifra.ifra_name,
63255009Sshin				sizeof(ifra.ifra_name));
63355009Sshin
63455009Sshin			bcopy(&ia->ia_addr, &ifra.ifra_addr,
63555009Sshin				ia->ia_addr.sin_len);
63655009Sshin			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
63755009Sshin				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
63855009Sshin					ia->ia_dstaddr.sin_len);
63955009Sshin			}
64055009Sshin			bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
64155009Sshin				ia->ia_sockmask.sin_len);
64255009Sshin
64355009Sshin			return in_control(so, SIOCDIFADDR, (caddr_t)&ifra,
64483366Sjulian					  ifp, td);
64555009Sshin		}
64655009Sshin	    }
64755009Sshin	}
64855009Sshin
64955009Sshin	return EOPNOTSUPP;	/*just for safety*/
65055009Sshin}
65155009Sshin
65255009Sshin/*
6531541Srgrimes * Delete any existing route for an interface.
6541541Srgrimes */
65522672Swollmanvoid
6561541Srgrimesin_ifscrub(ifp, ia)
6571541Srgrimes	register struct ifnet *ifp;
6581541Srgrimes	register struct in_ifaddr *ia;
6591541Srgrimes{
660137628Smlaier	in_scrubprefix(ia);
6611541Srgrimes}
6621541Srgrimes
6631541Srgrimes/*
6641541Srgrimes * Initialize an interface's internet address
6651541Srgrimes * and routing table entry.
6661541Srgrimes */
66712296Sphkstatic int
6681541Srgrimesin_ifinit(ifp, ia, sin, scrub)
6691541Srgrimes	register struct ifnet *ifp;
6701541Srgrimes	register struct in_ifaddr *ia;
6711541Srgrimes	struct sockaddr_in *sin;
6721541Srgrimes	int scrub;
6731541Srgrimes{
6741541Srgrimes	register u_long i = ntohl(sin->sin_addr.s_addr);
6751541Srgrimes	struct sockaddr_in oldaddr;
67694326Sbrian	int s = splimp(), flags = RTF_UP, error = 0;
6771541Srgrimes
6781541Srgrimes	oldaddr = ia->ia_addr;
679105748Ssuz	if (oldaddr.sin_family == AF_INET)
680105748Ssuz		LIST_REMOVE(ia, ia_hash);
6811541Srgrimes	ia->ia_addr = *sin;
682105748Ssuz	if (ia->ia_addr.sin_family == AF_INET)
683105748Ssuz		LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
684105748Ssuz		    ia, ia_hash);
6851541Srgrimes	/*
6861541Srgrimes	 * Give the interface a chance to initialize
6871541Srgrimes	 * if this is its first address,
6881541Srgrimes	 * and to validate the address if necessary.
6891541Srgrimes	 */
6901541Srgrimes	if (ifp->if_ioctl &&
6911541Srgrimes	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
6921541Srgrimes		splx(s);
693105748Ssuz		/* LIST_REMOVE(ia, ia_hash) is done in in_control */
6941541Srgrimes		ia->ia_addr = oldaddr;
695105748Ssuz		if (ia->ia_addr.sin_family == AF_INET)
696105748Ssuz			LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
697105748Ssuz			    ia, ia_hash);
6981541Srgrimes		return (error);
6991541Srgrimes	}
7001541Srgrimes	splx(s);
7011541Srgrimes	if (scrub) {
7021541Srgrimes		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
7031541Srgrimes		in_ifscrub(ifp, ia);
7041541Srgrimes		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
7051541Srgrimes	}
7061541Srgrimes	if (IN_CLASSA(i))
7071541Srgrimes		ia->ia_netmask = IN_CLASSA_NET;
7081541Srgrimes	else if (IN_CLASSB(i))
7091541Srgrimes		ia->ia_netmask = IN_CLASSB_NET;
7101541Srgrimes	else
7111541Srgrimes		ia->ia_netmask = IN_CLASSC_NET;
7121541Srgrimes	/*
7131541Srgrimes	 * The subnet mask usually includes at least the standard network part,
7141541Srgrimes	 * but may may be smaller in the case of supernetting.
7151541Srgrimes	 * If it is set, we believe it.
7161541Srgrimes	 */
7171541Srgrimes	if (ia->ia_subnetmask == 0) {
7181541Srgrimes		ia->ia_subnetmask = ia->ia_netmask;
7191541Srgrimes		ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
7201541Srgrimes	} else
7211541Srgrimes		ia->ia_netmask &= ia->ia_subnetmask;
7221541Srgrimes	ia->ia_net = i & ia->ia_netmask;
7231541Srgrimes	ia->ia_subnet = i & ia->ia_subnetmask;
7241541Srgrimes	in_socktrim(&ia->ia_sockmask);
7251541Srgrimes	/*
7261541Srgrimes	 * Add route for the network.
7271541Srgrimes	 */
7281541Srgrimes	ia->ia_ifa.ifa_metric = ifp->if_metric;
7291541Srgrimes	if (ifp->if_flags & IFF_BROADCAST) {
7301541Srgrimes		ia->ia_broadaddr.sin_addr.s_addr =
7311541Srgrimes			htonl(ia->ia_subnet | ~ia->ia_subnetmask);
7321541Srgrimes		ia->ia_netbroadcast.s_addr =
7331541Srgrimes			htonl(ia->ia_net | ~ ia->ia_netmask);
7341541Srgrimes	} else if (ifp->if_flags & IFF_LOOPBACK) {
7351541Srgrimes		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
7361541Srgrimes		flags |= RTF_HOST;
7371541Srgrimes	} else if (ifp->if_flags & IFF_POINTOPOINT) {
7381541Srgrimes		if (ia->ia_dstaddr.sin_family != AF_INET)
7391541Srgrimes			return (0);
7401541Srgrimes		flags |= RTF_HOST;
7411541Srgrimes	}
742137628Smlaier	if ((error = in_addprefix(ia, flags)) != 0)
743137628Smlaier		return (error);
74494326Sbrian
7451541Srgrimes	/*
7461541Srgrimes	 * If the interface supports multicast, join the "all hosts"
7471541Srgrimes	 * multicast group on that interface.
7481541Srgrimes	 */
7491541Srgrimes	if (ifp->if_flags & IFF_MULTICAST) {
7501541Srgrimes		struct in_addr addr;
7511541Srgrimes
7521541Srgrimes		addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
7531541Srgrimes		in_addmulti(&addr, ifp);
7541541Srgrimes	}
7551541Srgrimes	return (error);
7561541Srgrimes}
7571541Srgrimes
758137628Smlaier#define rtinitflags(x) \
759137628Smlaier	((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
760137628Smlaier	    ? RTF_HOST : 0)
761137628Smlaier/*
762137628Smlaier * Check if we have a route for the given prefix already or add a one
763137628Smlaier * accordingly.
764137628Smlaier */
765137628Smlaierstatic int
766137628Smlaierin_addprefix(target, flags)
767137628Smlaier	struct in_ifaddr *target;
768137628Smlaier	int flags;
769137628Smlaier{
770137628Smlaier	struct in_ifaddr *ia;
771137628Smlaier	struct in_addr prefix, mask, p;
772137628Smlaier	int error;
7731541Srgrimes
774137628Smlaier	if ((flags & RTF_HOST) != 0)
775137628Smlaier		prefix = target->ia_dstaddr.sin_addr;
776137628Smlaier	else {
777137628Smlaier		prefix = target->ia_addr.sin_addr;
778137628Smlaier		mask = target->ia_sockmask.sin_addr;
779137628Smlaier		prefix.s_addr &= mask.s_addr;
780137628Smlaier	}
781137628Smlaier
782137628Smlaier	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
783137628Smlaier		if (rtinitflags(ia))
784137628Smlaier			p = ia->ia_dstaddr.sin_addr;
785137628Smlaier		else {
786137628Smlaier			p = ia->ia_addr.sin_addr;
787137628Smlaier			p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
788137628Smlaier		}
789137628Smlaier
790137628Smlaier		if (prefix.s_addr != p.s_addr)
791137628Smlaier			continue;
792137628Smlaier
793137628Smlaier		/*
794137628Smlaier		 * If we got a matching prefix route inserted by other
795137628Smlaier		 * interface address, we are done here.
796137628Smlaier		 */
797137628Smlaier		if (ia->ia_flags & IFA_ROUTE)
798137628Smlaier			return 0;
799137628Smlaier	}
800137628Smlaier
801137628Smlaier	/*
802137628Smlaier	 * No-one seem to have this prefix route, so we try to insert it.
803137628Smlaier	 */
804137628Smlaier	error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
805137628Smlaier	if (!error)
806137628Smlaier		target->ia_flags |= IFA_ROUTE;
807137628Smlaier	return error;
808137628Smlaier}
809137628Smlaier
8101541Srgrimes/*
811137628Smlaier * If there is no other address in the system that can serve a route to the
812137628Smlaier * same prefix, remove the route.  Hand over the route to the new address
813137628Smlaier * otherwise.
814137628Smlaier */
815137628Smlaierstatic int
816137628Smlaierin_scrubprefix(target)
817137628Smlaier	struct in_ifaddr *target;
818137628Smlaier{
819137628Smlaier	struct in_ifaddr *ia;
820137628Smlaier	struct in_addr prefix, mask, p;
821137628Smlaier	int error;
822137628Smlaier
823137628Smlaier	if ((target->ia_flags & IFA_ROUTE) == 0)
824137628Smlaier		return 0;
825137628Smlaier
826137628Smlaier	if (rtinitflags(target))
827137628Smlaier		prefix = target->ia_dstaddr.sin_addr;
828137628Smlaier	else {
829137628Smlaier		prefix = target->ia_addr.sin_addr;
830137628Smlaier		mask = target->ia_sockmask.sin_addr;
831137628Smlaier		prefix.s_addr &= mask.s_addr;
832137628Smlaier	}
833137628Smlaier
834137628Smlaier	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
835137628Smlaier		if (rtinitflags(ia))
836137628Smlaier			p = ia->ia_dstaddr.sin_addr;
837137628Smlaier		else {
838137628Smlaier			p = ia->ia_addr.sin_addr;
839137628Smlaier			p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
840137628Smlaier		}
841137628Smlaier
842137628Smlaier		if (prefix.s_addr != p.s_addr)
843137628Smlaier			continue;
844137628Smlaier
845137628Smlaier		/*
846137628Smlaier		 * If we got a matching prefix address, move IFA_ROUTE and
847137628Smlaier		 * the route itself to it.  Make sure that routing daemons
848137628Smlaier		 * get a heads-up.
849137628Smlaier		 */
850137628Smlaier		if ((ia->ia_flags & IFA_ROUTE) == 0) {
851137628Smlaier			rtinit(&(target->ia_ifa), (int)RTM_DELETE,
852137628Smlaier			    rtinitflags(target));
853137628Smlaier			target->ia_flags &= ~IFA_ROUTE;
854137628Smlaier
855137628Smlaier			error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
856137628Smlaier			    rtinitflags(ia) | RTF_UP);
857137628Smlaier			if (error == 0)
858137628Smlaier				ia->ia_flags |= IFA_ROUTE;
859137628Smlaier			return error;
860137628Smlaier		}
861137628Smlaier	}
862137628Smlaier
863137628Smlaier	/*
864137628Smlaier	 * As no-one seem to have this prefix, we can remove the route.
865137628Smlaier	 */
866137628Smlaier	rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
867137628Smlaier	target->ia_flags &= ~IFA_ROUTE;
868137628Smlaier	return 0;
869137628Smlaier}
870137628Smlaier
871137628Smlaier#undef rtinitflags
872137628Smlaier
873137628Smlaier/*
8741541Srgrimes * Return 1 if the address might be a local broadcast address.
8751541Srgrimes */
8761549Srgrimesint
8771541Srgrimesin_broadcast(in, ifp)
8781541Srgrimes	struct in_addr in;
879133874Srwatson	struct ifnet *ifp;
8801541Srgrimes{
8811541Srgrimes	register struct ifaddr *ifa;
8821541Srgrimes	u_long t;
8831541Srgrimes
8841541Srgrimes	if (in.s_addr == INADDR_BROADCAST ||
8851541Srgrimes	    in.s_addr == INADDR_ANY)
8861541Srgrimes		return 1;
8871541Srgrimes	if ((ifp->if_flags & IFF_BROADCAST) == 0)
8881541Srgrimes		return 0;
8891541Srgrimes	t = ntohl(in.s_addr);
8901541Srgrimes	/*
8911541Srgrimes	 * Look through the list of addresses for a match
8921541Srgrimes	 * with a broadcast address.
8931541Srgrimes	 */
8941541Srgrimes#define ia ((struct in_ifaddr *)ifa)
89574362Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
8961541Srgrimes		if (ifa->ifa_addr->sa_family == AF_INET &&
8971541Srgrimes		    (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
8981541Srgrimes		     in.s_addr == ia->ia_netbroadcast.s_addr ||
8991541Srgrimes		     /*
9001541Srgrimes		      * Check for old-style (host 0) broadcast.
9011541Srgrimes		      */
90213351Sguido		     t == ia->ia_subnet || t == ia->ia_net) &&
90313351Sguido		     /*
90413351Sguido		      * Check for an all one subnetmask. These
90513351Sguido		      * only exist when an interface gets a secondary
90613351Sguido		      * address.
90713351Sguido		      */
90813351Sguido		     ia->ia_subnetmask != (u_long)0xffffffff)
9091541Srgrimes			    return 1;
9101541Srgrimes	return (0);
9111541Srgrimes#undef ia
9121541Srgrimes}
9131541Srgrimes/*
9141541Srgrimes * Add an address to the list of IP multicast addresses for a given interface.
9151541Srgrimes */
9161541Srgrimesstruct in_multi *
9171541Srgrimesin_addmulti(ap, ifp)
9181541Srgrimes	register struct in_addr *ap;
9191541Srgrimes	register struct ifnet *ifp;
9201541Srgrimes{
9211541Srgrimes	register struct in_multi *inm;
92221666Swollman	int error;
92321666Swollman	struct sockaddr_in sin;
92421666Swollman	struct ifmultiaddr *ifma;
9251541Srgrimes	int s = splnet();
9261541Srgrimes
9271541Srgrimes	/*
92821666Swollman	 * Call generic routine to add membership or increment
92921666Swollman	 * refcount.  It wants addresses in the form of a sockaddr,
93021666Swollman	 * so we build one here (being careful to zero the unused bytes).
9311541Srgrimes	 */
93221666Swollman	bzero(&sin, sizeof sin);
93321666Swollman	sin.sin_family = AF_INET;
93421666Swollman	sin.sin_len = sizeof sin;
93521666Swollman	sin.sin_addr = *ap;
93621666Swollman	error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
93721666Swollman	if (error) {
93821666Swollman		splx(s);
93921666Swollman		return 0;
9401541Srgrimes	}
9417280Swollman
94221666Swollman	/*
94321666Swollman	 * If ifma->ifma_protospec is null, then if_addmulti() created
94421666Swollman	 * a new record.  Otherwise, we are done.
94521666Swollman	 */
94664853Sbde	if (ifma->ifma_protospec != 0) {
94764853Sbde		splx(s);
94821666Swollman		return ifma->ifma_protospec;
94964853Sbde	}
95021666Swollman
951111119Simp	/* XXX - if_addmulti uses M_WAITOK.  Can this really be called
95221666Swollman	   at interrupt time?  If so, need to fix if_addmulti. XXX */
95369781Sdwmalone	inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR,
95469781Sdwmalone	    M_NOWAIT | M_ZERO);
95521666Swollman	if (inm == NULL) {
95621666Swollman		splx(s);
95721666Swollman		return (NULL);
9581541Srgrimes	}
95921666Swollman
96021666Swollman	inm->inm_addr = *ap;
96121666Swollman	inm->inm_ifp = ifp;
96221666Swollman	inm->inm_ifma = ifma;
96321666Swollman	ifma->ifma_protospec = inm;
96421666Swollman	LIST_INSERT_HEAD(&in_multihead, inm, inm_link);
96521666Swollman
96621666Swollman	/*
96721666Swollman	 * Let IGMP know that we have joined a new IP multicast group.
96821666Swollman	 */
96921666Swollman	igmp_joingroup(inm);
9701541Srgrimes	splx(s);
9711541Srgrimes	return (inm);
9721541Srgrimes}
9731541Srgrimes
9741541Srgrimes/*
9751541Srgrimes * Delete a multicast address record.
9761541Srgrimes */
9771549Srgrimesvoid
9781541Srgrimesin_delmulti(inm)
9791541Srgrimes	register struct in_multi *inm;
9801541Srgrimes{
98121666Swollman	struct ifmultiaddr *ifma = inm->inm_ifma;
98245997Sluigi	struct in_multi my_inm;
9831541Srgrimes	int s = splnet();
9841541Srgrimes
98545997Sluigi	my_inm.inm_ifp = NULL ; /* don't send the leave msg */
98621666Swollman	if (ifma->ifma_refcount == 1) {
9871541Srgrimes		/*
9881541Srgrimes		 * No remaining claims to this record; let IGMP know that
9891541Srgrimes		 * we are leaving the multicast group.
99045997Sluigi		 * But do it after the if_delmulti() which might reset
99145997Sluigi		 * the interface and nuke the packet.
9921541Srgrimes		 */
99345997Sluigi		my_inm = *inm ;
99421666Swollman		ifma->ifma_protospec = 0;
99521666Swollman		LIST_REMOVE(inm, inm_link);
9961541Srgrimes		free(inm, M_IPMADDR);
9971541Srgrimes	}
99821666Swollman	/* XXX - should be separate API for when we have an ifma? */
99921666Swollman	if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
100045997Sluigi	if (my_inm.inm_ifp != NULL)
100145997Sluigi		igmp_leavegroup(&my_inm);
10021541Srgrimes	splx(s);
10031541Srgrimes}
1004