xref: /csrg-svn/sys/netinet/in.c (revision 54716)
123175Smckusick /*
248464Skarels  * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
332787Sbostic  * All rights reserved.
423175Smckusick  *
544472Sbostic  * %sccs.include.redist.c%
632787Sbostic  *
7*54716Ssklower  *	@(#)in.c	7.25 (Berkeley) 07/06/92
823175Smckusick  */
97159Ssam 
1017058Sbloom #include "param.h"
1118377Skarels #include "ioctl.h"
1250134Ssklower #include "errno.h"
13*54716Ssklower #include "malloc.h"
1417058Sbloom #include "socket.h"
1517058Sbloom #include "socketvar.h"
1617058Sbloom #include "in_systm.h"
1748464Skarels #include "net/if.h"
1848464Skarels #include "net/route.h"
1948464Skarels #include "net/af.h"
2018377Skarels #include "in.h"
2118377Skarels #include "in_var.h"
227159Ssam 
237159Ssam #ifdef INET
247159Ssam /*
2518377Skarels  * Formulate an Internet address from network + host.
267159Ssam  */
277159Ssam struct in_addr
2818377Skarels in_makeaddr(net, host)
2918377Skarels 	u_long net, host;
307159Ssam {
3118377Skarels 	register struct in_ifaddr *ia;
3218377Skarels 	register u_long mask;
337159Ssam 	u_long addr;
347159Ssam 
3518377Skarels 	if (IN_CLASSA(net))
3618377Skarels 		mask = IN_CLASSA_HOST;
3718377Skarels 	else if (IN_CLASSB(net))
3818377Skarels 		mask = IN_CLASSB_HOST;
397159Ssam 	else
4018377Skarels 		mask = IN_CLASSC_HOST;
4118377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
4218377Skarels 		if ((ia->ia_netmask & net) == ia->ia_net) {
4318377Skarels 			mask = ~ia->ia_subnetmask;
4418377Skarels 			break;
4518377Skarels 		}
4618377Skarels 	addr = htonl(net | (host & mask));
477159Ssam 	return (*(struct in_addr *)&addr);
487159Ssam }
497159Ssam 
507159Ssam /*
518595Sroot  * Return the network number from an internet address.
527159Ssam  */
5324805Skarels u_long
547159Ssam in_netof(in)
557159Ssam 	struct in_addr in;
567159Ssam {
578937Sroot 	register u_long i = ntohl(in.s_addr);
5818377Skarels 	register u_long net;
5918377Skarels 	register struct in_ifaddr *ia;
607159Ssam 
6118377Skarels 	if (IN_CLASSA(i))
6218377Skarels 		net = i & IN_CLASSA_NET;
6318377Skarels 	else if (IN_CLASSB(i))
6418377Skarels 		net = i & IN_CLASSB_NET;
6531392Skarels 	else if (IN_CLASSC(i))
6631392Skarels 		net = i & IN_CLASSC_NET;
67*54716Ssklower #ifdef MULTICAST
68*54716Ssklower 	else if (IN_CLASSD(i))
69*54716Ssklower 		net = i & IN_CLASSD_NET;
70*54716Ssklower #endif
7118377Skarels 	else
7231392Skarels 		return (0);
7316413Skarels 
7416413Skarels 	/*
7518377Skarels 	 * Check whether network is a subnet;
7616413Skarels 	 * if so, return subnet number.
7716413Skarels 	 */
7818377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
7924805Skarels 		if (net == ia->ia_net)
8018377Skarels 			return (i & ia->ia_subnetmask);
8116413Skarels 	return (net);
827159Ssam }
837159Ssam 
847159Ssam /*
8537471Ssklower  * Compute and save network mask as sockaddr from an internet address.
8637471Ssklower  */
8737471Ssklower in_sockmaskof(in, sockmask)
8837471Ssklower 	struct in_addr in;
8937471Ssklower 	register struct sockaddr_in *sockmask;
9037471Ssklower {
9137471Ssklower 	register u_long net;
9237471Ssklower 	register u_long mask;
9337471Ssklower     {
9437471Ssklower 	register u_long i = ntohl(in.s_addr);
9537471Ssklower 
9637471Ssklower 	if (i == 0)
9737471Ssklower 		net = 0, mask = 0;
9837471Ssklower 	else if (IN_CLASSA(i))
9937471Ssklower 		net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
10037471Ssklower 	else if (IN_CLASSB(i))
10137471Ssklower 		net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
10237471Ssklower 	else if (IN_CLASSC(i))
10337471Ssklower 		net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
10437471Ssklower 	else
10537471Ssklower 		net = i, mask = -1;
10637471Ssklower     }
10737471Ssklower     {
10837471Ssklower 	register struct in_ifaddr *ia;
10937471Ssklower 	/*
11037471Ssklower 	 * Check whether network is a subnet;
11137471Ssklower 	 * if so, return subnet number.
11237471Ssklower 	 */
11337471Ssklower 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
11437471Ssklower 		if (net == ia->ia_net)
11537471Ssklower 			mask =  ia->ia_subnetmask;
11637471Ssklower     }
11737471Ssklower     {
11837471Ssklower 	register char *cpbase = (char *)&(sockmask->sin_addr);
11939183Ssklower 	register char *cp = (char *)(1 + &(sockmask->sin_addr));
12037471Ssklower 
12137471Ssklower 	sockmask->sin_addr.s_addr = htonl(mask);
12237471Ssklower 	sockmask->sin_len = 0;
12337471Ssklower 	while (--cp >= cpbase)
12437471Ssklower 		if (*cp) {
12537471Ssklower 			sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
12637471Ssklower 			break;
12737471Ssklower 		}
12837471Ssklower     }
12937471Ssklower }
13037471Ssklower 
13137471Ssklower /*
1328595Sroot  * Return the host portion of an internet address.
1337159Ssam  */
13426381Skarels u_long
1357159Ssam in_lnaof(in)
1367159Ssam 	struct in_addr in;
1377159Ssam {
1388937Sroot 	register u_long i = ntohl(in.s_addr);
13918377Skarels 	register u_long net, host;
14018377Skarels 	register struct in_ifaddr *ia;
1417159Ssam 
14216377Skarels 	if (IN_CLASSA(i)) {
14318377Skarels 		net = i & IN_CLASSA_NET;
14418377Skarels 		host = i & IN_CLASSA_HOST;
14516377Skarels 	} else if (IN_CLASSB(i)) {
14618377Skarels 		net = i & IN_CLASSB_NET;
14718377Skarels 		host = i & IN_CLASSB_HOST;
14831392Skarels 	} else if (IN_CLASSC(i)) {
14918377Skarels 		net = i & IN_CLASSC_NET;
15018377Skarels 		host = i & IN_CLASSC_HOST;
151*54716Ssklower #ifdef MULTICAST
152*54716Ssklower 	} else if (IN_CLASSD(i)) {
153*54716Ssklower 		net = i & IN_CLASSD_NET;
154*54716Ssklower 		host = i & IN_CLASSD_HOST;
155*54716Ssklower #endif
15631392Skarels 	} else
15731392Skarels 		return (i);
1587159Ssam 
15916413Skarels 	/*
16018377Skarels 	 * Check whether network is a subnet;
16116413Skarels 	 * if so, use the modified interpretation of `host'.
16216413Skarels 	 */
16318377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
16424805Skarels 		if (net == ia->ia_net)
16518377Skarels 			return (host &~ ia->ia_subnetmask);
16616413Skarels 	return (host);
16716377Skarels }
16816377Skarels 
16926381Skarels #ifndef SUBNETSARELOCAL
17026381Skarels #define	SUBNETSARELOCAL	1
17126381Skarels #endif
17226381Skarels int subnetsarelocal = SUBNETSARELOCAL;
17316377Skarels /*
17418377Skarels  * Return 1 if an internet address is for a ``local'' host
17526381Skarels  * (one to which we have a connection).  If subnetsarelocal
17626381Skarels  * is true, this includes other subnets of the local net.
17726381Skarels  * Otherwise, it includes only the directly-connected (sub)nets.
17817271Skarels  */
17917271Skarels in_localaddr(in)
18017271Skarels 	struct in_addr in;
18117271Skarels {
18217271Skarels 	register u_long i = ntohl(in.s_addr);
18318377Skarels 	register struct in_ifaddr *ia;
18417271Skarels 
18530697Skarels 	if (subnetsarelocal) {
18630697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
18730697Skarels 			if ((i & ia->ia_netmask) == ia->ia_net)
18830697Skarels 				return (1);
18930697Skarels 	} else {
19030697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
19130697Skarels 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
19230697Skarels 				return (1);
19330697Skarels 	}
19418377Skarels 	return (0);
19518377Skarels }
19618377Skarels 
19731392Skarels /*
19831392Skarels  * Determine whether an IP address is in a reserved set of addresses
19931392Skarels  * that may not be forwarded, or whether datagrams to that destination
20031392Skarels  * may be forwarded.
20131392Skarels  */
20231392Skarels in_canforward(in)
20331392Skarels 	struct in_addr in;
20431392Skarels {
20531392Skarels 	register u_long i = ntohl(in.s_addr);
20631392Skarels 	register u_long net;
20731392Skarels 
20831392Skarels 	if (IN_EXPERIMENTAL(i))
20931392Skarels 		return (0);
21031392Skarels 	if (IN_CLASSA(i)) {
21131392Skarels 		net = i & IN_CLASSA_NET;
21231392Skarels 		if (net == 0 || net == IN_LOOPBACKNET)
21331392Skarels 			return (0);
21431392Skarels 	}
21531392Skarels 	return (1);
21631392Skarels }
21731392Skarels 
21824805Skarels int	in_interfaces;		/* number of external internet interfaces */
21924805Skarels extern	struct ifnet loif;
22024805Skarels 
22118377Skarels /*
22218377Skarels  * Generic internet control operations (ioctl's).
22318377Skarels  * Ifp is 0 if not an interface-specific ioctl.
22418377Skarels  */
22524805Skarels /* ARGSUSED */
22618377Skarels in_control(so, cmd, data, ifp)
22718377Skarels 	struct socket *so;
22818377Skarels 	int cmd;
22918377Skarels 	caddr_t data;
23018377Skarels 	register struct ifnet *ifp;
23118377Skarels {
23218377Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
23318377Skarels 	register struct in_ifaddr *ia = 0;
23437471Ssklower 	register struct ifaddr *ifa;
23537471Ssklower 	struct in_ifaddr *oia;
23637471Ssklower 	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
23737471Ssklower 	struct sockaddr_in oldaddr;
23837471Ssklower 	int error, hostIsNew, maskIsNew;
23937471Ssklower 	u_long i;
24018377Skarels 
24118377Skarels 	/*
24218377Skarels 	 * Find address for this interface, if it exists.
24318377Skarels 	 */
24418377Skarels 	if (ifp)
24518377Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
24618377Skarels 			if (ia->ia_ifp == ifp)
24718377Skarels 				break;
24818377Skarels 
24918377Skarels 	switch (cmd) {
25018377Skarels 
25137471Ssklower 	case SIOCAIFADDR:
25237471Ssklower 	case SIOCDIFADDR:
25337471Ssklower 		if (ifra->ifra_addr.sin_family == AF_INET)
25437471Ssklower 		    for (oia = ia; ia; ia = ia->ia_next) {
25537471Ssklower 			if (ia->ia_ifp == ifp  &&
25637471Ssklower 			    ia->ia_addr.sin_addr.s_addr ==
25737471Ssklower 				ifra->ifra_addr.sin_addr.s_addr)
25837471Ssklower 			    break;
25937471Ssklower 		}
26037471Ssklower 		if (cmd == SIOCDIFADDR && ia == 0)
26137471Ssklower 			return (EADDRNOTAVAIL);
26237471Ssklower 		/* FALLTHROUGH */
26318377Skarels 	case SIOCSIFADDR:
26418377Skarels 	case SIOCSIFNETMASK:
26526456Skarels 	case SIOCSIFDSTADDR:
26648464Skarels 		if ((so->so_state & SS_PRIV) == 0)
26748464Skarels 			return (EPERM);
26818377Skarels 
26918377Skarels 		if (ifp == 0)
27018377Skarels 			panic("in_control");
27118377Skarels 		if (ia == (struct in_ifaddr *)0) {
27252028Ssklower 			oia = (struct in_ifaddr *)
27352028Ssklower 				malloc(sizeof *oia, M_IFADDR, M_WAITOK);
27452028Ssklower 			if (oia == (struct in_ifaddr *)NULL)
27518377Skarels 				return (ENOBUFS);
27652028Ssklower 			bzero((caddr_t)oia, sizeof *oia);
27718377Skarels 			if (ia = in_ifaddr) {
27818377Skarels 				for ( ; ia->ia_next; ia = ia->ia_next)
27952915Storek 					continue;
28052028Ssklower 				ia->ia_next = oia;
28118377Skarels 			} else
28252028Ssklower 				in_ifaddr = oia;
28352028Ssklower 			ia = oia;
28418377Skarels 			if (ifa = ifp->if_addrlist) {
28518377Skarels 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
28652915Storek 					continue;
28718377Skarels 				ifa->ifa_next = (struct ifaddr *) ia;
28818377Skarels 			} else
28918377Skarels 				ifp->if_addrlist = (struct ifaddr *) ia;
29037471Ssklower 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
29137471Ssklower 			ia->ia_ifa.ifa_dstaddr
29237471Ssklower 					= (struct sockaddr *)&ia->ia_dstaddr;
29337471Ssklower 			ia->ia_ifa.ifa_netmask
29437471Ssklower 					= (struct sockaddr *)&ia->ia_sockmask;
29537471Ssklower 			ia->ia_sockmask.sin_len = 8;
29637471Ssklower 			if (ifp->if_flags & IFF_BROADCAST) {
29737471Ssklower 				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
29837471Ssklower 				ia->ia_broadaddr.sin_family = AF_INET;
29937471Ssklower 			}
30018377Skarels 			ia->ia_ifp = ifp;
30124805Skarels 			if (ifp != &loif)
30224805Skarels 				in_interfaces++;
30317271Skarels 		}
30418377Skarels 		break;
30526317Skarels 
30626317Skarels 	case SIOCSIFBRDADDR:
30748464Skarels 		if ((so->so_state & SS_PRIV) == 0)
30848464Skarels 			return (EPERM);
30926317Skarels 		/* FALLTHROUGH */
31026317Skarels 
31139183Ssklower 	case SIOCGIFADDR:
31239183Ssklower 	case SIOCGIFNETMASK:
31339183Ssklower 	case SIOCGIFDSTADDR:
31439183Ssklower 	case SIOCGIFBRDADDR:
31526317Skarels 		if (ia == (struct in_ifaddr *)0)
31626317Skarels 			return (EADDRNOTAVAIL);
31726317Skarels 		break;
31817271Skarels 	}
31918377Skarels 	switch (cmd) {
32018377Skarels 
32118377Skarels 	case SIOCGIFADDR:
32237471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
32318377Skarels 		break;
32418377Skarels 
32518377Skarels 	case SIOCGIFBRDADDR:
32618377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
32718377Skarels 			return (EINVAL);
32837471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
32918377Skarels 		break;
33018377Skarels 
33118377Skarels 	case SIOCGIFDSTADDR:
33218377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
33318377Skarels 			return (EINVAL);
33437471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
33518377Skarels 		break;
33618377Skarels 
33718377Skarels 	case SIOCGIFNETMASK:
33837471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
33918377Skarels 		break;
34018377Skarels 
34118377Skarels 	case SIOCSIFDSTADDR:
34218377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
34318377Skarels 			return (EINVAL);
34427066Skarels 		oldaddr = ia->ia_dstaddr;
34537471Ssklower 		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
34652619Ssklower 		if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
34752619Ssklower 					(ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
34827066Skarels 			ia->ia_dstaddr = oldaddr;
34918377Skarels 			return (error);
35027066Skarels 		}
35127066Skarels 		if (ia->ia_flags & IFA_ROUTE) {
35237471Ssklower 			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
35337471Ssklower 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
35445454Ssklower 			ia->ia_ifa.ifa_dstaddr =
35545454Ssklower 					(struct sockaddr *)&ia->ia_dstaddr;
35637471Ssklower 			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
35727066Skarels 		}
35818377Skarels 		break;
35918377Skarels 
36018377Skarels 	case SIOCSIFBRDADDR:
36118377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
36218377Skarels 			return (EINVAL);
36337471Ssklower 		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
36418377Skarels 		break;
36518377Skarels 
36618377Skarels 	case SIOCSIFADDR:
36734500Skarels 		return (in_ifinit(ifp, ia,
36837471Ssklower 		    (struct sockaddr_in *) &ifr->ifr_addr, 1));
36918377Skarels 
37018377Skarels 	case SIOCSIFNETMASK:
37137471Ssklower 		i = ifra->ifra_addr.sin_addr.s_addr;
37237471Ssklower 		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
37318377Skarels 		break;
37418377Skarels 
37537471Ssklower 	case SIOCAIFADDR:
37644368Skarels 		maskIsNew = 0;
37744368Skarels 		hostIsNew = 1;
37844368Skarels 		error = 0;
37937471Ssklower 		if (ia->ia_addr.sin_family == AF_INET) {
38037471Ssklower 			if (ifra->ifra_addr.sin_len == 0) {
38137471Ssklower 				ifra->ifra_addr = ia->ia_addr;
38237471Ssklower 				hostIsNew = 0;
38337471Ssklower 			} else if (ifra->ifra_addr.sin_addr.s_addr ==
38437471Ssklower 					       ia->ia_addr.sin_addr.s_addr)
38537471Ssklower 				hostIsNew = 0;
38637471Ssklower 		}
38737471Ssklower 		if (ifra->ifra_mask.sin_len) {
38837471Ssklower 			in_ifscrub(ifp, ia);
38937471Ssklower 			ia->ia_sockmask = ifra->ifra_mask;
39037471Ssklower 			ia->ia_subnetmask =
39144368Skarels 			     ntohl(ia->ia_sockmask.sin_addr.s_addr);
39237471Ssklower 			maskIsNew = 1;
39337471Ssklower 		}
39437471Ssklower 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
39537471Ssklower 		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
39637471Ssklower 			in_ifscrub(ifp, ia);
39737471Ssklower 			ia->ia_dstaddr = ifra->ifra_dstaddr;
39837471Ssklower 			maskIsNew  = 1; /* We lie; but the effect's the same */
39937471Ssklower 		}
40037471Ssklower 		if (ifra->ifra_addr.sin_family == AF_INET &&
40144368Skarels 		    (hostIsNew || maskIsNew))
40237471Ssklower 			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
40337471Ssklower 		if ((ifp->if_flags & IFF_BROADCAST) &&
40437471Ssklower 		    (ifra->ifra_broadaddr.sin_family == AF_INET))
40537471Ssklower 			ia->ia_broadaddr = ifra->ifra_broadaddr;
40637471Ssklower 		return (error);
40737471Ssklower 
40837471Ssklower 	case SIOCDIFADDR:
40937471Ssklower 		in_ifscrub(ifp, ia);
41037471Ssklower 		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
41137471Ssklower 			ifp->if_addrlist = ifa->ifa_next;
41237471Ssklower 		else {
41337471Ssklower 			while (ifa->ifa_next &&
41437471Ssklower 			       (ifa->ifa_next != (struct ifaddr *)ia))
41537471Ssklower 				    ifa = ifa->ifa_next;
41637471Ssklower 			if (ifa->ifa_next)
41744368Skarels 				ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
41837471Ssklower 			else
41937471Ssklower 				printf("Couldn't unlink inifaddr from ifp\n");
42037471Ssklower 		}
42137471Ssklower 		oia = ia;
42244368Skarels 		if (oia == (ia = in_ifaddr))
42337471Ssklower 			in_ifaddr = ia->ia_next;
42444368Skarels 		else {
42544368Skarels 			while (ia->ia_next && (ia->ia_next != oia))
42637471Ssklower 				ia = ia->ia_next;
42737471Ssklower 			if (ia->ia_next)
42844368Skarels 				ia->ia_next = oia->ia_next;
42937471Ssklower 			else
43037471Ssklower 				printf("Didn't unlink inifadr from list\n");
43137471Ssklower 		}
43252028Ssklower 		IFAFREE((&oia->ia_ifa));
43337471Ssklower 		break;
43437471Ssklower 
43518377Skarels 	default:
43618377Skarels 		if (ifp == 0 || ifp->if_ioctl == 0)
43718377Skarels 			return (EOPNOTSUPP);
43818377Skarels 		return ((*ifp->if_ioctl)(ifp, cmd, data));
43918377Skarels 	}
44017271Skarels 	return (0);
44117271Skarels }
44217271Skarels 
44317271Skarels /*
44437471Ssklower  * Delete any existing route for an interface.
44537471Ssklower  */
44637471Ssklower in_ifscrub(ifp, ia)
44737471Ssklower 	register struct ifnet *ifp;
44837471Ssklower 	register struct in_ifaddr *ia;
44937471Ssklower {
45037471Ssklower 
45137471Ssklower 	if ((ia->ia_flags & IFA_ROUTE) == 0)
45237471Ssklower 		return;
45337471Ssklower 	if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
45437471Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
45537471Ssklower 	else
45637471Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
45737471Ssklower 	ia->ia_flags &= ~IFA_ROUTE;
45837471Ssklower }
45937471Ssklower 
46037471Ssklower /*
46118377Skarels  * Initialize an interface's internet address
46218377Skarels  * and routing table entry.
4637159Ssam  */
46437471Ssklower in_ifinit(ifp, ia, sin, scrub)
4657159Ssam 	register struct ifnet *ifp;
46618377Skarels 	register struct in_ifaddr *ia;
46718377Skarels 	struct sockaddr_in *sin;
46852274Storek 	int scrub;
4697159Ssam {
47018377Skarels 	register u_long i = ntohl(sin->sin_addr.s_addr);
47137471Ssklower 	struct sockaddr_in oldaddr;
472*54716Ssklower 	int s = splimp(), flags = RTF_UP, error, ether_output();
473*54716Ssklower 	void arp_rtrequest();
4747159Ssam 
47527066Skarels 	oldaddr = ia->ia_addr;
47637471Ssklower 	ia->ia_addr = *sin;
47718377Skarels 	/*
47826317Skarels 	 * Give the interface a chance to initialize
47926317Skarels 	 * if this is its first address,
48026317Skarels 	 * and to validate the address if necessary.
48126317Skarels 	 */
48252274Storek 	if (ifp->if_ioctl &&
48352274Storek 	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
48426317Skarels 		splx(s);
48527066Skarels 		ia->ia_addr = oldaddr;
48626317Skarels 		return (error);
48726317Skarels 	}
48850134Ssklower 	if (ifp->if_output == ether_output) { /* XXX: Another Kludge */
48950134Ssklower 		ia->ia_ifa.ifa_rtrequest = arp_rtrequest;
49050134Ssklower 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
49150134Ssklower 	}
49245454Ssklower 	splx(s);
49337471Ssklower 	if (scrub) {
49437471Ssklower 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
49537471Ssklower 		in_ifscrub(ifp, ia);
49637471Ssklower 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
49718377Skarels 	}
49818377Skarels 	if (IN_CLASSA(i))
49918377Skarels 		ia->ia_netmask = IN_CLASSA_NET;
50018377Skarels 	else if (IN_CLASSB(i))
50118377Skarels 		ia->ia_netmask = IN_CLASSB_NET;
50218377Skarels 	else
50318377Skarels 		ia->ia_netmask = IN_CLASSC_NET;
50418377Skarels 	ia->ia_net = i & ia->ia_netmask;
50518377Skarels 	/*
50618377Skarels 	 * The subnet mask includes at least the standard network part,
50718377Skarels 	 * but may already have been set to a larger value.
50818377Skarels 	 */
50918377Skarels 	ia->ia_subnetmask |= ia->ia_netmask;
51018377Skarels 	ia->ia_subnet = i & ia->ia_subnetmask;
51137471Ssklower 	ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
51239183Ssklower 	{
51339183Ssklower 		register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
51439183Ssklower 		register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
51539183Ssklower 		while (--cp >= cpbase)
51639183Ssklower 			if (*cp) {
51739183Ssklower 				ia->ia_sockmask.sin_len =
51839183Ssklower 					1 + cp - (char *) &(ia->ia_sockmask);
51939183Ssklower 				break;
52039183Ssklower 			}
52139183Ssklower 	}
52245454Ssklower 	/*
52345454Ssklower 	 * Add route for the network.
52445454Ssklower 	 */
52552617Ssklower 	ia->ia_ifa.ifa_metric = ifp->if_metric;
52618377Skarels 	if (ifp->if_flags & IFF_BROADCAST) {
52737471Ssklower 		ia->ia_broadaddr.sin_addr =
52818377Skarels 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
52925195Skarels 		ia->ia_netbroadcast.s_addr =
53025195Skarels 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
53145454Ssklower 	} else if (ifp->if_flags & IFF_LOOPBACK) {
53237471Ssklower 		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
53345454Ssklower 		flags |= RTF_HOST;
53445454Ssklower 	} else if (ifp->if_flags & IFF_POINTOPOINT) {
53545454Ssklower 		if (ia->ia_dstaddr.sin_family != AF_INET)
53645454Ssklower 			return (0);
53745454Ssklower 		flags |= RTF_HOST;
53827066Skarels 	}
53945454Ssklower 	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
54045454Ssklower 		ia->ia_flags |= IFA_ROUTE;
541*54716Ssklower #ifdef MULTICAST
542*54716Ssklower 	/*
543*54716Ssklower 	 * If the interface supports multicast, join the "all hosts"
544*54716Ssklower 	 * multicast group on that interface.
545*54716Ssklower 	 */
546*54716Ssklower 	if (ifp->if_flags & IFF_MULTICAST) {
547*54716Ssklower 		struct in_addr addr;
548*54716Ssklower 
549*54716Ssklower 		addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
550*54716Ssklower 		in_addmulti(&addr, ifp);
551*54716Ssklower 	}
552*54716Ssklower #endif
55345454Ssklower 	return (error);
5547159Ssam }
55518377Skarels 
55618377Skarels /*
55718377Skarels  * Return address info for specified internet network.
55818377Skarels  */
55918377Skarels struct in_ifaddr *
56018377Skarels in_iaonnetof(net)
56118377Skarels 	u_long net;
56218377Skarels {
56318377Skarels 	register struct in_ifaddr *ia;
56418377Skarels 
56518377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
56618377Skarels 		if (ia->ia_subnet == net)
56718377Skarels 			return (ia);
56818377Skarels 	return ((struct in_ifaddr *)0);
56918377Skarels }
57018377Skarels 
57118377Skarels /*
57230523Skarels  * Return 1 if the address might be a local broadcast address.
57318377Skarels  */
57418377Skarels in_broadcast(in)
57518377Skarels 	struct in_addr in;
57618377Skarels {
57718377Skarels 	register struct in_ifaddr *ia;
57830523Skarels 	u_long t;
57918377Skarels 
58018377Skarels 	/*
58118377Skarels 	 * Look through the list of addresses for a match
58218377Skarels 	 * with a broadcast address.
58318377Skarels 	 */
58418377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
58530523Skarels 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
58637471Ssklower 		if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
58718377Skarels 		     return (1);
58830523Skarels 		/*
58930523Skarels 		 * Check for old-style (host 0) broadcast.
59030523Skarels 		 */
59130523Skarels 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
59230523Skarels 		    return (1);
59330523Skarels 	}
59430523Skarels 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
59530523Skarels 		return (1);
59618377Skarels 	return (0);
59718377Skarels }
598*54716Ssklower 
599*54716Ssklower #ifdef MULTICAST
600*54716Ssklower /*
601*54716Ssklower  * Add an address to the list of IP multicast addresses for a given interface.
602*54716Ssklower  */
603*54716Ssklower struct in_multi *
604*54716Ssklower in_addmulti(ap, ifp)
605*54716Ssklower 	register struct in_addr *ap;
606*54716Ssklower 	register struct ifnet *ifp;
607*54716Ssklower {
608*54716Ssklower 	register struct in_multi *inm;
609*54716Ssklower 	struct ifreq ifr;
610*54716Ssklower 	struct in_ifaddr *ia;
611*54716Ssklower 	int s = splnet();
612*54716Ssklower int error;
613*54716Ssklower 
614*54716Ssklower 	/*
615*54716Ssklower 	 * See if address already in list.
616*54716Ssklower 	 */
617*54716Ssklower 	IN_LOOKUP_MULTI(*ap, ifp, inm);
618*54716Ssklower 	if (inm != NULL) {
619*54716Ssklower 		/*
620*54716Ssklower 		 * Found it; just increment the reference count.
621*54716Ssklower 		 */
622*54716Ssklower 		++inm->inm_refcount;
623*54716Ssklower 	}
624*54716Ssklower 	else {
625*54716Ssklower 		/*
626*54716Ssklower 		 * New address; allocate a new multicast record
627*54716Ssklower 		 * and link it into the interface's multicast list.
628*54716Ssklower 		 */
629*54716Ssklower 		inm = (struct in_multi *)malloc(sizeof(*inm),
630*54716Ssklower 		    M_IPMADDR, M_NOWAIT);
631*54716Ssklower 		if (inm == NULL) {
632*54716Ssklower 			splx(s);
633*54716Ssklower 			return (NULL);
634*54716Ssklower 		}
635*54716Ssklower 		inm->inm_addr = *ap;
636*54716Ssklower 		inm->inm_ifp = ifp;
637*54716Ssklower 		inm->inm_refcount = 1;
638*54716Ssklower 		IFP_TO_IA(ifp, ia);
639*54716Ssklower 		if (ia == NULL) {
640*54716Ssklower 			free(inm, M_IPMADDR);
641*54716Ssklower 			splx(s);
642*54716Ssklower 			return (NULL);
643*54716Ssklower 		}
644*54716Ssklower 		inm->inm_ia = ia;
645*54716Ssklower 		inm->inm_next = ia->ia_multiaddrs;
646*54716Ssklower 		ia->ia_multiaddrs = inm;
647*54716Ssklower 		/*
648*54716Ssklower 		 * Ask the network driver to update its multicast reception
649*54716Ssklower 		 * filter appropriately for the new address.
650*54716Ssklower 		 */
651*54716Ssklower 		((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
652*54716Ssklower 		((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
653*54716Ssklower 		if (ifp->if_ioctl == NULL) {
654*54716Ssklower 			free(inm, M_IPMADDR);
655*54716Ssklower 			splx(s);
656*54716Ssklower 			return (NULL);
657*54716Ssklower 		}
658*54716Ssklower 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr);
659*54716Ssklower 		if (error != 0) {
660*54716Ssklower 			free(inm, M_IPMADDR);
661*54716Ssklower 			splx(s);
662*54716Ssklower 			return (NULL);
663*54716Ssklower 		}
664*54716Ssklower 		/*
665*54716Ssklower 		 * Let IGMP know that we have joined a new IP multicast group.
666*54716Ssklower 		 */
667*54716Ssklower 		igmp_joingroup(inm);
668*54716Ssklower 	}
669*54716Ssklower 	splx(s);
670*54716Ssklower 	return (inm);
671*54716Ssklower }
672*54716Ssklower 
673*54716Ssklower /*
674*54716Ssklower  * Delete a multicast address record.
675*54716Ssklower  */
676*54716Ssklower int
677*54716Ssklower in_delmulti(inm)
678*54716Ssklower 	register struct in_multi *inm;
679*54716Ssklower {
680*54716Ssklower 	register struct in_multi **p;
681*54716Ssklower 	struct ifreq ifr;
682*54716Ssklower 	int s = splnet();
683*54716Ssklower 
684*54716Ssklower 	if (--inm->inm_refcount == 0) {
685*54716Ssklower 		/*
686*54716Ssklower 		 * No remaining claims to this record; let IGMP know that
687*54716Ssklower 		 * we are leaving the multicast group.
688*54716Ssklower 		 */
689*54716Ssklower 		igmp_leavegroup(inm);
690*54716Ssklower 		/*
691*54716Ssklower 		 * Unlink from list.
692*54716Ssklower 		 */
693*54716Ssklower 		for (p = &inm->inm_ia->ia_multiaddrs;
694*54716Ssklower 		     *p != inm;
695*54716Ssklower 		     p = &(*p)->inm_next)
696*54716Ssklower 			 continue;
697*54716Ssklower 		*p = (*p)->inm_next;
698*54716Ssklower 		/*
699*54716Ssklower 		 * Notify the network driver to update its multicast reception
700*54716Ssklower 		 * filter.
701*54716Ssklower 		 */
702*54716Ssklower 		((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
703*54716Ssklower 		((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
704*54716Ssklower 								inm->inm_addr;
705*54716Ssklower 		(*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
706*54716Ssklower 							     (caddr_t)&ifr);
707*54716Ssklower 		free(inm, M_IPMADDR);
708*54716Ssklower 	}
709*54716Ssklower 	splx(s);
710*54716Ssklower }
7117159Ssam #endif
712*54716Ssklower #endif
713