xref: /csrg-svn/sys/netinet/in.c (revision 56531)
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*56531Sbostic  *	@(#)in.c	7.26 (Berkeley) 10/11/92
823175Smckusick  */
97159Ssam 
10*56531Sbostic #include <sys/param.h>
11*56531Sbostic #include <sys/ioctl.h>
12*56531Sbostic #include <sys/errno.h>
13*56531Sbostic #include <sys/malloc.h>
14*56531Sbostic #include <sys/socket.h>
15*56531Sbostic #include <sys/socketvar.h>
167159Ssam 
17*56531Sbostic #include <net/if.h>
18*56531Sbostic #include <net/route.h>
19*56531Sbostic #include <net/af.h>
20*56531Sbostic 
21*56531Sbostic #include <netinet/in_systm.h>
22*56531Sbostic #include <netinet/in.h>
23*56531Sbostic #include <netinet/in_var.h>
24*56531Sbostic 
257159Ssam #ifdef INET
267159Ssam /*
2718377Skarels  * Formulate an Internet address from network + host.
287159Ssam  */
297159Ssam struct in_addr
3018377Skarels in_makeaddr(net, host)
3118377Skarels 	u_long net, host;
327159Ssam {
3318377Skarels 	register struct in_ifaddr *ia;
3418377Skarels 	register u_long mask;
357159Ssam 	u_long addr;
367159Ssam 
3718377Skarels 	if (IN_CLASSA(net))
3818377Skarels 		mask = IN_CLASSA_HOST;
3918377Skarels 	else if (IN_CLASSB(net))
4018377Skarels 		mask = IN_CLASSB_HOST;
417159Ssam 	else
4218377Skarels 		mask = IN_CLASSC_HOST;
4318377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
4418377Skarels 		if ((ia->ia_netmask & net) == ia->ia_net) {
4518377Skarels 			mask = ~ia->ia_subnetmask;
4618377Skarels 			break;
4718377Skarels 		}
4818377Skarels 	addr = htonl(net | (host & mask));
497159Ssam 	return (*(struct in_addr *)&addr);
507159Ssam }
517159Ssam 
527159Ssam /*
538595Sroot  * Return the network number from an internet address.
547159Ssam  */
5524805Skarels u_long
567159Ssam in_netof(in)
577159Ssam 	struct in_addr in;
587159Ssam {
598937Sroot 	register u_long i = ntohl(in.s_addr);
6018377Skarels 	register u_long net;
6118377Skarels 	register struct in_ifaddr *ia;
627159Ssam 
6318377Skarels 	if (IN_CLASSA(i))
6418377Skarels 		net = i & IN_CLASSA_NET;
6518377Skarels 	else if (IN_CLASSB(i))
6618377Skarels 		net = i & IN_CLASSB_NET;
6731392Skarels 	else if (IN_CLASSC(i))
6831392Skarels 		net = i & IN_CLASSC_NET;
6954716Ssklower #ifdef MULTICAST
7054716Ssklower 	else if (IN_CLASSD(i))
7154716Ssklower 		net = i & IN_CLASSD_NET;
7254716Ssklower #endif
7318377Skarels 	else
7431392Skarels 		return (0);
7516413Skarels 
7616413Skarels 	/*
7718377Skarels 	 * Check whether network is a subnet;
7816413Skarels 	 * if so, return subnet number.
7916413Skarels 	 */
8018377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
8124805Skarels 		if (net == ia->ia_net)
8218377Skarels 			return (i & ia->ia_subnetmask);
8316413Skarels 	return (net);
847159Ssam }
857159Ssam 
867159Ssam /*
8737471Ssklower  * Compute and save network mask as sockaddr from an internet address.
8837471Ssklower  */
8937471Ssklower in_sockmaskof(in, sockmask)
9037471Ssklower 	struct in_addr in;
9137471Ssklower 	register struct sockaddr_in *sockmask;
9237471Ssklower {
9337471Ssklower 	register u_long net;
9437471Ssklower 	register u_long mask;
9537471Ssklower     {
9637471Ssklower 	register u_long i = ntohl(in.s_addr);
9737471Ssklower 
9837471Ssklower 	if (i == 0)
9937471Ssklower 		net = 0, mask = 0;
10037471Ssklower 	else if (IN_CLASSA(i))
10137471Ssklower 		net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
10237471Ssklower 	else if (IN_CLASSB(i))
10337471Ssklower 		net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
10437471Ssklower 	else if (IN_CLASSC(i))
10537471Ssklower 		net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
10637471Ssklower 	else
10737471Ssklower 		net = i, mask = -1;
10837471Ssklower     }
10937471Ssklower     {
11037471Ssklower 	register struct in_ifaddr *ia;
11137471Ssklower 	/*
11237471Ssklower 	 * Check whether network is a subnet;
11337471Ssklower 	 * if so, return subnet number.
11437471Ssklower 	 */
11537471Ssklower 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
11637471Ssklower 		if (net == ia->ia_net)
11737471Ssklower 			mask =  ia->ia_subnetmask;
11837471Ssklower     }
11937471Ssklower     {
12037471Ssklower 	register char *cpbase = (char *)&(sockmask->sin_addr);
12139183Ssklower 	register char *cp = (char *)(1 + &(sockmask->sin_addr));
12237471Ssklower 
12337471Ssklower 	sockmask->sin_addr.s_addr = htonl(mask);
12437471Ssklower 	sockmask->sin_len = 0;
12537471Ssklower 	while (--cp >= cpbase)
12637471Ssklower 		if (*cp) {
12737471Ssklower 			sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
12837471Ssklower 			break;
12937471Ssklower 		}
13037471Ssklower     }
13137471Ssklower }
13237471Ssklower 
13337471Ssklower /*
1348595Sroot  * Return the host portion of an internet address.
1357159Ssam  */
13626381Skarels u_long
1377159Ssam in_lnaof(in)
1387159Ssam 	struct in_addr in;
1397159Ssam {
1408937Sroot 	register u_long i = ntohl(in.s_addr);
14118377Skarels 	register u_long net, host;
14218377Skarels 	register struct in_ifaddr *ia;
1437159Ssam 
14416377Skarels 	if (IN_CLASSA(i)) {
14518377Skarels 		net = i & IN_CLASSA_NET;
14618377Skarels 		host = i & IN_CLASSA_HOST;
14716377Skarels 	} else if (IN_CLASSB(i)) {
14818377Skarels 		net = i & IN_CLASSB_NET;
14918377Skarels 		host = i & IN_CLASSB_HOST;
15031392Skarels 	} else if (IN_CLASSC(i)) {
15118377Skarels 		net = i & IN_CLASSC_NET;
15218377Skarels 		host = i & IN_CLASSC_HOST;
15354716Ssklower #ifdef MULTICAST
15454716Ssklower 	} else if (IN_CLASSD(i)) {
15554716Ssklower 		net = i & IN_CLASSD_NET;
15654716Ssklower 		host = i & IN_CLASSD_HOST;
15754716Ssklower #endif
15831392Skarels 	} else
15931392Skarels 		return (i);
1607159Ssam 
16116413Skarels 	/*
16218377Skarels 	 * Check whether network is a subnet;
16316413Skarels 	 * if so, use the modified interpretation of `host'.
16416413Skarels 	 */
16518377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
16624805Skarels 		if (net == ia->ia_net)
16718377Skarels 			return (host &~ ia->ia_subnetmask);
16816413Skarels 	return (host);
16916377Skarels }
17016377Skarels 
17126381Skarels #ifndef SUBNETSARELOCAL
17226381Skarels #define	SUBNETSARELOCAL	1
17326381Skarels #endif
17426381Skarels int subnetsarelocal = SUBNETSARELOCAL;
17516377Skarels /*
17618377Skarels  * Return 1 if an internet address is for a ``local'' host
17726381Skarels  * (one to which we have a connection).  If subnetsarelocal
17826381Skarels  * is true, this includes other subnets of the local net.
17926381Skarels  * Otherwise, it includes only the directly-connected (sub)nets.
18017271Skarels  */
18117271Skarels in_localaddr(in)
18217271Skarels 	struct in_addr in;
18317271Skarels {
18417271Skarels 	register u_long i = ntohl(in.s_addr);
18518377Skarels 	register struct in_ifaddr *ia;
18617271Skarels 
18730697Skarels 	if (subnetsarelocal) {
18830697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
18930697Skarels 			if ((i & ia->ia_netmask) == ia->ia_net)
19030697Skarels 				return (1);
19130697Skarels 	} else {
19230697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
19330697Skarels 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
19430697Skarels 				return (1);
19530697Skarels 	}
19618377Skarels 	return (0);
19718377Skarels }
19818377Skarels 
19931392Skarels /*
20031392Skarels  * Determine whether an IP address is in a reserved set of addresses
20131392Skarels  * that may not be forwarded, or whether datagrams to that destination
20231392Skarels  * may be forwarded.
20331392Skarels  */
20431392Skarels in_canforward(in)
20531392Skarels 	struct in_addr in;
20631392Skarels {
20731392Skarels 	register u_long i = ntohl(in.s_addr);
20831392Skarels 	register u_long net;
20931392Skarels 
21031392Skarels 	if (IN_EXPERIMENTAL(i))
21131392Skarels 		return (0);
21231392Skarels 	if (IN_CLASSA(i)) {
21331392Skarels 		net = i & IN_CLASSA_NET;
21431392Skarels 		if (net == 0 || net == IN_LOOPBACKNET)
21531392Skarels 			return (0);
21631392Skarels 	}
21731392Skarels 	return (1);
21831392Skarels }
21931392Skarels 
22024805Skarels int	in_interfaces;		/* number of external internet interfaces */
22124805Skarels extern	struct ifnet loif;
22224805Skarels 
22318377Skarels /*
22418377Skarels  * Generic internet control operations (ioctl's).
22518377Skarels  * Ifp is 0 if not an interface-specific ioctl.
22618377Skarels  */
22724805Skarels /* ARGSUSED */
22818377Skarels in_control(so, cmd, data, ifp)
22918377Skarels 	struct socket *so;
23018377Skarels 	int cmd;
23118377Skarels 	caddr_t data;
23218377Skarels 	register struct ifnet *ifp;
23318377Skarels {
23418377Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
23518377Skarels 	register struct in_ifaddr *ia = 0;
23637471Ssklower 	register struct ifaddr *ifa;
23737471Ssklower 	struct in_ifaddr *oia;
23837471Ssklower 	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
23937471Ssklower 	struct sockaddr_in oldaddr;
24037471Ssklower 	int error, hostIsNew, maskIsNew;
24137471Ssklower 	u_long i;
24218377Skarels 
24318377Skarels 	/*
24418377Skarels 	 * Find address for this interface, if it exists.
24518377Skarels 	 */
24618377Skarels 	if (ifp)
24718377Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
24818377Skarels 			if (ia->ia_ifp == ifp)
24918377Skarels 				break;
25018377Skarels 
25118377Skarels 	switch (cmd) {
25218377Skarels 
25337471Ssklower 	case SIOCAIFADDR:
25437471Ssklower 	case SIOCDIFADDR:
25537471Ssklower 		if (ifra->ifra_addr.sin_family == AF_INET)
25637471Ssklower 		    for (oia = ia; ia; ia = ia->ia_next) {
25737471Ssklower 			if (ia->ia_ifp == ifp  &&
25837471Ssklower 			    ia->ia_addr.sin_addr.s_addr ==
25937471Ssklower 				ifra->ifra_addr.sin_addr.s_addr)
26037471Ssklower 			    break;
26137471Ssklower 		}
26237471Ssklower 		if (cmd == SIOCDIFADDR && ia == 0)
26337471Ssklower 			return (EADDRNOTAVAIL);
26437471Ssklower 		/* FALLTHROUGH */
26518377Skarels 	case SIOCSIFADDR:
26618377Skarels 	case SIOCSIFNETMASK:
26726456Skarels 	case SIOCSIFDSTADDR:
26848464Skarels 		if ((so->so_state & SS_PRIV) == 0)
26948464Skarels 			return (EPERM);
27018377Skarels 
27118377Skarels 		if (ifp == 0)
27218377Skarels 			panic("in_control");
27318377Skarels 		if (ia == (struct in_ifaddr *)0) {
27452028Ssklower 			oia = (struct in_ifaddr *)
27552028Ssklower 				malloc(sizeof *oia, M_IFADDR, M_WAITOK);
27652028Ssklower 			if (oia == (struct in_ifaddr *)NULL)
27718377Skarels 				return (ENOBUFS);
27852028Ssklower 			bzero((caddr_t)oia, sizeof *oia);
27918377Skarels 			if (ia = in_ifaddr) {
28018377Skarels 				for ( ; ia->ia_next; ia = ia->ia_next)
28152915Storek 					continue;
28252028Ssklower 				ia->ia_next = oia;
28318377Skarels 			} else
28452028Ssklower 				in_ifaddr = oia;
28552028Ssklower 			ia = oia;
28618377Skarels 			if (ifa = ifp->if_addrlist) {
28718377Skarels 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
28852915Storek 					continue;
28918377Skarels 				ifa->ifa_next = (struct ifaddr *) ia;
29018377Skarels 			} else
29118377Skarels 				ifp->if_addrlist = (struct ifaddr *) ia;
29237471Ssklower 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
29337471Ssklower 			ia->ia_ifa.ifa_dstaddr
29437471Ssklower 					= (struct sockaddr *)&ia->ia_dstaddr;
29537471Ssklower 			ia->ia_ifa.ifa_netmask
29637471Ssklower 					= (struct sockaddr *)&ia->ia_sockmask;
29737471Ssklower 			ia->ia_sockmask.sin_len = 8;
29837471Ssklower 			if (ifp->if_flags & IFF_BROADCAST) {
29937471Ssklower 				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
30037471Ssklower 				ia->ia_broadaddr.sin_family = AF_INET;
30137471Ssklower 			}
30218377Skarels 			ia->ia_ifp = ifp;
30324805Skarels 			if (ifp != &loif)
30424805Skarels 				in_interfaces++;
30517271Skarels 		}
30618377Skarels 		break;
30726317Skarels 
30826317Skarels 	case SIOCSIFBRDADDR:
30948464Skarels 		if ((so->so_state & SS_PRIV) == 0)
31048464Skarels 			return (EPERM);
31126317Skarels 		/* FALLTHROUGH */
31226317Skarels 
31339183Ssklower 	case SIOCGIFADDR:
31439183Ssklower 	case SIOCGIFNETMASK:
31539183Ssklower 	case SIOCGIFDSTADDR:
31639183Ssklower 	case SIOCGIFBRDADDR:
31726317Skarels 		if (ia == (struct in_ifaddr *)0)
31826317Skarels 			return (EADDRNOTAVAIL);
31926317Skarels 		break;
32017271Skarels 	}
32118377Skarels 	switch (cmd) {
32218377Skarels 
32318377Skarels 	case SIOCGIFADDR:
32437471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
32518377Skarels 		break;
32618377Skarels 
32718377Skarels 	case SIOCGIFBRDADDR:
32818377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
32918377Skarels 			return (EINVAL);
33037471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
33118377Skarels 		break;
33218377Skarels 
33318377Skarels 	case SIOCGIFDSTADDR:
33418377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
33518377Skarels 			return (EINVAL);
33637471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
33718377Skarels 		break;
33818377Skarels 
33918377Skarels 	case SIOCGIFNETMASK:
34037471Ssklower 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
34118377Skarels 		break;
34218377Skarels 
34318377Skarels 	case SIOCSIFDSTADDR:
34418377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
34518377Skarels 			return (EINVAL);
34627066Skarels 		oldaddr = ia->ia_dstaddr;
34737471Ssklower 		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
34852619Ssklower 		if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
34952619Ssklower 					(ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
35027066Skarels 			ia->ia_dstaddr = oldaddr;
35118377Skarels 			return (error);
35227066Skarels 		}
35327066Skarels 		if (ia->ia_flags & IFA_ROUTE) {
35437471Ssklower 			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
35537471Ssklower 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
35645454Ssklower 			ia->ia_ifa.ifa_dstaddr =
35745454Ssklower 					(struct sockaddr *)&ia->ia_dstaddr;
35837471Ssklower 			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
35927066Skarels 		}
36018377Skarels 		break;
36118377Skarels 
36218377Skarels 	case SIOCSIFBRDADDR:
36318377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
36418377Skarels 			return (EINVAL);
36537471Ssklower 		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
36618377Skarels 		break;
36718377Skarels 
36818377Skarels 	case SIOCSIFADDR:
36934500Skarels 		return (in_ifinit(ifp, ia,
37037471Ssklower 		    (struct sockaddr_in *) &ifr->ifr_addr, 1));
37118377Skarels 
37218377Skarels 	case SIOCSIFNETMASK:
37337471Ssklower 		i = ifra->ifra_addr.sin_addr.s_addr;
37437471Ssklower 		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
37518377Skarels 		break;
37618377Skarels 
37737471Ssklower 	case SIOCAIFADDR:
37844368Skarels 		maskIsNew = 0;
37944368Skarels 		hostIsNew = 1;
38044368Skarels 		error = 0;
38137471Ssklower 		if (ia->ia_addr.sin_family == AF_INET) {
38237471Ssklower 			if (ifra->ifra_addr.sin_len == 0) {
38337471Ssklower 				ifra->ifra_addr = ia->ia_addr;
38437471Ssklower 				hostIsNew = 0;
38537471Ssklower 			} else if (ifra->ifra_addr.sin_addr.s_addr ==
38637471Ssklower 					       ia->ia_addr.sin_addr.s_addr)
38737471Ssklower 				hostIsNew = 0;
38837471Ssklower 		}
38937471Ssklower 		if (ifra->ifra_mask.sin_len) {
39037471Ssklower 			in_ifscrub(ifp, ia);
39137471Ssklower 			ia->ia_sockmask = ifra->ifra_mask;
39237471Ssklower 			ia->ia_subnetmask =
39344368Skarels 			     ntohl(ia->ia_sockmask.sin_addr.s_addr);
39437471Ssklower 			maskIsNew = 1;
39537471Ssklower 		}
39637471Ssklower 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
39737471Ssklower 		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
39837471Ssklower 			in_ifscrub(ifp, ia);
39937471Ssklower 			ia->ia_dstaddr = ifra->ifra_dstaddr;
40037471Ssklower 			maskIsNew  = 1; /* We lie; but the effect's the same */
40137471Ssklower 		}
40237471Ssklower 		if (ifra->ifra_addr.sin_family == AF_INET &&
40344368Skarels 		    (hostIsNew || maskIsNew))
40437471Ssklower 			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
40537471Ssklower 		if ((ifp->if_flags & IFF_BROADCAST) &&
40637471Ssklower 		    (ifra->ifra_broadaddr.sin_family == AF_INET))
40737471Ssklower 			ia->ia_broadaddr = ifra->ifra_broadaddr;
40837471Ssklower 		return (error);
40937471Ssklower 
41037471Ssklower 	case SIOCDIFADDR:
41137471Ssklower 		in_ifscrub(ifp, ia);
41237471Ssklower 		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
41337471Ssklower 			ifp->if_addrlist = ifa->ifa_next;
41437471Ssklower 		else {
41537471Ssklower 			while (ifa->ifa_next &&
41637471Ssklower 			       (ifa->ifa_next != (struct ifaddr *)ia))
41737471Ssklower 				    ifa = ifa->ifa_next;
41837471Ssklower 			if (ifa->ifa_next)
41944368Skarels 				ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
42037471Ssklower 			else
42137471Ssklower 				printf("Couldn't unlink inifaddr from ifp\n");
42237471Ssklower 		}
42337471Ssklower 		oia = ia;
42444368Skarels 		if (oia == (ia = in_ifaddr))
42537471Ssklower 			in_ifaddr = ia->ia_next;
42644368Skarels 		else {
42744368Skarels 			while (ia->ia_next && (ia->ia_next != oia))
42837471Ssklower 				ia = ia->ia_next;
42937471Ssklower 			if (ia->ia_next)
43044368Skarels 				ia->ia_next = oia->ia_next;
43137471Ssklower 			else
43237471Ssklower 				printf("Didn't unlink inifadr from list\n");
43337471Ssklower 		}
43452028Ssklower 		IFAFREE((&oia->ia_ifa));
43537471Ssklower 		break;
43637471Ssklower 
43718377Skarels 	default:
43818377Skarels 		if (ifp == 0 || ifp->if_ioctl == 0)
43918377Skarels 			return (EOPNOTSUPP);
44018377Skarels 		return ((*ifp->if_ioctl)(ifp, cmd, data));
44118377Skarels 	}
44217271Skarels 	return (0);
44317271Skarels }
44417271Skarels 
44517271Skarels /*
44637471Ssklower  * Delete any existing route for an interface.
44737471Ssklower  */
44837471Ssklower in_ifscrub(ifp, ia)
44937471Ssklower 	register struct ifnet *ifp;
45037471Ssklower 	register struct in_ifaddr *ia;
45137471Ssklower {
45237471Ssklower 
45337471Ssklower 	if ((ia->ia_flags & IFA_ROUTE) == 0)
45437471Ssklower 		return;
45537471Ssklower 	if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
45637471Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
45737471Ssklower 	else
45837471Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
45937471Ssklower 	ia->ia_flags &= ~IFA_ROUTE;
46037471Ssklower }
46137471Ssklower 
46237471Ssklower /*
46318377Skarels  * Initialize an interface's internet address
46418377Skarels  * and routing table entry.
4657159Ssam  */
46637471Ssklower in_ifinit(ifp, ia, sin, scrub)
4677159Ssam 	register struct ifnet *ifp;
46818377Skarels 	register struct in_ifaddr *ia;
46918377Skarels 	struct sockaddr_in *sin;
47052274Storek 	int scrub;
4717159Ssam {
47218377Skarels 	register u_long i = ntohl(sin->sin_addr.s_addr);
47337471Ssklower 	struct sockaddr_in oldaddr;
47454716Ssklower 	int s = splimp(), flags = RTF_UP, error, ether_output();
47554716Ssklower 	void arp_rtrequest();
4767159Ssam 
47727066Skarels 	oldaddr = ia->ia_addr;
47837471Ssklower 	ia->ia_addr = *sin;
47918377Skarels 	/*
48026317Skarels 	 * Give the interface a chance to initialize
48126317Skarels 	 * if this is its first address,
48226317Skarels 	 * and to validate the address if necessary.
48326317Skarels 	 */
48452274Storek 	if (ifp->if_ioctl &&
48552274Storek 	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
48626317Skarels 		splx(s);
48727066Skarels 		ia->ia_addr = oldaddr;
48826317Skarels 		return (error);
48926317Skarels 	}
49050134Ssklower 	if (ifp->if_output == ether_output) { /* XXX: Another Kludge */
49150134Ssklower 		ia->ia_ifa.ifa_rtrequest = arp_rtrequest;
49250134Ssklower 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
49350134Ssklower 	}
49445454Ssklower 	splx(s);
49537471Ssklower 	if (scrub) {
49637471Ssklower 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
49737471Ssklower 		in_ifscrub(ifp, ia);
49837471Ssklower 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
49918377Skarels 	}
50018377Skarels 	if (IN_CLASSA(i))
50118377Skarels 		ia->ia_netmask = IN_CLASSA_NET;
50218377Skarels 	else if (IN_CLASSB(i))
50318377Skarels 		ia->ia_netmask = IN_CLASSB_NET;
50418377Skarels 	else
50518377Skarels 		ia->ia_netmask = IN_CLASSC_NET;
50618377Skarels 	ia->ia_net = i & ia->ia_netmask;
50718377Skarels 	/*
50818377Skarels 	 * The subnet mask includes at least the standard network part,
50918377Skarels 	 * but may already have been set to a larger value.
51018377Skarels 	 */
51118377Skarels 	ia->ia_subnetmask |= ia->ia_netmask;
51218377Skarels 	ia->ia_subnet = i & ia->ia_subnetmask;
51337471Ssklower 	ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
51439183Ssklower 	{
51539183Ssklower 		register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
51639183Ssklower 		register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
51739183Ssklower 		while (--cp >= cpbase)
51839183Ssklower 			if (*cp) {
51939183Ssklower 				ia->ia_sockmask.sin_len =
52039183Ssklower 					1 + cp - (char *) &(ia->ia_sockmask);
52139183Ssklower 				break;
52239183Ssklower 			}
52339183Ssklower 	}
52445454Ssklower 	/*
52545454Ssklower 	 * Add route for the network.
52645454Ssklower 	 */
52752617Ssklower 	ia->ia_ifa.ifa_metric = ifp->if_metric;
52818377Skarels 	if (ifp->if_flags & IFF_BROADCAST) {
52937471Ssklower 		ia->ia_broadaddr.sin_addr =
53018377Skarels 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
53125195Skarels 		ia->ia_netbroadcast.s_addr =
53225195Skarels 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
53345454Ssklower 	} else if (ifp->if_flags & IFF_LOOPBACK) {
53437471Ssklower 		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
53545454Ssklower 		flags |= RTF_HOST;
53645454Ssklower 	} else if (ifp->if_flags & IFF_POINTOPOINT) {
53745454Ssklower 		if (ia->ia_dstaddr.sin_family != AF_INET)
53845454Ssklower 			return (0);
53945454Ssklower 		flags |= RTF_HOST;
54027066Skarels 	}
54145454Ssklower 	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
54245454Ssklower 		ia->ia_flags |= IFA_ROUTE;
54354716Ssklower #ifdef MULTICAST
54454716Ssklower 	/*
54554716Ssklower 	 * If the interface supports multicast, join the "all hosts"
54654716Ssklower 	 * multicast group on that interface.
54754716Ssklower 	 */
54854716Ssklower 	if (ifp->if_flags & IFF_MULTICAST) {
54954716Ssklower 		struct in_addr addr;
55054716Ssklower 
55154716Ssklower 		addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
55254716Ssklower 		in_addmulti(&addr, ifp);
55354716Ssklower 	}
55454716Ssklower #endif
55545454Ssklower 	return (error);
5567159Ssam }
55718377Skarels 
55818377Skarels /*
55918377Skarels  * Return address info for specified internet network.
56018377Skarels  */
56118377Skarels struct in_ifaddr *
56218377Skarels in_iaonnetof(net)
56318377Skarels 	u_long net;
56418377Skarels {
56518377Skarels 	register struct in_ifaddr *ia;
56618377Skarels 
56718377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
56818377Skarels 		if (ia->ia_subnet == net)
56918377Skarels 			return (ia);
57018377Skarels 	return ((struct in_ifaddr *)0);
57118377Skarels }
57218377Skarels 
57318377Skarels /*
57430523Skarels  * Return 1 if the address might be a local broadcast address.
57518377Skarels  */
57618377Skarels in_broadcast(in)
57718377Skarels 	struct in_addr in;
57818377Skarels {
57918377Skarels 	register struct in_ifaddr *ia;
58030523Skarels 	u_long t;
58118377Skarels 
58218377Skarels 	/*
58318377Skarels 	 * Look through the list of addresses for a match
58418377Skarels 	 * with a broadcast address.
58518377Skarels 	 */
58618377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
58730523Skarels 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
58837471Ssklower 		if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
58918377Skarels 		     return (1);
59030523Skarels 		/*
59130523Skarels 		 * Check for old-style (host 0) broadcast.
59230523Skarels 		 */
59330523Skarels 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
59430523Skarels 		    return (1);
59530523Skarels 	}
59630523Skarels 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
59730523Skarels 		return (1);
59818377Skarels 	return (0);
59918377Skarels }
60054716Ssklower 
60154716Ssklower #ifdef MULTICAST
60254716Ssklower /*
60354716Ssklower  * Add an address to the list of IP multicast addresses for a given interface.
60454716Ssklower  */
60554716Ssklower struct in_multi *
60654716Ssklower in_addmulti(ap, ifp)
60754716Ssklower 	register struct in_addr *ap;
60854716Ssklower 	register struct ifnet *ifp;
60954716Ssklower {
61054716Ssklower 	register struct in_multi *inm;
61154716Ssklower 	struct ifreq ifr;
61254716Ssklower 	struct in_ifaddr *ia;
61354716Ssklower 	int s = splnet();
61454716Ssklower int error;
61554716Ssklower 
61654716Ssklower 	/*
61754716Ssklower 	 * See if address already in list.
61854716Ssklower 	 */
61954716Ssklower 	IN_LOOKUP_MULTI(*ap, ifp, inm);
62054716Ssklower 	if (inm != NULL) {
62154716Ssklower 		/*
62254716Ssklower 		 * Found it; just increment the reference count.
62354716Ssklower 		 */
62454716Ssklower 		++inm->inm_refcount;
62554716Ssklower 	}
62654716Ssklower 	else {
62754716Ssklower 		/*
62854716Ssklower 		 * New address; allocate a new multicast record
62954716Ssklower 		 * and link it into the interface's multicast list.
63054716Ssklower 		 */
63154716Ssklower 		inm = (struct in_multi *)malloc(sizeof(*inm),
63254716Ssklower 		    M_IPMADDR, M_NOWAIT);
63354716Ssklower 		if (inm == NULL) {
63454716Ssklower 			splx(s);
63554716Ssklower 			return (NULL);
63654716Ssklower 		}
63754716Ssklower 		inm->inm_addr = *ap;
63854716Ssklower 		inm->inm_ifp = ifp;
63954716Ssklower 		inm->inm_refcount = 1;
64054716Ssklower 		IFP_TO_IA(ifp, ia);
64154716Ssklower 		if (ia == NULL) {
64254716Ssklower 			free(inm, M_IPMADDR);
64354716Ssklower 			splx(s);
64454716Ssklower 			return (NULL);
64554716Ssklower 		}
64654716Ssklower 		inm->inm_ia = ia;
64754716Ssklower 		inm->inm_next = ia->ia_multiaddrs;
64854716Ssklower 		ia->ia_multiaddrs = inm;
64954716Ssklower 		/*
65054716Ssklower 		 * Ask the network driver to update its multicast reception
65154716Ssklower 		 * filter appropriately for the new address.
65254716Ssklower 		 */
65354716Ssklower 		((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
65454716Ssklower 		((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
65554716Ssklower 		if (ifp->if_ioctl == NULL) {
65654716Ssklower 			free(inm, M_IPMADDR);
65754716Ssklower 			splx(s);
65854716Ssklower 			return (NULL);
65954716Ssklower 		}
66054716Ssklower 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr);
66154716Ssklower 		if (error != 0) {
66254716Ssklower 			free(inm, M_IPMADDR);
66354716Ssklower 			splx(s);
66454716Ssklower 			return (NULL);
66554716Ssklower 		}
66654716Ssklower 		/*
66754716Ssklower 		 * Let IGMP know that we have joined a new IP multicast group.
66854716Ssklower 		 */
66954716Ssklower 		igmp_joingroup(inm);
67054716Ssklower 	}
67154716Ssklower 	splx(s);
67254716Ssklower 	return (inm);
67354716Ssklower }
67454716Ssklower 
67554716Ssklower /*
67654716Ssklower  * Delete a multicast address record.
67754716Ssklower  */
67854716Ssklower int
67954716Ssklower in_delmulti(inm)
68054716Ssklower 	register struct in_multi *inm;
68154716Ssklower {
68254716Ssklower 	register struct in_multi **p;
68354716Ssklower 	struct ifreq ifr;
68454716Ssklower 	int s = splnet();
68554716Ssklower 
68654716Ssklower 	if (--inm->inm_refcount == 0) {
68754716Ssklower 		/*
68854716Ssklower 		 * No remaining claims to this record; let IGMP know that
68954716Ssklower 		 * we are leaving the multicast group.
69054716Ssklower 		 */
69154716Ssklower 		igmp_leavegroup(inm);
69254716Ssklower 		/*
69354716Ssklower 		 * Unlink from list.
69454716Ssklower 		 */
69554716Ssklower 		for (p = &inm->inm_ia->ia_multiaddrs;
69654716Ssklower 		     *p != inm;
69754716Ssklower 		     p = &(*p)->inm_next)
69854716Ssklower 			 continue;
69954716Ssklower 		*p = (*p)->inm_next;
70054716Ssklower 		/*
70154716Ssklower 		 * Notify the network driver to update its multicast reception
70254716Ssklower 		 * filter.
70354716Ssklower 		 */
70454716Ssklower 		((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
70554716Ssklower 		((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
70654716Ssklower 								inm->inm_addr;
70754716Ssklower 		(*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
70854716Ssklower 							     (caddr_t)&ifr);
70954716Ssklower 		free(inm, M_IPMADDR);
71054716Ssklower 	}
71154716Ssklower 	splx(s);
71254716Ssklower }
7137159Ssam #endif
71454716Ssklower #endif
715