in.c revision 1541
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
331541Srgrimes *	@(#)in.c	8.2 (Berkeley) 11/15/93
341541Srgrimes */
351541Srgrimes
361541Srgrimes#include <sys/param.h>
371541Srgrimes#include <sys/ioctl.h>
381541Srgrimes#include <sys/errno.h>
391541Srgrimes#include <sys/malloc.h>
401541Srgrimes#include <sys/socket.h>
411541Srgrimes#include <sys/socketvar.h>
421541Srgrimes
431541Srgrimes#include <net/if.h>
441541Srgrimes#include <net/route.h>
451541Srgrimes
461541Srgrimes#include <netinet/in_systm.h>
471541Srgrimes#include <netinet/in.h>
481541Srgrimes#include <netinet/in_var.h>
491541Srgrimes#include <netinet/if_ether.h>
501541Srgrimes
511541Srgrimes#ifdef INET
521541Srgrimes/*
531541Srgrimes * Return the network number from an internet address.
541541Srgrimes */
551541Srgrimesu_long
561541Srgrimesin_netof(in)
571541Srgrimes	struct in_addr in;
581541Srgrimes{
591541Srgrimes	register u_long i = ntohl(in.s_addr);
601541Srgrimes	register u_long net;
611541Srgrimes	register struct in_ifaddr *ia;
621541Srgrimes
631541Srgrimes	if (IN_CLASSA(i))
641541Srgrimes		net = i & IN_CLASSA_NET;
651541Srgrimes	else if (IN_CLASSB(i))
661541Srgrimes		net = i & IN_CLASSB_NET;
671541Srgrimes	else if (IN_CLASSC(i))
681541Srgrimes		net = i & IN_CLASSC_NET;
691541Srgrimes	else if (IN_CLASSD(i))
701541Srgrimes		net = i & IN_CLASSD_NET;
711541Srgrimes	else
721541Srgrimes		return (0);
731541Srgrimes
741541Srgrimes	/*
751541Srgrimes	 * Check whether network is a subnet;
761541Srgrimes	 * if so, return subnet number.
771541Srgrimes	 */
781541Srgrimes	for (ia = in_ifaddr; ia; ia = ia->ia_next)
791541Srgrimes		if (net == ia->ia_net)
801541Srgrimes			return (i & ia->ia_subnetmask);
811541Srgrimes	return (net);
821541Srgrimes}
831541Srgrimes
841541Srgrimes#ifndef SUBNETSARELOCAL
851541Srgrimes#define	SUBNETSARELOCAL	1
861541Srgrimes#endif
871541Srgrimesint subnetsarelocal = SUBNETSARELOCAL;
881541Srgrimes/*
891541Srgrimes * Return 1 if an internet address is for a ``local'' host
901541Srgrimes * (one to which we have a connection).  If subnetsarelocal
911541Srgrimes * is true, this includes other subnets of the local net.
921541Srgrimes * Otherwise, it includes only the directly-connected (sub)nets.
931541Srgrimes */
941541Srgrimesin_localaddr(in)
951541Srgrimes	struct in_addr in;
961541Srgrimes{
971541Srgrimes	register u_long i = ntohl(in.s_addr);
981541Srgrimes	register struct in_ifaddr *ia;
991541Srgrimes
1001541Srgrimes	if (subnetsarelocal) {
1011541Srgrimes		for (ia = in_ifaddr; ia; ia = ia->ia_next)
1021541Srgrimes			if ((i & ia->ia_netmask) == ia->ia_net)
1031541Srgrimes				return (1);
1041541Srgrimes	} else {
1051541Srgrimes		for (ia = in_ifaddr; ia; ia = ia->ia_next)
1061541Srgrimes			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
1071541Srgrimes				return (1);
1081541Srgrimes	}
1091541Srgrimes	return (0);
1101541Srgrimes}
1111541Srgrimes
1121541Srgrimes/*
1131541Srgrimes * Determine whether an IP address is in a reserved set of addresses
1141541Srgrimes * that may not be forwarded, or whether datagrams to that destination
1151541Srgrimes * may be forwarded.
1161541Srgrimes */
1171541Srgrimesin_canforward(in)
1181541Srgrimes	struct in_addr in;
1191541Srgrimes{
1201541Srgrimes	register u_long i = ntohl(in.s_addr);
1211541Srgrimes	register u_long net;
1221541Srgrimes
1231541Srgrimes	if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i))
1241541Srgrimes		return (0);
1251541Srgrimes	if (IN_CLASSA(i)) {
1261541Srgrimes		net = i & IN_CLASSA_NET;
1271541Srgrimes		if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
1281541Srgrimes			return (0);
1291541Srgrimes	}
1301541Srgrimes	return (1);
1311541Srgrimes}
1321541Srgrimes
1331541Srgrimes/*
1341541Srgrimes * Trim a mask in a sockaddr
1351541Srgrimes */
1361541Srgrimesvoid
1371541Srgrimesin_socktrim(ap)
1381541Srgrimesstruct sockaddr_in *ap;
1391541Srgrimes{
1401541Srgrimes    register char *cplim = (char *) &ap->sin_addr;
1411541Srgrimes    register char *cp = (char *) (&ap->sin_addr + 1);
1421541Srgrimes
1431541Srgrimes    ap->sin_len = 0;
1441541Srgrimes    while (--cp > cplim)
1451541Srgrimes        if (*cp) {
1461541Srgrimes	    (ap)->sin_len = cp - (char *) (ap) + 1;
1471541Srgrimes	    break;
1481541Srgrimes	}
1491541Srgrimes}
1501541Srgrimes
1511541Srgrimesint	in_interfaces;		/* number of external internet interfaces */
1521541Srgrimesextern	struct ifnet loif;
1531541Srgrimes
1541541Srgrimes/*
1551541Srgrimes * Generic internet control operations (ioctl's).
1561541Srgrimes * Ifp is 0 if not an interface-specific ioctl.
1571541Srgrimes */
1581541Srgrimes/* ARGSUSED */
1591541Srgrimesin_control(so, cmd, data, ifp)
1601541Srgrimes	struct socket *so;
1611541Srgrimes	int cmd;
1621541Srgrimes	caddr_t data;
1631541Srgrimes	register struct ifnet *ifp;
1641541Srgrimes{
1651541Srgrimes	register struct ifreq *ifr = (struct ifreq *)data;
1661541Srgrimes	register struct in_ifaddr *ia = 0;
1671541Srgrimes	register struct ifaddr *ifa;
1681541Srgrimes	struct in_ifaddr *oia;
1691541Srgrimes	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
1701541Srgrimes	struct sockaddr_in oldaddr;
1711541Srgrimes	int error, hostIsNew, maskIsNew;
1721541Srgrimes	u_long i;
1731541Srgrimes
1741541Srgrimes	/*
1751541Srgrimes	 * Find address for this interface, if it exists.
1761541Srgrimes	 */
1771541Srgrimes	if (ifp)
1781541Srgrimes		for (ia = in_ifaddr; ia; ia = ia->ia_next)
1791541Srgrimes			if (ia->ia_ifp == ifp)
1801541Srgrimes				break;
1811541Srgrimes
1821541Srgrimes	switch (cmd) {
1831541Srgrimes
1841541Srgrimes	case SIOCAIFADDR:
1851541Srgrimes	case SIOCDIFADDR:
1861541Srgrimes		if (ifra->ifra_addr.sin_family == AF_INET)
1871541Srgrimes		    for (oia = ia; ia; ia = ia->ia_next) {
1881541Srgrimes			if (ia->ia_ifp == ifp  &&
1891541Srgrimes			    ia->ia_addr.sin_addr.s_addr ==
1901541Srgrimes				ifra->ifra_addr.sin_addr.s_addr)
1911541Srgrimes			    break;
1921541Srgrimes		}
1931541Srgrimes		if (cmd == SIOCDIFADDR && ia == 0)
1941541Srgrimes			return (EADDRNOTAVAIL);
1951541Srgrimes		/* FALLTHROUGH */
1961541Srgrimes	case SIOCSIFADDR:
1971541Srgrimes	case SIOCSIFNETMASK:
1981541Srgrimes	case SIOCSIFDSTADDR:
1991541Srgrimes		if ((so->so_state & SS_PRIV) == 0)
2001541Srgrimes			return (EPERM);
2011541Srgrimes
2021541Srgrimes		if (ifp == 0)
2031541Srgrimes			panic("in_control");
2041541Srgrimes		if (ia == (struct in_ifaddr *)0) {
2051541Srgrimes			oia = (struct in_ifaddr *)
2061541Srgrimes				malloc(sizeof *oia, M_IFADDR, M_WAITOK);
2071541Srgrimes			if (oia == (struct in_ifaddr *)NULL)
2081541Srgrimes				return (ENOBUFS);
2091541Srgrimes			bzero((caddr_t)oia, sizeof *oia);
2101541Srgrimes			if (ia = in_ifaddr) {
2111541Srgrimes				for ( ; ia->ia_next; ia = ia->ia_next)
2121541Srgrimes					continue;
2131541Srgrimes				ia->ia_next = oia;
2141541Srgrimes			} else
2151541Srgrimes				in_ifaddr = oia;
2161541Srgrimes			ia = oia;
2171541Srgrimes			if (ifa = ifp->if_addrlist) {
2181541Srgrimes				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
2191541Srgrimes					continue;
2201541Srgrimes				ifa->ifa_next = (struct ifaddr *) ia;
2211541Srgrimes			} else
2221541Srgrimes				ifp->if_addrlist = (struct ifaddr *) ia;
2231541Srgrimes			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
2241541Srgrimes			ia->ia_ifa.ifa_dstaddr
2251541Srgrimes					= (struct sockaddr *)&ia->ia_dstaddr;
2261541Srgrimes			ia->ia_ifa.ifa_netmask
2271541Srgrimes					= (struct sockaddr *)&ia->ia_sockmask;
2281541Srgrimes			ia->ia_sockmask.sin_len = 8;
2291541Srgrimes			if (ifp->if_flags & IFF_BROADCAST) {
2301541Srgrimes				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
2311541Srgrimes				ia->ia_broadaddr.sin_family = AF_INET;
2321541Srgrimes			}
2331541Srgrimes			ia->ia_ifp = ifp;
2341541Srgrimes			if (ifp != &loif)
2351541Srgrimes				in_interfaces++;
2361541Srgrimes		}
2371541Srgrimes		break;
2381541Srgrimes
2391541Srgrimes	case SIOCSIFBRDADDR:
2401541Srgrimes		if ((so->so_state & SS_PRIV) == 0)
2411541Srgrimes			return (EPERM);
2421541Srgrimes		/* FALLTHROUGH */
2431541Srgrimes
2441541Srgrimes	case SIOCGIFADDR:
2451541Srgrimes	case SIOCGIFNETMASK:
2461541Srgrimes	case SIOCGIFDSTADDR:
2471541Srgrimes	case SIOCGIFBRDADDR:
2481541Srgrimes		if (ia == (struct in_ifaddr *)0)
2491541Srgrimes			return (EADDRNOTAVAIL);
2501541Srgrimes		break;
2511541Srgrimes	}
2521541Srgrimes	switch (cmd) {
2531541Srgrimes
2541541Srgrimes	case SIOCGIFADDR:
2551541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
2561541Srgrimes		break;
2571541Srgrimes
2581541Srgrimes	case SIOCGIFBRDADDR:
2591541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) == 0)
2601541Srgrimes			return (EINVAL);
2611541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
2621541Srgrimes		break;
2631541Srgrimes
2641541Srgrimes	case SIOCGIFDSTADDR:
2651541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
2661541Srgrimes			return (EINVAL);
2671541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
2681541Srgrimes		break;
2691541Srgrimes
2701541Srgrimes	case SIOCGIFNETMASK:
2711541Srgrimes		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
2721541Srgrimes		break;
2731541Srgrimes
2741541Srgrimes	case SIOCSIFDSTADDR:
2751541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
2761541Srgrimes			return (EINVAL);
2771541Srgrimes		oldaddr = ia->ia_dstaddr;
2781541Srgrimes		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
2791541Srgrimes		if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
2801541Srgrimes					(ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
2811541Srgrimes			ia->ia_dstaddr = oldaddr;
2821541Srgrimes			return (error);
2831541Srgrimes		}
2841541Srgrimes		if (ia->ia_flags & IFA_ROUTE) {
2851541Srgrimes			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
2861541Srgrimes			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
2871541Srgrimes			ia->ia_ifa.ifa_dstaddr =
2881541Srgrimes					(struct sockaddr *)&ia->ia_dstaddr;
2891541Srgrimes			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
2901541Srgrimes		}
2911541Srgrimes		break;
2921541Srgrimes
2931541Srgrimes	case SIOCSIFBRDADDR:
2941541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) == 0)
2951541Srgrimes			return (EINVAL);
2961541Srgrimes		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
2971541Srgrimes		break;
2981541Srgrimes
2991541Srgrimes	case SIOCSIFADDR:
3001541Srgrimes		return (in_ifinit(ifp, ia,
3011541Srgrimes		    (struct sockaddr_in *) &ifr->ifr_addr, 1));
3021541Srgrimes
3031541Srgrimes	case SIOCSIFNETMASK:
3041541Srgrimes		i = ifra->ifra_addr.sin_addr.s_addr;
3051541Srgrimes		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
3061541Srgrimes		break;
3071541Srgrimes
3081541Srgrimes	case SIOCAIFADDR:
3091541Srgrimes		maskIsNew = 0;
3101541Srgrimes		hostIsNew = 1;
3111541Srgrimes		error = 0;
3121541Srgrimes		if (ia->ia_addr.sin_family == AF_INET) {
3131541Srgrimes			if (ifra->ifra_addr.sin_len == 0) {
3141541Srgrimes				ifra->ifra_addr = ia->ia_addr;
3151541Srgrimes				hostIsNew = 0;
3161541Srgrimes			} else if (ifra->ifra_addr.sin_addr.s_addr ==
3171541Srgrimes					       ia->ia_addr.sin_addr.s_addr)
3181541Srgrimes				hostIsNew = 0;
3191541Srgrimes		}
3201541Srgrimes		if (ifra->ifra_mask.sin_len) {
3211541Srgrimes			in_ifscrub(ifp, ia);
3221541Srgrimes			ia->ia_sockmask = ifra->ifra_mask;
3231541Srgrimes			ia->ia_subnetmask =
3241541Srgrimes			     ntohl(ia->ia_sockmask.sin_addr.s_addr);
3251541Srgrimes			maskIsNew = 1;
3261541Srgrimes		}
3271541Srgrimes		if ((ifp->if_flags & IFF_POINTOPOINT) &&
3281541Srgrimes		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
3291541Srgrimes			in_ifscrub(ifp, ia);
3301541Srgrimes			ia->ia_dstaddr = ifra->ifra_dstaddr;
3311541Srgrimes			maskIsNew  = 1; /* We lie; but the effect's the same */
3321541Srgrimes		}
3331541Srgrimes		if (ifra->ifra_addr.sin_family == AF_INET &&
3341541Srgrimes		    (hostIsNew || maskIsNew))
3351541Srgrimes			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
3361541Srgrimes		if ((ifp->if_flags & IFF_BROADCAST) &&
3371541Srgrimes		    (ifra->ifra_broadaddr.sin_family == AF_INET))
3381541Srgrimes			ia->ia_broadaddr = ifra->ifra_broadaddr;
3391541Srgrimes		return (error);
3401541Srgrimes
3411541Srgrimes	case SIOCDIFADDR:
3421541Srgrimes		in_ifscrub(ifp, ia);
3431541Srgrimes		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
3441541Srgrimes			ifp->if_addrlist = ifa->ifa_next;
3451541Srgrimes		else {
3461541Srgrimes			while (ifa->ifa_next &&
3471541Srgrimes			       (ifa->ifa_next != (struct ifaddr *)ia))
3481541Srgrimes				    ifa = ifa->ifa_next;
3491541Srgrimes			if (ifa->ifa_next)
3501541Srgrimes				ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
3511541Srgrimes			else
3521541Srgrimes				printf("Couldn't unlink inifaddr from ifp\n");
3531541Srgrimes		}
3541541Srgrimes		oia = ia;
3551541Srgrimes		if (oia == (ia = in_ifaddr))
3561541Srgrimes			in_ifaddr = ia->ia_next;
3571541Srgrimes		else {
3581541Srgrimes			while (ia->ia_next && (ia->ia_next != oia))
3591541Srgrimes				ia = ia->ia_next;
3601541Srgrimes			if (ia->ia_next)
3611541Srgrimes				ia->ia_next = oia->ia_next;
3621541Srgrimes			else
3631541Srgrimes				printf("Didn't unlink inifadr from list\n");
3641541Srgrimes		}
3651541Srgrimes		IFAFREE((&oia->ia_ifa));
3661541Srgrimes		break;
3671541Srgrimes
3681541Srgrimes	default:
3691541Srgrimes		if (ifp == 0 || ifp->if_ioctl == 0)
3701541Srgrimes			return (EOPNOTSUPP);
3711541Srgrimes		return ((*ifp->if_ioctl)(ifp, cmd, data));
3721541Srgrimes	}
3731541Srgrimes	return (0);
3741541Srgrimes}
3751541Srgrimes
3761541Srgrimes/*
3771541Srgrimes * Delete any existing route for an interface.
3781541Srgrimes */
3791541Srgrimesvoid
3801541Srgrimesin_ifscrub(ifp, ia)
3811541Srgrimes	register struct ifnet *ifp;
3821541Srgrimes	register struct in_ifaddr *ia;
3831541Srgrimes{
3841541Srgrimes
3851541Srgrimes	if ((ia->ia_flags & IFA_ROUTE) == 0)
3861541Srgrimes		return;
3871541Srgrimes	if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
3881541Srgrimes		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
3891541Srgrimes	else
3901541Srgrimes		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
3911541Srgrimes	ia->ia_flags &= ~IFA_ROUTE;
3921541Srgrimes}
3931541Srgrimes
3941541Srgrimes/*
3951541Srgrimes * Initialize an interface's internet address
3961541Srgrimes * and routing table entry.
3971541Srgrimes */
3981541Srgrimesin_ifinit(ifp, ia, sin, scrub)
3991541Srgrimes	register struct ifnet *ifp;
4001541Srgrimes	register struct in_ifaddr *ia;
4011541Srgrimes	struct sockaddr_in *sin;
4021541Srgrimes	int scrub;
4031541Srgrimes{
4041541Srgrimes	register u_long i = ntohl(sin->sin_addr.s_addr);
4051541Srgrimes	struct sockaddr_in oldaddr;
4061541Srgrimes	int s = splimp(), flags = RTF_UP, error, ether_output();
4071541Srgrimes
4081541Srgrimes	oldaddr = ia->ia_addr;
4091541Srgrimes	ia->ia_addr = *sin;
4101541Srgrimes	/*
4111541Srgrimes	 * Give the interface a chance to initialize
4121541Srgrimes	 * if this is its first address,
4131541Srgrimes	 * and to validate the address if necessary.
4141541Srgrimes	 */
4151541Srgrimes	if (ifp->if_ioctl &&
4161541Srgrimes	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
4171541Srgrimes		splx(s);
4181541Srgrimes		ia->ia_addr = oldaddr;
4191541Srgrimes		return (error);
4201541Srgrimes	}
4211541Srgrimes	if (ifp->if_output == ether_output) { /* XXX: Another Kludge */
4221541Srgrimes		ia->ia_ifa.ifa_rtrequest = arp_rtrequest;
4231541Srgrimes		ia->ia_ifa.ifa_flags |= RTF_CLONING;
4241541Srgrimes	}
4251541Srgrimes	splx(s);
4261541Srgrimes	if (scrub) {
4271541Srgrimes		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
4281541Srgrimes		in_ifscrub(ifp, ia);
4291541Srgrimes		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
4301541Srgrimes	}
4311541Srgrimes	if (IN_CLASSA(i))
4321541Srgrimes		ia->ia_netmask = IN_CLASSA_NET;
4331541Srgrimes	else if (IN_CLASSB(i))
4341541Srgrimes		ia->ia_netmask = IN_CLASSB_NET;
4351541Srgrimes	else
4361541Srgrimes		ia->ia_netmask = IN_CLASSC_NET;
4371541Srgrimes	/*
4381541Srgrimes	 * The subnet mask usually includes at least the standard network part,
4391541Srgrimes	 * but may may be smaller in the case of supernetting.
4401541Srgrimes	 * If it is set, we believe it.
4411541Srgrimes	 */
4421541Srgrimes	if (ia->ia_subnetmask == 0) {
4431541Srgrimes		ia->ia_subnetmask = ia->ia_netmask;
4441541Srgrimes		ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
4451541Srgrimes	} else
4461541Srgrimes		ia->ia_netmask &= ia->ia_subnetmask;
4471541Srgrimes	ia->ia_net = i & ia->ia_netmask;
4481541Srgrimes	ia->ia_subnet = i & ia->ia_subnetmask;
4491541Srgrimes	in_socktrim(&ia->ia_sockmask);
4501541Srgrimes	/*
4511541Srgrimes	 * Add route for the network.
4521541Srgrimes	 */
4531541Srgrimes	ia->ia_ifa.ifa_metric = ifp->if_metric;
4541541Srgrimes	if (ifp->if_flags & IFF_BROADCAST) {
4551541Srgrimes		ia->ia_broadaddr.sin_addr.s_addr =
4561541Srgrimes			htonl(ia->ia_subnet | ~ia->ia_subnetmask);
4571541Srgrimes		ia->ia_netbroadcast.s_addr =
4581541Srgrimes			htonl(ia->ia_net | ~ ia->ia_netmask);
4591541Srgrimes	} else if (ifp->if_flags & IFF_LOOPBACK) {
4601541Srgrimes		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
4611541Srgrimes		flags |= RTF_HOST;
4621541Srgrimes	} else if (ifp->if_flags & IFF_POINTOPOINT) {
4631541Srgrimes		if (ia->ia_dstaddr.sin_family != AF_INET)
4641541Srgrimes			return (0);
4651541Srgrimes		flags |= RTF_HOST;
4661541Srgrimes	}
4671541Srgrimes	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
4681541Srgrimes		ia->ia_flags |= IFA_ROUTE;
4691541Srgrimes	/*
4701541Srgrimes	 * If the interface supports multicast, join the "all hosts"
4711541Srgrimes	 * multicast group on that interface.
4721541Srgrimes	 */
4731541Srgrimes	if (ifp->if_flags & IFF_MULTICAST) {
4741541Srgrimes		struct in_addr addr;
4751541Srgrimes
4761541Srgrimes		addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
4771541Srgrimes		in_addmulti(&addr, ifp);
4781541Srgrimes	}
4791541Srgrimes	return (error);
4801541Srgrimes}
4811541Srgrimes
4821541Srgrimes
4831541Srgrimes/*
4841541Srgrimes * Return 1 if the address might be a local broadcast address.
4851541Srgrimes */
4861541Srgrimesin_broadcast(in, ifp)
4871541Srgrimes	struct in_addr in;
4881541Srgrimes        struct ifnet *ifp;
4891541Srgrimes{
4901541Srgrimes	register struct ifaddr *ifa;
4911541Srgrimes	u_long t;
4921541Srgrimes
4931541Srgrimes	if (in.s_addr == INADDR_BROADCAST ||
4941541Srgrimes	    in.s_addr == INADDR_ANY)
4951541Srgrimes		return 1;
4961541Srgrimes	if ((ifp->if_flags & IFF_BROADCAST) == 0)
4971541Srgrimes		return 0;
4981541Srgrimes	t = ntohl(in.s_addr);
4991541Srgrimes	/*
5001541Srgrimes	 * Look through the list of addresses for a match
5011541Srgrimes	 * with a broadcast address.
5021541Srgrimes	 */
5031541Srgrimes#define ia ((struct in_ifaddr *)ifa)
5041541Srgrimes	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
5051541Srgrimes		if (ifa->ifa_addr->sa_family == AF_INET &&
5061541Srgrimes		    (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
5071541Srgrimes		     in.s_addr == ia->ia_netbroadcast.s_addr ||
5081541Srgrimes		     /*
5091541Srgrimes		      * Check for old-style (host 0) broadcast.
5101541Srgrimes		      */
5111541Srgrimes		     t == ia->ia_subnet || t == ia->ia_net))
5121541Srgrimes			    return 1;
5131541Srgrimes	return (0);
5141541Srgrimes#undef ia
5151541Srgrimes}
5161541Srgrimes/*
5171541Srgrimes * Add an address to the list of IP multicast addresses for a given interface.
5181541Srgrimes */
5191541Srgrimesstruct in_multi *
5201541Srgrimesin_addmulti(ap, ifp)
5211541Srgrimes	register struct in_addr *ap;
5221541Srgrimes	register struct ifnet *ifp;
5231541Srgrimes{
5241541Srgrimes	register struct in_multi *inm;
5251541Srgrimes	struct ifreq ifr;
5261541Srgrimes	struct in_ifaddr *ia;
5271541Srgrimes	int s = splnet();
5281541Srgrimes
5291541Srgrimes	/*
5301541Srgrimes	 * See if address already in list.
5311541Srgrimes	 */
5321541Srgrimes	IN_LOOKUP_MULTI(*ap, ifp, inm);
5331541Srgrimes	if (inm != NULL) {
5341541Srgrimes		/*
5351541Srgrimes		 * Found it; just increment the reference count.
5361541Srgrimes		 */
5371541Srgrimes		++inm->inm_refcount;
5381541Srgrimes	}
5391541Srgrimes	else {
5401541Srgrimes		/*
5411541Srgrimes		 * New address; allocate a new multicast record
5421541Srgrimes		 * and link it into the interface's multicast list.
5431541Srgrimes		 */
5441541Srgrimes		inm = (struct in_multi *)malloc(sizeof(*inm),
5451541Srgrimes		    M_IPMADDR, M_NOWAIT);
5461541Srgrimes		if (inm == NULL) {
5471541Srgrimes			splx(s);
5481541Srgrimes			return (NULL);
5491541Srgrimes		}
5501541Srgrimes		inm->inm_addr = *ap;
5511541Srgrimes		inm->inm_ifp = ifp;
5521541Srgrimes		inm->inm_refcount = 1;
5531541Srgrimes		IFP_TO_IA(ifp, ia);
5541541Srgrimes		if (ia == NULL) {
5551541Srgrimes			free(inm, M_IPMADDR);
5561541Srgrimes			splx(s);
5571541Srgrimes			return (NULL);
5581541Srgrimes		}
5591541Srgrimes		inm->inm_ia = ia;
5601541Srgrimes		inm->inm_next = ia->ia_multiaddrs;
5611541Srgrimes		ia->ia_multiaddrs = inm;
5621541Srgrimes		/*
5631541Srgrimes		 * Ask the network driver to update its multicast reception
5641541Srgrimes		 * filter appropriately for the new address.
5651541Srgrimes		 */
5661541Srgrimes		((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
5671541Srgrimes		((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
5681541Srgrimes		if ((ifp->if_ioctl == NULL) ||
5691541Srgrimes		    (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
5701541Srgrimes			ia->ia_multiaddrs = inm->inm_next;
5711541Srgrimes			free(inm, M_IPMADDR);
5721541Srgrimes			splx(s);
5731541Srgrimes			return (NULL);
5741541Srgrimes		}
5751541Srgrimes		/*
5761541Srgrimes		 * Let IGMP know that we have joined a new IP multicast group.
5771541Srgrimes		 */
5781541Srgrimes		igmp_joingroup(inm);
5791541Srgrimes	}
5801541Srgrimes	splx(s);
5811541Srgrimes	return (inm);
5821541Srgrimes}
5831541Srgrimes
5841541Srgrimes/*
5851541Srgrimes * Delete a multicast address record.
5861541Srgrimes */
5871541Srgrimesint
5881541Srgrimesin_delmulti(inm)
5891541Srgrimes	register struct in_multi *inm;
5901541Srgrimes{
5911541Srgrimes	register struct in_multi **p;
5921541Srgrimes	struct ifreq ifr;
5931541Srgrimes	int s = splnet();
5941541Srgrimes
5951541Srgrimes	if (--inm->inm_refcount == 0) {
5961541Srgrimes		/*
5971541Srgrimes		 * No remaining claims to this record; let IGMP know that
5981541Srgrimes		 * we are leaving the multicast group.
5991541Srgrimes		 */
6001541Srgrimes		igmp_leavegroup(inm);
6011541Srgrimes		/*
6021541Srgrimes		 * Unlink from list.
6031541Srgrimes		 */
6041541Srgrimes		for (p = &inm->inm_ia->ia_multiaddrs;
6051541Srgrimes		     *p != inm;
6061541Srgrimes		     p = &(*p)->inm_next)
6071541Srgrimes			 continue;
6081541Srgrimes		*p = (*p)->inm_next;
6091541Srgrimes		/*
6101541Srgrimes		 * Notify the network driver to update its multicast reception
6111541Srgrimes		 * filter.
6121541Srgrimes		 */
6131541Srgrimes		((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
6141541Srgrimes		((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
6151541Srgrimes								inm->inm_addr;
6161541Srgrimes		(*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
6171541Srgrimes							     (caddr_t)&ifr);
6181541Srgrimes		free(inm, M_IPMADDR);
6191541Srgrimes	}
6201541Srgrimes	splx(s);
6211541Srgrimes}
6221541Srgrimes#endif
623