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