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