xref: /csrg-svn/sys/netinet/in.c (revision 34854)
123175Smckusick /*
229136Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
332787Sbostic  * All rights reserved.
423175Smckusick  *
532787Sbostic  * Redistribution and use in source and binary forms are permitted
6*34854Sbostic  * provided that the above copyright notice and this paragraph are
7*34854Sbostic  * duplicated in all such forms and that any documentation,
8*34854Sbostic  * advertising materials, and other materials related to such
9*34854Sbostic  * distribution and use acknowledge that the software was developed
10*34854Sbostic  * by the University of California, Berkeley.  The name of the
11*34854Sbostic  * University may not be used to endorse or promote products derived
12*34854Sbostic  * from this software without specific prior written permission.
13*34854Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34854Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34854Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1632787Sbostic  *
17*34854Sbostic  *	@(#)in.c	7.9 (Berkeley) 06/29/88
1823175Smckusick  */
197159Ssam 
2017058Sbloom #include "param.h"
2118377Skarels #include "ioctl.h"
2217058Sbloom #include "mbuf.h"
2317058Sbloom #include "protosw.h"
2417058Sbloom #include "socket.h"
2517058Sbloom #include "socketvar.h"
2618377Skarels #include "uio.h"
2718377Skarels #include "dir.h"
2818377Skarels #include "user.h"
2917058Sbloom #include "in_systm.h"
307166Ssam #include "../net/if.h"
317166Ssam #include "../net/route.h"
327159Ssam #include "../net/af.h"
3318377Skarels #include "in.h"
3418377Skarels #include "in_var.h"
357159Ssam 
367159Ssam #ifdef INET
377159Ssam inet_hash(sin, hp)
387159Ssam 	register struct sockaddr_in *sin;
397159Ssam 	struct afhash *hp;
407159Ssam {
4118377Skarels 	register u_long n;
428595Sroot 
4318377Skarels 	n = in_netof(sin->sin_addr);
4418377Skarels 	if (n)
4518377Skarels 	    while ((n & 0xff) == 0)
4618377Skarels 		n >>= 8;
4718377Skarels 	hp->afh_nethash = n;
488937Sroot 	hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
497159Ssam }
507159Ssam 
517159Ssam inet_netmatch(sin1, sin2)
527159Ssam 	struct sockaddr_in *sin1, *sin2;
537159Ssam {
548595Sroot 
5511566Ssam 	return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr));
567159Ssam }
577159Ssam 
587159Ssam /*
5918377Skarels  * Formulate an Internet address from network + host.
607159Ssam  */
617159Ssam struct in_addr
6218377Skarels in_makeaddr(net, host)
6318377Skarels 	u_long net, host;
647159Ssam {
6518377Skarels 	register struct in_ifaddr *ia;
6618377Skarels 	register u_long mask;
677159Ssam 	u_long addr;
687159Ssam 
6918377Skarels 	if (IN_CLASSA(net))
7018377Skarels 		mask = IN_CLASSA_HOST;
7118377Skarels 	else if (IN_CLASSB(net))
7218377Skarels 		mask = IN_CLASSB_HOST;
737159Ssam 	else
7418377Skarels 		mask = IN_CLASSC_HOST;
7518377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
7618377Skarels 		if ((ia->ia_netmask & net) == ia->ia_net) {
7718377Skarels 			mask = ~ia->ia_subnetmask;
7818377Skarels 			break;
7918377Skarels 		}
8018377Skarels 	addr = htonl(net | (host & mask));
817159Ssam 	return (*(struct in_addr *)&addr);
827159Ssam }
837159Ssam 
847159Ssam /*
858595Sroot  * Return the network number from an internet address.
867159Ssam  */
8724805Skarels u_long
887159Ssam in_netof(in)
897159Ssam 	struct in_addr in;
907159Ssam {
918937Sroot 	register u_long i = ntohl(in.s_addr);
9218377Skarels 	register u_long net;
9318377Skarels 	register struct in_ifaddr *ia;
947159Ssam 
9518377Skarels 	if (IN_CLASSA(i))
9618377Skarels 		net = i & IN_CLASSA_NET;
9718377Skarels 	else if (IN_CLASSB(i))
9818377Skarels 		net = i & IN_CLASSB_NET;
9931392Skarels 	else if (IN_CLASSC(i))
10031392Skarels 		net = i & IN_CLASSC_NET;
10118377Skarels 	else
10231392Skarels 		return (0);
10316413Skarels 
10416413Skarels 	/*
10518377Skarels 	 * Check whether network is a subnet;
10616413Skarels 	 * if so, return subnet number.
10716413Skarels 	 */
10818377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
10924805Skarels 		if (net == ia->ia_net)
11018377Skarels 			return (i & ia->ia_subnetmask);
11116413Skarels 	return (net);
1127159Ssam }
1137159Ssam 
1147159Ssam /*
1158595Sroot  * Return the host portion of an internet address.
1167159Ssam  */
11726381Skarels u_long
1187159Ssam in_lnaof(in)
1197159Ssam 	struct in_addr in;
1207159Ssam {
1218937Sroot 	register u_long i = ntohl(in.s_addr);
12218377Skarels 	register u_long net, host;
12318377Skarels 	register struct in_ifaddr *ia;
1247159Ssam 
12516377Skarels 	if (IN_CLASSA(i)) {
12618377Skarels 		net = i & IN_CLASSA_NET;
12718377Skarels 		host = i & IN_CLASSA_HOST;
12816377Skarels 	} else if (IN_CLASSB(i)) {
12918377Skarels 		net = i & IN_CLASSB_NET;
13018377Skarels 		host = i & IN_CLASSB_HOST;
13131392Skarels 	} else if (IN_CLASSC(i)) {
13218377Skarels 		net = i & IN_CLASSC_NET;
13318377Skarels 		host = i & IN_CLASSC_HOST;
13431392Skarels 	} else
13531392Skarels 		return (i);
1367159Ssam 
13716413Skarels 	/*
13818377Skarels 	 * Check whether network is a subnet;
13916413Skarels 	 * if so, use the modified interpretation of `host'.
14016413Skarels 	 */
14118377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
14224805Skarels 		if (net == ia->ia_net)
14318377Skarels 			return (host &~ ia->ia_subnetmask);
14416413Skarels 	return (host);
14516377Skarels }
14616377Skarels 
14726381Skarels #ifndef SUBNETSARELOCAL
14826381Skarels #define	SUBNETSARELOCAL	1
14926381Skarels #endif
15026381Skarels int subnetsarelocal = SUBNETSARELOCAL;
15116377Skarels /*
15218377Skarels  * Return 1 if an internet address is for a ``local'' host
15326381Skarels  * (one to which we have a connection).  If subnetsarelocal
15426381Skarels  * is true, this includes other subnets of the local net.
15526381Skarels  * Otherwise, it includes only the directly-connected (sub)nets.
15617271Skarels  */
15717271Skarels in_localaddr(in)
15817271Skarels 	struct in_addr in;
15917271Skarels {
16017271Skarels 	register u_long i = ntohl(in.s_addr);
16118377Skarels 	register struct in_ifaddr *ia;
16217271Skarels 
16330697Skarels 	if (subnetsarelocal) {
16430697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
16530697Skarels 			if ((i & ia->ia_netmask) == ia->ia_net)
16630697Skarels 				return (1);
16730697Skarels 	} else {
16830697Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
16930697Skarels 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
17030697Skarels 				return (1);
17130697Skarels 	}
17218377Skarels 	return (0);
17318377Skarels }
17418377Skarels 
17531392Skarels /*
17631392Skarels  * Determine whether an IP address is in a reserved set of addresses
17731392Skarels  * that may not be forwarded, or whether datagrams to that destination
17831392Skarels  * may be forwarded.
17931392Skarels  */
18031392Skarels in_canforward(in)
18131392Skarels 	struct in_addr in;
18231392Skarels {
18331392Skarels 	register u_long i = ntohl(in.s_addr);
18431392Skarels 	register u_long net;
18531392Skarels 
18631392Skarels 	if (IN_EXPERIMENTAL(i))
18731392Skarels 		return (0);
18831392Skarels 	if (IN_CLASSA(i)) {
18931392Skarels 		net = i & IN_CLASSA_NET;
19031392Skarels 		if (net == 0 || net == IN_LOOPBACKNET)
19131392Skarels 			return (0);
19231392Skarels 	}
19331392Skarels 	return (1);
19431392Skarels }
19531392Skarels 
19624805Skarels int	in_interfaces;		/* number of external internet interfaces */
19724805Skarels extern	struct ifnet loif;
19824805Skarels 
19918377Skarels /*
20018377Skarels  * Generic internet control operations (ioctl's).
20118377Skarels  * Ifp is 0 if not an interface-specific ioctl.
20218377Skarels  */
20324805Skarels /* ARGSUSED */
20418377Skarels in_control(so, cmd, data, ifp)
20518377Skarels 	struct socket *so;
20618377Skarels 	int cmd;
20718377Skarels 	caddr_t data;
20818377Skarels 	register struct ifnet *ifp;
20918377Skarels {
21018377Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
21118377Skarels 	register struct in_ifaddr *ia = 0;
21218377Skarels 	struct ifaddr *ifa;
21318377Skarels 	struct mbuf *m;
21418377Skarels 	int error;
21518377Skarels 
21618377Skarels 	/*
21718377Skarels 	 * Find address for this interface, if it exists.
21818377Skarels 	 */
21918377Skarels 	if (ifp)
22018377Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
22118377Skarels 			if (ia->ia_ifp == ifp)
22218377Skarels 				break;
22318377Skarels 
22418377Skarels 	switch (cmd) {
22518377Skarels 
22618377Skarels 	case SIOCSIFADDR:
22718377Skarels 	case SIOCSIFNETMASK:
22826456Skarels 	case SIOCSIFDSTADDR:
22918377Skarels 		if (!suser())
23018377Skarels 			return (u.u_error);
23118377Skarels 
23218377Skarels 		if (ifp == 0)
23318377Skarels 			panic("in_control");
23418377Skarels 		if (ia == (struct in_ifaddr *)0) {
23518377Skarels 			m = m_getclr(M_WAIT, MT_IFADDR);
23618377Skarels 			if (m == (struct mbuf *)NULL)
23718377Skarels 				return (ENOBUFS);
23818377Skarels 			if (ia = in_ifaddr) {
23918377Skarels 				for ( ; ia->ia_next; ia = ia->ia_next)
24018377Skarels 					;
24118377Skarels 				ia->ia_next = mtod(m, struct in_ifaddr *);
24218377Skarels 			} else
24318377Skarels 				in_ifaddr = mtod(m, struct in_ifaddr *);
24418377Skarels 			ia = mtod(m, struct in_ifaddr *);
24518377Skarels 			if (ifa = ifp->if_addrlist) {
24618377Skarels 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
24718377Skarels 					;
24818377Skarels 				ifa->ifa_next = (struct ifaddr *) ia;
24918377Skarels 			} else
25018377Skarels 				ifp->if_addrlist = (struct ifaddr *) ia;
25118377Skarels 			ia->ia_ifp = ifp;
25218377Skarels 			IA_SIN(ia)->sin_family = AF_INET;
25324805Skarels 			if (ifp != &loif)
25424805Skarels 				in_interfaces++;
25517271Skarels 		}
25618377Skarels 		break;
25726317Skarels 
25826317Skarels 	case SIOCSIFBRDADDR:
25926317Skarels 		if (!suser())
26026317Skarels 			return (u.u_error);
26126317Skarels 		/* FALLTHROUGH */
26226317Skarels 
26326317Skarels 	default:
26426317Skarels 		if (ia == (struct in_ifaddr *)0)
26526317Skarels 			return (EADDRNOTAVAIL);
26626317Skarels 		break;
26717271Skarels 	}
26818377Skarels 
26918377Skarels 	switch (cmd) {
27018377Skarels 
27118377Skarels 	case SIOCGIFADDR:
27218377Skarels 		ifr->ifr_addr = ia->ia_addr;
27318377Skarels 		break;
27418377Skarels 
27518377Skarels 	case SIOCGIFBRDADDR:
27618377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
27718377Skarels 			return (EINVAL);
27818377Skarels 		ifr->ifr_dstaddr = ia->ia_broadaddr;
27918377Skarels 		break;
28018377Skarels 
28118377Skarels 	case SIOCGIFDSTADDR:
28218377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
28318377Skarels 			return (EINVAL);
28418377Skarels 		ifr->ifr_dstaddr = ia->ia_dstaddr;
28518377Skarels 		break;
28618377Skarels 
28718377Skarels 	case SIOCGIFNETMASK:
28818377Skarels #define	satosin(sa)	((struct sockaddr_in *)(sa))
28918377Skarels 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
29018377Skarels 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
29118377Skarels 		break;
29218377Skarels 
29318377Skarels 	case SIOCSIFDSTADDR:
29427066Skarels 	    {
29527066Skarels 		struct sockaddr oldaddr;
29627066Skarels 
29718377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
29818377Skarels 			return (EINVAL);
29927066Skarels 		oldaddr = ia->ia_dstaddr;
30027066Skarels 		ia->ia_dstaddr = ifr->ifr_dstaddr;
30118377Skarels 		if (ifp->if_ioctl &&
30227066Skarels 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
30327066Skarels 			ia->ia_dstaddr = oldaddr;
30418377Skarels 			return (error);
30527066Skarels 		}
30627066Skarels 		if (ia->ia_flags & IFA_ROUTE) {
30727066Skarels 			rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
30827066Skarels 			    RTF_HOST);
30927066Skarels 			rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
31027066Skarels 			    RTF_HOST|RTF_UP);
31127066Skarels 		}
31227066Skarels 	    }
31318377Skarels 		break;
31418377Skarels 
31518377Skarels 	case SIOCSIFBRDADDR:
31618377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
31718377Skarels 			return (EINVAL);
31818377Skarels 		ia->ia_broadaddr = ifr->ifr_broadaddr;
31918377Skarels 		break;
32018377Skarels 
32118377Skarels 	case SIOCSIFADDR:
32234500Skarels 		return (in_ifinit(ifp, ia,
32334500Skarels 		    (struct sockaddr_in *) &ifr->ifr_addr));
32418377Skarels 
32518377Skarels 	case SIOCSIFNETMASK:
32618377Skarels 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
32718377Skarels 		break;
32818377Skarels 
32918377Skarels 	default:
33018377Skarels 		if (ifp == 0 || ifp->if_ioctl == 0)
33118377Skarels 			return (EOPNOTSUPP);
33218377Skarels 		return ((*ifp->if_ioctl)(ifp, cmd, data));
33318377Skarels 	}
33417271Skarels 	return (0);
33517271Skarels }
33617271Skarels 
33717271Skarels /*
33818377Skarels  * Initialize an interface's internet address
33918377Skarels  * and routing table entry.
3407159Ssam  */
34118377Skarels in_ifinit(ifp, ia, sin)
3427159Ssam 	register struct ifnet *ifp;
34318377Skarels 	register struct in_ifaddr *ia;
34418377Skarels 	struct sockaddr_in *sin;
3457159Ssam {
34618377Skarels 	register u_long i = ntohl(sin->sin_addr.s_addr);
34727066Skarels 	struct sockaddr oldaddr;
34827066Skarels 	struct sockaddr_in netaddr;
34918377Skarels 	int s = splimp(), error;
3507159Ssam 
35127066Skarels 	oldaddr = ia->ia_addr;
35226317Skarels 	ia->ia_addr = *(struct sockaddr *)sin;
35326317Skarels 
35418377Skarels 	/*
35526317Skarels 	 * Give the interface a chance to initialize
35626317Skarels 	 * if this is its first address,
35726317Skarels 	 * and to validate the address if necessary.
35826317Skarels 	 */
35926317Skarels 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
36026317Skarels 		splx(s);
36127066Skarels 		ia->ia_addr = oldaddr;
36226317Skarels 		return (error);
36326317Skarels 	}
36426317Skarels 
36526317Skarels 	/*
36618377Skarels 	 * Delete any previous route for an old address.
36718377Skarels 	 */
36827066Skarels 	bzero((caddr_t)&netaddr, sizeof (netaddr));
36927066Skarels 	netaddr.sin_family = AF_INET;
37018377Skarels 	if (ia->ia_flags & IFA_ROUTE) {
37127066Skarels 		if (ifp->if_flags & IFF_LOOPBACK)
37227066Skarels 			rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
37327066Skarels 		else if (ifp->if_flags & IFF_POINTOPOINT)
37427066Skarels 			rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
37527066Skarels 			    RTF_HOST);
37627066Skarels 		else {
37727066Skarels 			netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
37827066Skarels 			    INADDR_ANY);
37927066Skarels 			rtinit((struct sockaddr *)&netaddr, &oldaddr,
38025452Ssklower 			    (int)SIOCDELRT, 0);
38127066Skarels 		}
38218377Skarels 		ia->ia_flags &= ~IFA_ROUTE;
38318377Skarels 	}
38418377Skarels 	if (IN_CLASSA(i))
38518377Skarels 		ia->ia_netmask = IN_CLASSA_NET;
38618377Skarels 	else if (IN_CLASSB(i))
38718377Skarels 		ia->ia_netmask = IN_CLASSB_NET;
38818377Skarels 	else
38918377Skarels 		ia->ia_netmask = IN_CLASSC_NET;
39018377Skarels 	ia->ia_net = i & ia->ia_netmask;
39118377Skarels 	/*
39218377Skarels 	 * The subnet mask includes at least the standard network part,
39318377Skarels 	 * but may already have been set to a larger value.
39418377Skarels 	 */
39518377Skarels 	ia->ia_subnetmask |= ia->ia_netmask;
39618377Skarels 	ia->ia_subnet = i & ia->ia_subnetmask;
39718377Skarels 	if (ifp->if_flags & IFF_BROADCAST) {
39818377Skarels 		ia->ia_broadaddr.sa_family = AF_INET;
39918377Skarels 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
40018377Skarels 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
40125195Skarels 		ia->ia_netbroadcast.s_addr =
40225195Skarels 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
40318377Skarels 	}
40418377Skarels 	/*
40518377Skarels 	 * Add route for the network.
40618377Skarels 	 */
40727066Skarels 	if (ifp->if_flags & IFF_LOOPBACK)
40827066Skarels 		rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
40927066Skarels 		    RTF_HOST|RTF_UP);
41027066Skarels 	else if (ifp->if_flags & IFF_POINTOPOINT)
41127066Skarels 		rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
41227066Skarels 		    RTF_HOST|RTF_UP);
41327066Skarels 	else {
41427066Skarels 		netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
41527066Skarels 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
41627066Skarels 		    (int)SIOCADDRT, RTF_UP);
41727066Skarels 	}
41818377Skarels 	ia->ia_flags |= IFA_ROUTE;
41930523Skarels 	splx(s);
42018642Skarels 	return (0);
4217159Ssam }
42218377Skarels 
42318377Skarels /*
42418377Skarels  * Return address info for specified internet network.
42518377Skarels  */
42618377Skarels struct in_ifaddr *
42718377Skarels in_iaonnetof(net)
42818377Skarels 	u_long net;
42918377Skarels {
43018377Skarels 	register struct in_ifaddr *ia;
43118377Skarels 
43218377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
43318377Skarels 		if (ia->ia_subnet == net)
43418377Skarels 			return (ia);
43518377Skarels 	return ((struct in_ifaddr *)0);
43618377Skarels }
43718377Skarels 
43818377Skarels /*
43930523Skarels  * Return 1 if the address might be a local broadcast address.
44018377Skarels  */
44118377Skarels in_broadcast(in)
44218377Skarels 	struct in_addr in;
44318377Skarels {
44418377Skarels 	register struct in_ifaddr *ia;
44530523Skarels 	u_long t;
44618377Skarels 
44718377Skarels 	/*
44818377Skarels 	 * Look through the list of addresses for a match
44918377Skarels 	 * with a broadcast address.
45018377Skarels 	 */
45118377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
45230523Skarels 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
45330523Skarels 		if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
45418377Skarels 		     return (1);
45530523Skarels 		/*
45630523Skarels 		 * Check for old-style (host 0) broadcast.
45730523Skarels 		 */
45830523Skarels 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
45930523Skarels 		    return (1);
46030523Skarels 	}
46130523Skarels 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
46230523Skarels 		return (1);
46318377Skarels 	return (0);
46418377Skarels }
4657159Ssam #endif
466