xref: /csrg-svn/sys/netinet/in.c (revision 31392)
123175Smckusick /*
229136Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323175Smckusick  * All rights reserved.  The Berkeley software License Agreement
423175Smckusick  * specifies the terms and conditions for redistribution.
523175Smckusick  *
6*31392Skarels  *	@(#)in.c	7.5 (Berkeley) 06/04/87
723175Smckusick  */
87159Ssam 
917058Sbloom #include "param.h"
1018377Skarels #include "ioctl.h"
1117058Sbloom #include "mbuf.h"
1217058Sbloom #include "protosw.h"
1317058Sbloom #include "socket.h"
1417058Sbloom #include "socketvar.h"
1518377Skarels #include "uio.h"
1618377Skarels #include "dir.h"
1718377Skarels #include "user.h"
1817058Sbloom #include "in_systm.h"
197166Ssam #include "../net/if.h"
207166Ssam #include "../net/route.h"
217159Ssam #include "../net/af.h"
2218377Skarels #include "in.h"
2318377Skarels #include "in_var.h"
247159Ssam 
257159Ssam #ifdef INET
267159Ssam inet_hash(sin, hp)
277159Ssam 	register struct sockaddr_in *sin;
287159Ssam 	struct afhash *hp;
297159Ssam {
3018377Skarels 	register u_long n;
318595Sroot 
3218377Skarels 	n = in_netof(sin->sin_addr);
3318377Skarels 	if (n)
3418377Skarels 	    while ((n & 0xff) == 0)
3518377Skarels 		n >>= 8;
3618377Skarels 	hp->afh_nethash = n;
378937Sroot 	hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
387159Ssam }
397159Ssam 
407159Ssam inet_netmatch(sin1, sin2)
417159Ssam 	struct sockaddr_in *sin1, *sin2;
427159Ssam {
438595Sroot 
4411566Ssam 	return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr));
457159Ssam }
467159Ssam 
477159Ssam /*
4818377Skarels  * Formulate an Internet address from network + host.
497159Ssam  */
507159Ssam struct in_addr
5118377Skarels in_makeaddr(net, host)
5218377Skarels 	u_long net, host;
537159Ssam {
5418377Skarels 	register struct in_ifaddr *ia;
5518377Skarels 	register u_long mask;
567159Ssam 	u_long addr;
577159Ssam 
5818377Skarels 	if (IN_CLASSA(net))
5918377Skarels 		mask = IN_CLASSA_HOST;
6018377Skarels 	else if (IN_CLASSB(net))
6118377Skarels 		mask = IN_CLASSB_HOST;
627159Ssam 	else
6318377Skarels 		mask = IN_CLASSC_HOST;
6418377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
6518377Skarels 		if ((ia->ia_netmask & net) == ia->ia_net) {
6618377Skarels 			mask = ~ia->ia_subnetmask;
6718377Skarels 			break;
6818377Skarels 		}
6918377Skarels 	addr = htonl(net | (host & mask));
707159Ssam 	return (*(struct in_addr *)&addr);
717159Ssam }
727159Ssam 
737159Ssam /*
748595Sroot  * Return the network number from an internet address.
757159Ssam  */
7624805Skarels u_long
777159Ssam in_netof(in)
787159Ssam 	struct in_addr in;
797159Ssam {
808937Sroot 	register u_long i = ntohl(in.s_addr);
8118377Skarels 	register u_long net;
8218377Skarels 	register struct in_ifaddr *ia;
837159Ssam 
8418377Skarels 	if (IN_CLASSA(i))
8518377Skarels 		net = i & IN_CLASSA_NET;
8618377Skarels 	else if (IN_CLASSB(i))
8718377Skarels 		net = i & IN_CLASSB_NET;
88*31392Skarels 	else if (IN_CLASSC(i))
89*31392Skarels 		net = i & IN_CLASSC_NET;
9018377Skarels 	else
91*31392Skarels 		return (0);
9216413Skarels 
9316413Skarels 	/*
9418377Skarels 	 * Check whether network is a subnet;
9516413Skarels 	 * if so, return subnet number.
9616413Skarels 	 */
9718377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
9824805Skarels 		if (net == ia->ia_net)
9918377Skarels 			return (i & ia->ia_subnetmask);
10016413Skarels 	return (net);
1017159Ssam }
1027159Ssam 
1037159Ssam /*
1048595Sroot  * Return the host portion of an internet address.
1057159Ssam  */
10626381Skarels u_long
1077159Ssam in_lnaof(in)
1087159Ssam 	struct in_addr in;
1097159Ssam {
1108937Sroot 	register u_long i = ntohl(in.s_addr);
11118377Skarels 	register u_long net, host;
11218377Skarels 	register struct in_ifaddr *ia;
1137159Ssam 
11416377Skarels 	if (IN_CLASSA(i)) {
11518377Skarels 		net = i & IN_CLASSA_NET;
11618377Skarels 		host = i & IN_CLASSA_HOST;
11716377Skarels 	} else if (IN_CLASSB(i)) {
11818377Skarels 		net = i & IN_CLASSB_NET;
11918377Skarels 		host = i & IN_CLASSB_HOST;
120*31392Skarels 	} else if (IN_CLASSC(i)) {
12118377Skarels 		net = i & IN_CLASSC_NET;
12218377Skarels 		host = i & IN_CLASSC_HOST;
123*31392Skarels 	} else
124*31392Skarels 		return (i);
1257159Ssam 
12616413Skarels 	/*
12718377Skarels 	 * Check whether network is a subnet;
12816413Skarels 	 * if so, use the modified interpretation of `host'.
12916413Skarels 	 */
13018377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
13124805Skarels 		if (net == ia->ia_net)
13218377Skarels 			return (host &~ ia->ia_subnetmask);
13316413Skarels 	return (host);
13416377Skarels }
13516377Skarels 
13626381Skarels #ifndef SUBNETSARELOCAL
13726381Skarels #define	SUBNETSARELOCAL	1
13826381Skarels #endif
13926381Skarels int subnetsarelocal = SUBNETSARELOCAL;
14016377Skarels /*
14118377Skarels  * Return 1 if an internet address is for a ``local'' host
14226381Skarels  * (one to which we have a connection).  If subnetsarelocal
14326381Skarels  * is true, this includes other subnets of the local net.
14426381Skarels  * Otherwise, it includes only the directly-connected (sub)nets.
14517271Skarels  */
14617271Skarels in_localaddr(in)
14717271Skarels 	struct in_addr in;
14817271Skarels {
14917271Skarels 	register u_long i = ntohl(in.s_addr);
15018377Skarels 	register struct in_ifaddr *ia;
15117271Skarels 
15230697Skarels 	if (subnetsarelocal) {
15330697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
15430697Skarels 			if ((i & ia->ia_netmask) == ia->ia_net)
15530697Skarels 				return (1);
15630697Skarels 	} else {
15730697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
15830697Skarels 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
15930697Skarels 				return (1);
16030697Skarels 	}
16118377Skarels 	return (0);
16218377Skarels }
16318377Skarels 
164*31392Skarels /*
165*31392Skarels  * Determine whether an IP address is in a reserved set of addresses
166*31392Skarels  * that may not be forwarded, or whether datagrams to that destination
167*31392Skarels  * may be forwarded.
168*31392Skarels  */
169*31392Skarels in_canforward(in)
170*31392Skarels 	struct in_addr in;
171*31392Skarels {
172*31392Skarels 	register u_long i = ntohl(in.s_addr);
173*31392Skarels 	register u_long net;
174*31392Skarels 
175*31392Skarels 	if (IN_EXPERIMENTAL(i))
176*31392Skarels 		return (0);
177*31392Skarels 	if (IN_CLASSA(i)) {
178*31392Skarels 		net = i & IN_CLASSA_NET;
179*31392Skarels 		if (net == 0 || net == IN_LOOPBACKNET)
180*31392Skarels 			return (0);
181*31392Skarels 	}
182*31392Skarels 	return (1);
183*31392Skarels }
184*31392Skarels 
18524805Skarels int	in_interfaces;		/* number of external internet interfaces */
18624805Skarels extern	struct ifnet loif;
18724805Skarels 
18818377Skarels /*
18918377Skarels  * Generic internet control operations (ioctl's).
19018377Skarels  * Ifp is 0 if not an interface-specific ioctl.
19118377Skarels  */
19224805Skarels /* ARGSUSED */
19318377Skarels in_control(so, cmd, data, ifp)
19418377Skarels 	struct socket *so;
19518377Skarels 	int cmd;
19618377Skarels 	caddr_t data;
19718377Skarels 	register struct ifnet *ifp;
19818377Skarels {
19918377Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
20018377Skarels 	register struct in_ifaddr *ia = 0;
20125195Skarels 	u_long tmp;
20218377Skarels 	struct ifaddr *ifa;
20318377Skarels 	struct mbuf *m;
20418377Skarels 	int error;
20518377Skarels 
20618377Skarels 	/*
20718377Skarels 	 * Find address for this interface, if it exists.
20818377Skarels 	 */
20918377Skarels 	if (ifp)
21018377Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
21118377Skarels 			if (ia->ia_ifp == ifp)
21218377Skarels 				break;
21318377Skarels 
21418377Skarels 	switch (cmd) {
21518377Skarels 
21618377Skarels 	case SIOCSIFADDR:
21718377Skarels 	case SIOCSIFNETMASK:
21826456Skarels 	case SIOCSIFDSTADDR:
21918377Skarels 		if (!suser())
22018377Skarels 			return (u.u_error);
22118377Skarels 
22218377Skarels 		if (ifp == 0)
22318377Skarels 			panic("in_control");
22418377Skarels 		if (ia == (struct in_ifaddr *)0) {
22518377Skarels 			m = m_getclr(M_WAIT, MT_IFADDR);
22618377Skarels 			if (m == (struct mbuf *)NULL)
22718377Skarels 				return (ENOBUFS);
22818377Skarels 			if (ia = in_ifaddr) {
22918377Skarels 				for ( ; ia->ia_next; ia = ia->ia_next)
23018377Skarels 					;
23118377Skarels 				ia->ia_next = mtod(m, struct in_ifaddr *);
23218377Skarels 			} else
23318377Skarels 				in_ifaddr = mtod(m, struct in_ifaddr *);
23418377Skarels 			ia = mtod(m, struct in_ifaddr *);
23518377Skarels 			if (ifa = ifp->if_addrlist) {
23618377Skarels 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
23718377Skarels 					;
23818377Skarels 				ifa->ifa_next = (struct ifaddr *) ia;
23918377Skarels 			} else
24018377Skarels 				ifp->if_addrlist = (struct ifaddr *) ia;
24118377Skarels 			ia->ia_ifp = ifp;
24218377Skarels 			IA_SIN(ia)->sin_family = AF_INET;
24324805Skarels 			if (ifp != &loif)
24424805Skarels 				in_interfaces++;
24517271Skarels 		}
24618377Skarels 		break;
24726317Skarels 
24826317Skarels 	case SIOCSIFBRDADDR:
24926317Skarels 		if (!suser())
25026317Skarels 			return (u.u_error);
25126317Skarels 		/* FALLTHROUGH */
25226317Skarels 
25326317Skarels 	default:
25426317Skarels 		if (ia == (struct in_ifaddr *)0)
25526317Skarels 			return (EADDRNOTAVAIL);
25626317Skarels 		break;
25717271Skarels 	}
25818377Skarels 
25918377Skarels 	switch (cmd) {
26018377Skarels 
26118377Skarels 	case SIOCGIFADDR:
26218377Skarels 		ifr->ifr_addr = ia->ia_addr;
26318377Skarels 		break;
26418377Skarels 
26518377Skarels 	case SIOCGIFBRDADDR:
26618377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
26718377Skarels 			return (EINVAL);
26818377Skarels 		ifr->ifr_dstaddr = ia->ia_broadaddr;
26918377Skarels 		break;
27018377Skarels 
27118377Skarels 	case SIOCGIFDSTADDR:
27218377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
27318377Skarels 			return (EINVAL);
27418377Skarels 		ifr->ifr_dstaddr = ia->ia_dstaddr;
27518377Skarels 		break;
27618377Skarels 
27718377Skarels 	case SIOCGIFNETMASK:
27818377Skarels #define	satosin(sa)	((struct sockaddr_in *)(sa))
27918377Skarels 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
28018377Skarels 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
28118377Skarels 		break;
28218377Skarels 
28318377Skarels 	case SIOCSIFDSTADDR:
28427066Skarels 	    {
28527066Skarels 		struct sockaddr oldaddr;
28627066Skarels 
28718377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
28818377Skarels 			return (EINVAL);
28927066Skarels 		oldaddr = ia->ia_dstaddr;
29027066Skarels 		ia->ia_dstaddr = ifr->ifr_dstaddr;
29118377Skarels 		if (ifp->if_ioctl &&
29227066Skarels 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
29327066Skarels 			ia->ia_dstaddr = oldaddr;
29418377Skarels 			return (error);
29527066Skarels 		}
29627066Skarels 		if (ia->ia_flags & IFA_ROUTE) {
29727066Skarels 			rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
29827066Skarels 			    RTF_HOST);
29927066Skarels 			rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
30027066Skarels 			    RTF_HOST|RTF_UP);
30127066Skarels 		}
30227066Skarels 	    }
30318377Skarels 		break;
30418377Skarels 
30518377Skarels 	case SIOCSIFBRDADDR:
30618377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
30718377Skarels 			return (EINVAL);
30818377Skarels 		ia->ia_broadaddr = ifr->ifr_broadaddr;
30925195Skarels 		tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
31025195Skarels 		if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
31125195Skarels 			tmp |= ~ia->ia_netmask;
31225195Skarels 		else if ((tmp &~ ia->ia_subnetmask) == 0)
31325195Skarels 			tmp &= ia->ia_netmask;
31425195Skarels 		ia->ia_netbroadcast.s_addr = htonl(tmp);
31518377Skarels 		break;
31618377Skarels 
31718377Skarels 	case SIOCSIFADDR:
31818377Skarels 		return (in_ifinit(ifp, ia, &ifr->ifr_addr));
31918377Skarels 
32018377Skarels 	case SIOCSIFNETMASK:
32118377Skarels 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
32218377Skarels 		break;
32318377Skarels 
32418377Skarels 	default:
32518377Skarels 		if (ifp == 0 || ifp->if_ioctl == 0)
32618377Skarels 			return (EOPNOTSUPP);
32718377Skarels 		return ((*ifp->if_ioctl)(ifp, cmd, data));
32818377Skarels 	}
32917271Skarels 	return (0);
33017271Skarels }
33117271Skarels 
33217271Skarels /*
33318377Skarels  * Initialize an interface's internet address
33418377Skarels  * and routing table entry.
3357159Ssam  */
33618377Skarels in_ifinit(ifp, ia, sin)
3377159Ssam 	register struct ifnet *ifp;
33818377Skarels 	register struct in_ifaddr *ia;
33918377Skarels 	struct sockaddr_in *sin;
3407159Ssam {
34118377Skarels 	register u_long i = ntohl(sin->sin_addr.s_addr);
34227066Skarels 	struct sockaddr oldaddr;
34327066Skarels 	struct sockaddr_in netaddr;
34418377Skarels 	int s = splimp(), error;
3457159Ssam 
34627066Skarels 	oldaddr = ia->ia_addr;
34726317Skarels 	ia->ia_addr = *(struct sockaddr *)sin;
34826317Skarels 
34918377Skarels 	/*
35026317Skarels 	 * Give the interface a chance to initialize
35126317Skarels 	 * if this is its first address,
35226317Skarels 	 * and to validate the address if necessary.
35326317Skarels 	 */
35426317Skarels 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
35526317Skarels 		splx(s);
35627066Skarels 		ia->ia_addr = oldaddr;
35726317Skarels 		return (error);
35826317Skarels 	}
35926317Skarels 
36026317Skarels 	/*
36118377Skarels 	 * Delete any previous route for an old address.
36218377Skarels 	 */
36327066Skarels 	bzero((caddr_t)&netaddr, sizeof (netaddr));
36427066Skarels 	netaddr.sin_family = AF_INET;
36518377Skarels 	if (ia->ia_flags & IFA_ROUTE) {
36627066Skarels 		if (ifp->if_flags & IFF_LOOPBACK)
36727066Skarels 			rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
36827066Skarels 		else if (ifp->if_flags & IFF_POINTOPOINT)
36927066Skarels 			rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
37027066Skarels 			    RTF_HOST);
37127066Skarels 		else {
37227066Skarels 			netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
37327066Skarels 			    INADDR_ANY);
37427066Skarels 			rtinit((struct sockaddr *)&netaddr, &oldaddr,
37525452Ssklower 			    (int)SIOCDELRT, 0);
37627066Skarels 		}
37718377Skarels 		ia->ia_flags &= ~IFA_ROUTE;
37818377Skarels 	}
37918377Skarels 	if (IN_CLASSA(i))
38018377Skarels 		ia->ia_netmask = IN_CLASSA_NET;
38118377Skarels 	else if (IN_CLASSB(i))
38218377Skarels 		ia->ia_netmask = IN_CLASSB_NET;
38318377Skarels 	else
38418377Skarels 		ia->ia_netmask = IN_CLASSC_NET;
38518377Skarels 	ia->ia_net = i & ia->ia_netmask;
38618377Skarels 	/*
38718377Skarels 	 * The subnet mask includes at least the standard network part,
38818377Skarels 	 * but may already have been set to a larger value.
38918377Skarels 	 */
39018377Skarels 	ia->ia_subnetmask |= ia->ia_netmask;
39118377Skarels 	ia->ia_subnet = i & ia->ia_subnetmask;
39218377Skarels 	if (ifp->if_flags & IFF_BROADCAST) {
39318377Skarels 		ia->ia_broadaddr.sa_family = AF_INET;
39418377Skarels 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
39518377Skarels 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
39625195Skarels 		ia->ia_netbroadcast.s_addr =
39725195Skarels 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
39818377Skarels 	}
39918377Skarels 	/*
40018377Skarels 	 * Add route for the network.
40118377Skarels 	 */
40227066Skarels 	if (ifp->if_flags & IFF_LOOPBACK)
40327066Skarels 		rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
40427066Skarels 		    RTF_HOST|RTF_UP);
40527066Skarels 	else if (ifp->if_flags & IFF_POINTOPOINT)
40627066Skarels 		rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
40727066Skarels 		    RTF_HOST|RTF_UP);
40827066Skarels 	else {
40927066Skarels 		netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
41027066Skarels 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
41127066Skarels 		    (int)SIOCADDRT, RTF_UP);
41227066Skarels 	}
41318377Skarels 	ia->ia_flags |= IFA_ROUTE;
41430523Skarels 	splx(s);
41518642Skarels 	return (0);
4167159Ssam }
41718377Skarels 
41818377Skarels /*
41918377Skarels  * Return address info for specified internet network.
42018377Skarels  */
42118377Skarels struct in_ifaddr *
42218377Skarels in_iaonnetof(net)
42318377Skarels 	u_long net;
42418377Skarels {
42518377Skarels 	register struct in_ifaddr *ia;
42618377Skarels 
42718377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
42818377Skarels 		if (ia->ia_subnet == net)
42918377Skarels 			return (ia);
43018377Skarels 	return ((struct in_ifaddr *)0);
43118377Skarels }
43218377Skarels 
43318377Skarels /*
43430523Skarels  * Return 1 if the address might be a local broadcast address.
43518377Skarels  */
43618377Skarels in_broadcast(in)
43718377Skarels 	struct in_addr in;
43818377Skarels {
43918377Skarels 	register struct in_ifaddr *ia;
44030523Skarels 	u_long t;
44118377Skarels 
44218377Skarels 	/*
44318377Skarels 	 * Look through the list of addresses for a match
44418377Skarels 	 * with a broadcast address.
44518377Skarels 	 */
44618377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
44730523Skarels 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
44830523Skarels 		if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
44918377Skarels 		     return (1);
45030523Skarels 		/*
45130523Skarels 		 * Check for old-style (host 0) broadcast.
45230523Skarels 		 */
45330523Skarels 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
45430523Skarels 		    return (1);
45530523Skarels 	}
45630523Skarels 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
45730523Skarels 		return (1);
45818377Skarels 	return (0);
45918377Skarels }
4607159Ssam #endif
461