xref: /csrg-svn/sys/netinet/in.c (revision 31392)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)in.c	7.5 (Berkeley) 06/04/87
7  */
8 
9 #include "param.h"
10 #include "ioctl.h"
11 #include "mbuf.h"
12 #include "protosw.h"
13 #include "socket.h"
14 #include "socketvar.h"
15 #include "uio.h"
16 #include "dir.h"
17 #include "user.h"
18 #include "in_systm.h"
19 #include "../net/if.h"
20 #include "../net/route.h"
21 #include "../net/af.h"
22 #include "in.h"
23 #include "in_var.h"
24 
25 #ifdef INET
26 inet_hash(sin, hp)
27 	register struct sockaddr_in *sin;
28 	struct afhash *hp;
29 {
30 	register u_long n;
31 
32 	n = in_netof(sin->sin_addr);
33 	if (n)
34 	    while ((n & 0xff) == 0)
35 		n >>= 8;
36 	hp->afh_nethash = n;
37 	hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
38 }
39 
40 inet_netmatch(sin1, sin2)
41 	struct sockaddr_in *sin1, *sin2;
42 {
43 
44 	return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr));
45 }
46 
47 /*
48  * Formulate an Internet address from network + host.
49  */
50 struct in_addr
51 in_makeaddr(net, host)
52 	u_long net, host;
53 {
54 	register struct in_ifaddr *ia;
55 	register u_long mask;
56 	u_long addr;
57 
58 	if (IN_CLASSA(net))
59 		mask = IN_CLASSA_HOST;
60 	else if (IN_CLASSB(net))
61 		mask = IN_CLASSB_HOST;
62 	else
63 		mask = IN_CLASSC_HOST;
64 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
65 		if ((ia->ia_netmask & net) == ia->ia_net) {
66 			mask = ~ia->ia_subnetmask;
67 			break;
68 		}
69 	addr = htonl(net | (host & mask));
70 	return (*(struct in_addr *)&addr);
71 }
72 
73 /*
74  * Return the network number from an internet address.
75  */
76 u_long
77 in_netof(in)
78 	struct in_addr in;
79 {
80 	register u_long i = ntohl(in.s_addr);
81 	register u_long net;
82 	register struct in_ifaddr *ia;
83 
84 	if (IN_CLASSA(i))
85 		net = i & IN_CLASSA_NET;
86 	else if (IN_CLASSB(i))
87 		net = i & IN_CLASSB_NET;
88 	else if (IN_CLASSC(i))
89 		net = i & IN_CLASSC_NET;
90 	else
91 		return (0);
92 
93 	/*
94 	 * Check whether network is a subnet;
95 	 * if so, return subnet number.
96 	 */
97 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
98 		if (net == ia->ia_net)
99 			return (i & ia->ia_subnetmask);
100 	return (net);
101 }
102 
103 /*
104  * Return the host portion of an internet address.
105  */
106 u_long
107 in_lnaof(in)
108 	struct in_addr in;
109 {
110 	register u_long i = ntohl(in.s_addr);
111 	register u_long net, host;
112 	register struct in_ifaddr *ia;
113 
114 	if (IN_CLASSA(i)) {
115 		net = i & IN_CLASSA_NET;
116 		host = i & IN_CLASSA_HOST;
117 	} else if (IN_CLASSB(i)) {
118 		net = i & IN_CLASSB_NET;
119 		host = i & IN_CLASSB_HOST;
120 	} else if (IN_CLASSC(i)) {
121 		net = i & IN_CLASSC_NET;
122 		host = i & IN_CLASSC_HOST;
123 	} else
124 		return (i);
125 
126 	/*
127 	 * Check whether network is a subnet;
128 	 * if so, use the modified interpretation of `host'.
129 	 */
130 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
131 		if (net == ia->ia_net)
132 			return (host &~ ia->ia_subnetmask);
133 	return (host);
134 }
135 
136 #ifndef SUBNETSARELOCAL
137 #define	SUBNETSARELOCAL	1
138 #endif
139 int subnetsarelocal = SUBNETSARELOCAL;
140 /*
141  * Return 1 if an internet address is for a ``local'' host
142  * (one to which we have a connection).  If subnetsarelocal
143  * is true, this includes other subnets of the local net.
144  * Otherwise, it includes only the directly-connected (sub)nets.
145  */
146 in_localaddr(in)
147 	struct in_addr in;
148 {
149 	register u_long i = ntohl(in.s_addr);
150 	register struct in_ifaddr *ia;
151 
152 	if (subnetsarelocal) {
153 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
154 			if ((i & ia->ia_netmask) == ia->ia_net)
155 				return (1);
156 	} else {
157 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
158 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
159 				return (1);
160 	}
161 	return (0);
162 }
163 
164 /*
165  * Determine whether an IP address is in a reserved set of addresses
166  * that may not be forwarded, or whether datagrams to that destination
167  * may be forwarded.
168  */
169 in_canforward(in)
170 	struct in_addr in;
171 {
172 	register u_long i = ntohl(in.s_addr);
173 	register u_long net;
174 
175 	if (IN_EXPERIMENTAL(i))
176 		return (0);
177 	if (IN_CLASSA(i)) {
178 		net = i & IN_CLASSA_NET;
179 		if (net == 0 || net == IN_LOOPBACKNET)
180 			return (0);
181 	}
182 	return (1);
183 }
184 
185 int	in_interfaces;		/* number of external internet interfaces */
186 extern	struct ifnet loif;
187 
188 /*
189  * Generic internet control operations (ioctl's).
190  * Ifp is 0 if not an interface-specific ioctl.
191  */
192 /* ARGSUSED */
193 in_control(so, cmd, data, ifp)
194 	struct socket *so;
195 	int cmd;
196 	caddr_t data;
197 	register struct ifnet *ifp;
198 {
199 	register struct ifreq *ifr = (struct ifreq *)data;
200 	register struct in_ifaddr *ia = 0;
201 	u_long tmp;
202 	struct ifaddr *ifa;
203 	struct mbuf *m;
204 	int error;
205 
206 	/*
207 	 * Find address for this interface, if it exists.
208 	 */
209 	if (ifp)
210 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
211 			if (ia->ia_ifp == ifp)
212 				break;
213 
214 	switch (cmd) {
215 
216 	case SIOCSIFADDR:
217 	case SIOCSIFNETMASK:
218 	case SIOCSIFDSTADDR:
219 		if (!suser())
220 			return (u.u_error);
221 
222 		if (ifp == 0)
223 			panic("in_control");
224 		if (ia == (struct in_ifaddr *)0) {
225 			m = m_getclr(M_WAIT, MT_IFADDR);
226 			if (m == (struct mbuf *)NULL)
227 				return (ENOBUFS);
228 			if (ia = in_ifaddr) {
229 				for ( ; ia->ia_next; ia = ia->ia_next)
230 					;
231 				ia->ia_next = mtod(m, struct in_ifaddr *);
232 			} else
233 				in_ifaddr = mtod(m, struct in_ifaddr *);
234 			ia = mtod(m, struct in_ifaddr *);
235 			if (ifa = ifp->if_addrlist) {
236 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
237 					;
238 				ifa->ifa_next = (struct ifaddr *) ia;
239 			} else
240 				ifp->if_addrlist = (struct ifaddr *) ia;
241 			ia->ia_ifp = ifp;
242 			IA_SIN(ia)->sin_family = AF_INET;
243 			if (ifp != &loif)
244 				in_interfaces++;
245 		}
246 		break;
247 
248 	case SIOCSIFBRDADDR:
249 		if (!suser())
250 			return (u.u_error);
251 		/* FALLTHROUGH */
252 
253 	default:
254 		if (ia == (struct in_ifaddr *)0)
255 			return (EADDRNOTAVAIL);
256 		break;
257 	}
258 
259 	switch (cmd) {
260 
261 	case SIOCGIFADDR:
262 		ifr->ifr_addr = ia->ia_addr;
263 		break;
264 
265 	case SIOCGIFBRDADDR:
266 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
267 			return (EINVAL);
268 		ifr->ifr_dstaddr = ia->ia_broadaddr;
269 		break;
270 
271 	case SIOCGIFDSTADDR:
272 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
273 			return (EINVAL);
274 		ifr->ifr_dstaddr = ia->ia_dstaddr;
275 		break;
276 
277 	case SIOCGIFNETMASK:
278 #define	satosin(sa)	((struct sockaddr_in *)(sa))
279 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
280 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
281 		break;
282 
283 	case SIOCSIFDSTADDR:
284 	    {
285 		struct sockaddr oldaddr;
286 
287 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
288 			return (EINVAL);
289 		oldaddr = ia->ia_dstaddr;
290 		ia->ia_dstaddr = ifr->ifr_dstaddr;
291 		if (ifp->if_ioctl &&
292 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
293 			ia->ia_dstaddr = oldaddr;
294 			return (error);
295 		}
296 		if (ia->ia_flags & IFA_ROUTE) {
297 			rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
298 			    RTF_HOST);
299 			rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
300 			    RTF_HOST|RTF_UP);
301 		}
302 	    }
303 		break;
304 
305 	case SIOCSIFBRDADDR:
306 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
307 			return (EINVAL);
308 		ia->ia_broadaddr = ifr->ifr_broadaddr;
309 		tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
310 		if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
311 			tmp |= ~ia->ia_netmask;
312 		else if ((tmp &~ ia->ia_subnetmask) == 0)
313 			tmp &= ia->ia_netmask;
314 		ia->ia_netbroadcast.s_addr = htonl(tmp);
315 		break;
316 
317 	case SIOCSIFADDR:
318 		return (in_ifinit(ifp, ia, &ifr->ifr_addr));
319 
320 	case SIOCSIFNETMASK:
321 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
322 		break;
323 
324 	default:
325 		if (ifp == 0 || ifp->if_ioctl == 0)
326 			return (EOPNOTSUPP);
327 		return ((*ifp->if_ioctl)(ifp, cmd, data));
328 	}
329 	return (0);
330 }
331 
332 /*
333  * Initialize an interface's internet address
334  * and routing table entry.
335  */
336 in_ifinit(ifp, ia, sin)
337 	register struct ifnet *ifp;
338 	register struct in_ifaddr *ia;
339 	struct sockaddr_in *sin;
340 {
341 	register u_long i = ntohl(sin->sin_addr.s_addr);
342 	struct sockaddr oldaddr;
343 	struct sockaddr_in netaddr;
344 	int s = splimp(), error;
345 
346 	oldaddr = ia->ia_addr;
347 	ia->ia_addr = *(struct sockaddr *)sin;
348 
349 	/*
350 	 * Give the interface a chance to initialize
351 	 * if this is its first address,
352 	 * and to validate the address if necessary.
353 	 */
354 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
355 		splx(s);
356 		ia->ia_addr = oldaddr;
357 		return (error);
358 	}
359 
360 	/*
361 	 * Delete any previous route for an old address.
362 	 */
363 	bzero((caddr_t)&netaddr, sizeof (netaddr));
364 	netaddr.sin_family = AF_INET;
365 	if (ia->ia_flags & IFA_ROUTE) {
366 		if (ifp->if_flags & IFF_LOOPBACK)
367 			rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
368 		else if (ifp->if_flags & IFF_POINTOPOINT)
369 			rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
370 			    RTF_HOST);
371 		else {
372 			netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
373 			    INADDR_ANY);
374 			rtinit((struct sockaddr *)&netaddr, &oldaddr,
375 			    (int)SIOCDELRT, 0);
376 		}
377 		ia->ia_flags &= ~IFA_ROUTE;
378 	}
379 	if (IN_CLASSA(i))
380 		ia->ia_netmask = IN_CLASSA_NET;
381 	else if (IN_CLASSB(i))
382 		ia->ia_netmask = IN_CLASSB_NET;
383 	else
384 		ia->ia_netmask = IN_CLASSC_NET;
385 	ia->ia_net = i & ia->ia_netmask;
386 	/*
387 	 * The subnet mask includes at least the standard network part,
388 	 * but may already have been set to a larger value.
389 	 */
390 	ia->ia_subnetmask |= ia->ia_netmask;
391 	ia->ia_subnet = i & ia->ia_subnetmask;
392 	if (ifp->if_flags & IFF_BROADCAST) {
393 		ia->ia_broadaddr.sa_family = AF_INET;
394 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
395 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
396 		ia->ia_netbroadcast.s_addr =
397 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
398 	}
399 	/*
400 	 * Add route for the network.
401 	 */
402 	if (ifp->if_flags & IFF_LOOPBACK)
403 		rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
404 		    RTF_HOST|RTF_UP);
405 	else if (ifp->if_flags & IFF_POINTOPOINT)
406 		rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
407 		    RTF_HOST|RTF_UP);
408 	else {
409 		netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
410 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
411 		    (int)SIOCADDRT, RTF_UP);
412 	}
413 	ia->ia_flags |= IFA_ROUTE;
414 	splx(s);
415 	return (0);
416 }
417 
418 /*
419  * Return address info for specified internet network.
420  */
421 struct in_ifaddr *
422 in_iaonnetof(net)
423 	u_long net;
424 {
425 	register struct in_ifaddr *ia;
426 
427 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
428 		if (ia->ia_subnet == net)
429 			return (ia);
430 	return ((struct in_ifaddr *)0);
431 }
432 
433 /*
434  * Return 1 if the address might be a local broadcast address.
435  */
436 in_broadcast(in)
437 	struct in_addr in;
438 {
439 	register struct in_ifaddr *ia;
440 	u_long t;
441 
442 	/*
443 	 * Look through the list of addresses for a match
444 	 * with a broadcast address.
445 	 */
446 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
447 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
448 		if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
449 		     return (1);
450 		/*
451 		 * Check for old-style (host 0) broadcast.
452 		 */
453 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
454 		    return (1);
455 	}
456 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
457 		return (1);
458 	return (0);
459 }
460 #endif
461