xref: /csrg-svn/sys/netinet/in.c (revision 26381)
123175Smckusick /*
223175Smckusick  * Copyright (c) 1982 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*26381Skarels  *	@(#)in.c	6.13 (Berkeley) 02/23/86
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;
8818377Skarels 	else
8918377Skarels 		net = i & IN_CLASSC_NET;
9016413Skarels 
9116413Skarels 	/*
9218377Skarels 	 * Check whether network is a subnet;
9316413Skarels 	 * if so, return subnet number.
9416413Skarels 	 */
9518377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
9624805Skarels 		if (net == ia->ia_net)
9718377Skarels 			return (i & ia->ia_subnetmask);
9816413Skarels 	return (net);
997159Ssam }
1007159Ssam 
1017159Ssam /*
1028595Sroot  * Return the host portion of an internet address.
1037159Ssam  */
104*26381Skarels u_long
1057159Ssam in_lnaof(in)
1067159Ssam 	struct in_addr in;
1077159Ssam {
1088937Sroot 	register u_long i = ntohl(in.s_addr);
10918377Skarels 	register u_long net, host;
11018377Skarels 	register struct in_ifaddr *ia;
1117159Ssam 
11216377Skarels 	if (IN_CLASSA(i)) {
11318377Skarels 		net = i & IN_CLASSA_NET;
11418377Skarels 		host = i & IN_CLASSA_HOST;
11516377Skarels 	} else if (IN_CLASSB(i)) {
11618377Skarels 		net = i & IN_CLASSB_NET;
11718377Skarels 		host = i & IN_CLASSB_HOST;
11816377Skarels 	} else {
11918377Skarels 		net = i & IN_CLASSC_NET;
12018377Skarels 		host = i & IN_CLASSC_HOST;
12116377Skarels 	}
1227159Ssam 
12316413Skarels 	/*
12418377Skarels 	 * Check whether network is a subnet;
12516413Skarels 	 * if so, use the modified interpretation of `host'.
12616413Skarels 	 */
12718377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
12824805Skarels 		if (net == ia->ia_net)
12918377Skarels 			return (host &~ ia->ia_subnetmask);
13016413Skarels 	return (host);
13116377Skarels }
13216377Skarels 
133*26381Skarels #ifndef SUBNETSARELOCAL
134*26381Skarels #define	SUBNETSARELOCAL	1
135*26381Skarels #endif
136*26381Skarels int subnetsarelocal = SUBNETSARELOCAL;
13716377Skarels /*
13818377Skarels  * Return 1 if an internet address is for a ``local'' host
139*26381Skarels  * (one to which we have a connection).  If subnetsarelocal
140*26381Skarels  * is true, this includes other subnets of the local net.
141*26381Skarels  * Otherwise, it includes only the directly-connected (sub)nets.
14217271Skarels  */
14317271Skarels in_localaddr(in)
14417271Skarels 	struct in_addr in;
14517271Skarels {
14617271Skarels 	register u_long i = ntohl(in.s_addr);
14717271Skarels 	register u_long net;
14818377Skarels 	register struct in_ifaddr *ia;
14917271Skarels 
15017271Skarels 	if (IN_CLASSA(i))
15118377Skarels 		net = i & IN_CLASSA_NET;
15217271Skarels 	else if (IN_CLASSB(i))
15318377Skarels 		net = i & IN_CLASSB_NET;
15417271Skarels 	else
15518377Skarels 		net = i & IN_CLASSC_NET;
15617271Skarels 
15718377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
158*26381Skarels 		if (net == subnetsarelocal ? ia->ia_net : ia->ia_subnet)
15918377Skarels 			return (1);
16018377Skarels 	return (0);
16118377Skarels }
16218377Skarels 
16324805Skarels int	in_interfaces;		/* number of external internet interfaces */
16424805Skarels extern	struct ifnet loif;
16524805Skarels 
16618377Skarels /*
16718377Skarels  * Generic internet control operations (ioctl's).
16818377Skarels  * Ifp is 0 if not an interface-specific ioctl.
16918377Skarels  */
17024805Skarels /* ARGSUSED */
17118377Skarels in_control(so, cmd, data, ifp)
17218377Skarels 	struct socket *so;
17318377Skarels 	int cmd;
17418377Skarels 	caddr_t data;
17518377Skarels 	register struct ifnet *ifp;
17618377Skarels {
17718377Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
17818377Skarels 	register struct in_ifaddr *ia = 0;
17925195Skarels 	u_long tmp;
18018377Skarels 	struct ifaddr *ifa;
18118377Skarels 	struct mbuf *m;
18218377Skarels 	int error;
18318377Skarels 
18418377Skarels 	/*
18518377Skarels 	 * Find address for this interface, if it exists.
18618377Skarels 	 */
18718377Skarels 	if (ifp)
18818377Skarels 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
18918377Skarels 			if (ia->ia_ifp == ifp)
19018377Skarels 				break;
19118377Skarels 
19218377Skarels 	switch (cmd) {
19318377Skarels 
19418377Skarels 	case SIOCSIFADDR:
19518377Skarels 	case SIOCSIFNETMASK:
19618377Skarels 		if (!suser())
19718377Skarels 			return (u.u_error);
19818377Skarels 
19918377Skarels 		if (ifp == 0)
20018377Skarels 			panic("in_control");
20118377Skarels 		if (ia == (struct in_ifaddr *)0) {
20218377Skarels 			m = m_getclr(M_WAIT, MT_IFADDR);
20318377Skarels 			if (m == (struct mbuf *)NULL)
20418377Skarels 				return (ENOBUFS);
20518377Skarels 			if (ia = in_ifaddr) {
20618377Skarels 				for ( ; ia->ia_next; ia = ia->ia_next)
20718377Skarels 					;
20818377Skarels 				ia->ia_next = mtod(m, struct in_ifaddr *);
20918377Skarels 			} else
21018377Skarels 				in_ifaddr = mtod(m, struct in_ifaddr *);
21118377Skarels 			ia = mtod(m, struct in_ifaddr *);
21218377Skarels 			if (ifa = ifp->if_addrlist) {
21318377Skarels 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
21418377Skarels 					;
21518377Skarels 				ifa->ifa_next = (struct ifaddr *) ia;
21618377Skarels 			} else
21718377Skarels 				ifp->if_addrlist = (struct ifaddr *) ia;
21818377Skarels 			ia->ia_ifp = ifp;
21918377Skarels 			IA_SIN(ia)->sin_family = AF_INET;
22024805Skarels 			if (ifp != &loif)
22124805Skarels 				in_interfaces++;
22217271Skarels 		}
22318377Skarels 		break;
22426317Skarels 
22526317Skarels 	case SIOCSIFBRDADDR:
22626317Skarels 	case SIOCSIFDSTADDR:
22726317Skarels 		if (!suser())
22826317Skarels 			return (u.u_error);
22926317Skarels 		/* FALLTHROUGH */
23026317Skarels 
23126317Skarels 	default:
23226317Skarels 		if (ia == (struct in_ifaddr *)0)
23326317Skarels 			return (EADDRNOTAVAIL);
23426317Skarels 		break;
23517271Skarels 	}
23618377Skarels 
23718377Skarels 	switch (cmd) {
23818377Skarels 
23918377Skarels 	case SIOCGIFADDR:
24018377Skarels 		ifr->ifr_addr = ia->ia_addr;
24118377Skarels 		break;
24218377Skarels 
24318377Skarels 	case SIOCGIFBRDADDR:
24418377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
24518377Skarels 			return (EINVAL);
24618377Skarels 		ifr->ifr_dstaddr = ia->ia_broadaddr;
24718377Skarels 		break;
24818377Skarels 
24918377Skarels 	case SIOCGIFDSTADDR:
25018377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
25118377Skarels 			return (EINVAL);
25218377Skarels 		ifr->ifr_dstaddr = ia->ia_dstaddr;
25318377Skarels 		break;
25418377Skarels 
25518377Skarels 	case SIOCGIFNETMASK:
25618377Skarels #define	satosin(sa)	((struct sockaddr_in *)(sa))
25718377Skarels 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
25818377Skarels 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
25918377Skarels 		break;
26018377Skarels 
26118377Skarels 	case SIOCSIFDSTADDR:
26218377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
26318377Skarels 			return (EINVAL);
26418377Skarels 		if (ifp->if_ioctl &&
26524805Skarels 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia)))
26618377Skarels 			return (error);
26718377Skarels 		ia->ia_dstaddr = ifr->ifr_dstaddr;
26818377Skarels 		break;
26918377Skarels 
27018377Skarels 	case SIOCSIFBRDADDR:
27118377Skarels 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
27218377Skarels 			return (EINVAL);
27318377Skarels 		ia->ia_broadaddr = ifr->ifr_broadaddr;
27425195Skarels 		tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
27525195Skarels 		if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
27625195Skarels 			tmp |= ~ia->ia_netmask;
27725195Skarels 		else if ((tmp &~ ia->ia_subnetmask) == 0)
27825195Skarels 			tmp &= ia->ia_netmask;
27925195Skarels 		ia->ia_netbroadcast.s_addr = htonl(tmp);
28018377Skarels 		break;
28118377Skarels 
28218377Skarels 	case SIOCSIFADDR:
28318377Skarels 		return (in_ifinit(ifp, ia, &ifr->ifr_addr));
28418377Skarels 
28518377Skarels 	case SIOCSIFNETMASK:
28618377Skarels 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
28718377Skarels 		break;
28818377Skarels 
28918377Skarels 	default:
29018377Skarels 		if (ifp == 0 || ifp->if_ioctl == 0)
29118377Skarels 			return (EOPNOTSUPP);
29218377Skarels 		return ((*ifp->if_ioctl)(ifp, cmd, data));
29318377Skarels 	}
29417271Skarels 	return (0);
29517271Skarels }
29617271Skarels 
29717271Skarels /*
29818377Skarels  * Initialize an interface's internet address
29918377Skarels  * and routing table entry.
3007159Ssam  */
30118377Skarels in_ifinit(ifp, ia, sin)
3027159Ssam 	register struct ifnet *ifp;
30318377Skarels 	register struct in_ifaddr *ia;
30418377Skarels 	struct sockaddr_in *sin;
3057159Ssam {
30618377Skarels 	register u_long i = ntohl(sin->sin_addr.s_addr);
30726317Skarels 	struct sockaddr_in tmpaddr;
30818377Skarels 	int s = splimp(), error;
3097159Ssam 
31026317Skarels 	tmpaddr = *(struct sockaddr_in *)&ia->ia_addr;
31126317Skarels 	ia->ia_addr = *(struct sockaddr *)sin;
31226317Skarels 
31318377Skarels 	/*
31426317Skarels 	 * Give the interface a chance to initialize
31526317Skarels 	 * if this is its first address,
31626317Skarels 	 * and to validate the address if necessary.
31726317Skarels 	 */
31826317Skarels 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
31926317Skarels 		splx(s);
32026317Skarels 		ia->ia_addr = *(struct sockaddr *)&tmpaddr;
32126317Skarels 		return (error);
32226317Skarels 	}
32326317Skarels 
32426317Skarels 	bzero((caddr_t)&tmpaddr, sizeof (tmpaddr));
32526317Skarels 	tmpaddr.sin_family = AF_INET;
32626317Skarels 	/*
32718377Skarels 	 * Delete any previous route for an old address.
32818377Skarels 	 */
32918377Skarels 	if (ia->ia_flags & IFA_ROUTE) {
33018377Skarels 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
33126317Skarels 		    tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
33226317Skarels 		    rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr,
33325452Ssklower 			    (int)SIOCDELRT, 0);
33418377Skarels 		} else
33525452Ssklower 		    rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
33625452Ssklower 			    (int)SIOCDELRT, RTF_HOST);
33718377Skarels 		ia->ia_flags &= ~IFA_ROUTE;
33818377Skarels 	}
33918377Skarels 	if (IN_CLASSA(i))
34018377Skarels 		ia->ia_netmask = IN_CLASSA_NET;
34118377Skarels 	else if (IN_CLASSB(i))
34218377Skarels 		ia->ia_netmask = IN_CLASSB_NET;
34318377Skarels 	else
34418377Skarels 		ia->ia_netmask = IN_CLASSC_NET;
34518377Skarels 	ia->ia_net = i & ia->ia_netmask;
34618377Skarels 	/*
34718377Skarels 	 * The subnet mask includes at least the standard network part,
34818377Skarels 	 * but may already have been set to a larger value.
34918377Skarels 	 */
35018377Skarels 	ia->ia_subnetmask |= ia->ia_netmask;
35118377Skarels 	ia->ia_subnet = i & ia->ia_subnetmask;
35218377Skarels 	if (ifp->if_flags & IFF_BROADCAST) {
35318377Skarels 		ia->ia_broadaddr.sa_family = AF_INET;
35418377Skarels 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
35518377Skarels 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
35625195Skarels 		ia->ia_netbroadcast.s_addr =
35725195Skarels 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
35818377Skarels 	}
35918377Skarels 	splx(s);
36018377Skarels 	/*
36118377Skarels 	 * Add route for the network.
36218377Skarels 	 */
36318377Skarels 	if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
36426317Skarels 		tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
36526317Skarels 		rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr,
36625452Ssklower 			(int)SIOCADDRT, RTF_UP);
36718377Skarels 	} else
36818377Skarels 		rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
36925452Ssklower 			(int)SIOCADDRT, RTF_HOST|RTF_UP);
37018377Skarels 	ia->ia_flags |= IFA_ROUTE;
37118642Skarels 	return (0);
3727159Ssam }
37318377Skarels 
37418377Skarels /*
37518377Skarels  * Return address info for specified internet network.
37618377Skarels  */
37718377Skarels struct in_ifaddr *
37818377Skarels in_iaonnetof(net)
37918377Skarels 	u_long net;
38018377Skarels {
38118377Skarels 	register struct in_ifaddr *ia;
38218377Skarels 
38318377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
38418377Skarels 		if (ia->ia_subnet == net)
38518377Skarels 			return (ia);
38618377Skarels 	return ((struct in_ifaddr *)0);
38718377Skarels }
38818377Skarels 
38918377Skarels /*
39018377Skarels  * Return 1 if the address is a local broadcast address.
39118377Skarels  */
39218377Skarels in_broadcast(in)
39318377Skarels 	struct in_addr in;
39418377Skarels {
39518377Skarels 	register struct in_ifaddr *ia;
39618377Skarels 
39718377Skarels 	/*
39818377Skarels 	 * Look through the list of addresses for a match
39918377Skarels 	 * with a broadcast address.
40018377Skarels 	 */
40118377Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
40218377Skarels 	    if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr ==
40318377Skarels 		in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST))
40418377Skarels 		     return (1);
40518377Skarels 	return (0);
40618377Skarels }
4077159Ssam #endif
408