xref: /csrg-svn/sys/netinet/in.c (revision 25195)
1 /*
2  * Copyright (c) 1982 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	6.10 (Berkeley) 10/14/85
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
89 		net = i & IN_CLASSC_NET;
90 
91 	/*
92 	 * Check whether network is a subnet;
93 	 * if so, return subnet number.
94 	 */
95 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
96 		if (net == ia->ia_net)
97 			return (i & ia->ia_subnetmask);
98 	return (net);
99 }
100 
101 /*
102  * Return the host portion of an internet address.
103  */
104 in_lnaof(in)
105 	struct in_addr in;
106 {
107 	register u_long i = ntohl(in.s_addr);
108 	register u_long net, host;
109 	register struct in_ifaddr *ia;
110 
111 	if (IN_CLASSA(i)) {
112 		net = i & IN_CLASSA_NET;
113 		host = i & IN_CLASSA_HOST;
114 	} else if (IN_CLASSB(i)) {
115 		net = i & IN_CLASSB_NET;
116 		host = i & IN_CLASSB_HOST;
117 	} else {
118 		net = i & IN_CLASSC_NET;
119 		host = i & IN_CLASSC_HOST;
120 	}
121 
122 	/*
123 	 * Check whether network is a subnet;
124 	 * if so, use the modified interpretation of `host'.
125 	 */
126 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
127 		if (net == ia->ia_net)
128 			return (host &~ ia->ia_subnetmask);
129 	return (host);
130 }
131 
132 /*
133  * Return 1 if an internet address is for a ``local'' host
134  * (one to which we have a connection through a local logical net).
135  */
136 in_localaddr(in)
137 	struct in_addr in;
138 {
139 	register u_long i = ntohl(in.s_addr);
140 	register u_long net;
141 	register struct in_ifaddr *ia;
142 
143 	if (IN_CLASSA(i))
144 		net = i & IN_CLASSA_NET;
145 	else if (IN_CLASSB(i))
146 		net = i & IN_CLASSB_NET;
147 	else
148 		net = i & IN_CLASSC_NET;
149 
150 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
151 		if (net == ia->ia_net)
152 			return (1);
153 	return (0);
154 }
155 
156 int	in_interfaces;		/* number of external internet interfaces */
157 extern	struct ifnet loif;
158 
159 /*
160  * Generic internet control operations (ioctl's).
161  * Ifp is 0 if not an interface-specific ioctl.
162  */
163 /* ARGSUSED */
164 in_control(so, cmd, data, ifp)
165 	struct socket *so;
166 	int cmd;
167 	caddr_t data;
168 	register struct ifnet *ifp;
169 {
170 	register struct ifreq *ifr = (struct ifreq *)data;
171 	register struct in_ifaddr *ia = 0;
172 	u_long tmp;
173 	struct ifaddr *ifa;
174 	struct mbuf *m;
175 	int error;
176 
177 	/*
178 	 * Find address for this interface, if it exists.
179 	 */
180 	if (ifp)
181 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
182 			if (ia->ia_ifp == ifp)
183 				break;
184 
185 	switch (cmd) {
186 
187 	case SIOCGIFADDR:
188 	case SIOCGIFBRDADDR:
189 	case SIOCGIFDSTADDR:
190 	case SIOCGIFNETMASK:
191 		if (ia == (struct in_ifaddr *)0)
192 			return (EADDRNOTAVAIL);
193 		break;
194 
195 	case SIOCSIFADDR:
196 	case SIOCSIFDSTADDR:
197 	case SIOCSIFBRDADDR:
198 	case SIOCSIFNETMASK:
199 		if (!suser())
200 			return (u.u_error);
201 
202 		if (ifp == 0)
203 			panic("in_control");
204 		if (ia == (struct in_ifaddr *)0) {
205 			m = m_getclr(M_WAIT, MT_IFADDR);
206 			if (m == (struct mbuf *)NULL)
207 				return (ENOBUFS);
208 			if (ia = in_ifaddr) {
209 				for ( ; ia->ia_next; ia = ia->ia_next)
210 					;
211 				ia->ia_next = mtod(m, struct in_ifaddr *);
212 			} else
213 				in_ifaddr = mtod(m, struct in_ifaddr *);
214 			ia = mtod(m, struct in_ifaddr *);
215 			if (ifa = ifp->if_addrlist) {
216 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
217 					;
218 				ifa->ifa_next = (struct ifaddr *) ia;
219 			} else
220 				ifp->if_addrlist = (struct ifaddr *) ia;
221 			ia->ia_ifp = ifp;
222 			IA_SIN(ia)->sin_family = AF_INET;
223 			if (ifp != &loif)
224 				in_interfaces++;
225 		}
226 		break;
227 	}
228 
229 	switch (cmd) {
230 
231 	case SIOCGIFADDR:
232 		ifr->ifr_addr = ia->ia_addr;
233 		break;
234 
235 	case SIOCGIFBRDADDR:
236 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
237 			return (EINVAL);
238 		ifr->ifr_dstaddr = ia->ia_broadaddr;
239 		break;
240 
241 	case SIOCGIFDSTADDR:
242 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
243 			return (EINVAL);
244 		ifr->ifr_dstaddr = ia->ia_dstaddr;
245 		break;
246 
247 	case SIOCGIFNETMASK:
248 #define	satosin(sa)	((struct sockaddr_in *)(sa))
249 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
250 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
251 		break;
252 
253 	case SIOCSIFDSTADDR:
254 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
255 			return (EINVAL);
256 		if (ifp->if_ioctl &&
257 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia)))
258 			return (error);
259 		ia->ia_dstaddr = ifr->ifr_dstaddr;
260 		break;
261 
262 	case SIOCSIFBRDADDR:
263 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
264 			return (EINVAL);
265 		ia->ia_broadaddr = ifr->ifr_broadaddr;
266 		tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
267 		if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
268 			tmp |= ~ia->ia_netmask;
269 		else if ((tmp &~ ia->ia_subnetmask) == 0)
270 			tmp &= ia->ia_netmask;
271 		ia->ia_netbroadcast.s_addr = htonl(tmp);
272 		break;
273 
274 	case SIOCSIFADDR:
275 		return (in_ifinit(ifp, ia, &ifr->ifr_addr));
276 
277 	case SIOCSIFNETMASK:
278 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
279 		break;
280 
281 	default:
282 		if (ifp == 0 || ifp->if_ioctl == 0)
283 			return (EOPNOTSUPP);
284 		return ((*ifp->if_ioctl)(ifp, cmd, data));
285 	}
286 	return (0);
287 }
288 
289 /*
290  * Initialize an interface's internet address
291  * and routing table entry.
292  */
293 in_ifinit(ifp, ia, sin)
294 	register struct ifnet *ifp;
295 	register struct in_ifaddr *ia;
296 	struct sockaddr_in *sin;
297 {
298 	register u_long i = ntohl(sin->sin_addr.s_addr);
299 	struct sockaddr_in netaddr;
300 	int s = splimp(), error;
301 
302 	bzero((caddr_t)&netaddr, sizeof (netaddr));
303 	netaddr.sin_family = AF_INET;
304 	/*
305 	 * Delete any previous route for an old address.
306 	 */
307 	if (ia->ia_flags & IFA_ROUTE) {
308 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
309 		    netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
310 		    rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1);
311 		} else
312 		    rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1);
313 		ia->ia_flags &= ~IFA_ROUTE;
314 	}
315 	ia->ia_addr = *(struct sockaddr *)sin;
316 	if (IN_CLASSA(i))
317 		ia->ia_netmask = IN_CLASSA_NET;
318 	else if (IN_CLASSB(i))
319 		ia->ia_netmask = IN_CLASSB_NET;
320 	else
321 		ia->ia_netmask = IN_CLASSC_NET;
322 	ia->ia_net = i & ia->ia_netmask;
323 	/*
324 	 * The subnet mask includes at least the standard network part,
325 	 * but may already have been set to a larger value.
326 	 */
327 	ia->ia_subnetmask |= ia->ia_netmask;
328 	ia->ia_subnet = i & ia->ia_subnetmask;
329 	if (ifp->if_flags & IFF_BROADCAST) {
330 		ia->ia_broadaddr.sa_family = AF_INET;
331 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
332 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
333 		ia->ia_netbroadcast.s_addr =
334 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
335 	}
336 
337 	/*
338 	 * Give the interface a chance to initialize
339 	 * if this is its first address,
340 	 * and to validate the address if necessary.
341 	 */
342 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
343 		splx(s);
344 		bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr));
345 		return (error);
346 	}
347 	splx(s);
348 	/*
349 	 * Add route for the network.
350 	 */
351 	if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
352 		netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
353 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP);
354 	} else
355 		rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
356 			RTF_HOST|RTF_UP);
357 	ia->ia_flags |= IFA_ROUTE;
358 	return (0);
359 }
360 
361 /*
362  * Return address info for specified internet network.
363  */
364 struct in_ifaddr *
365 in_iaonnetof(net)
366 	u_long net;
367 {
368 	register struct in_ifaddr *ia;
369 
370 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
371 		if (ia->ia_subnet == net)
372 			return (ia);
373 	return ((struct in_ifaddr *)0);
374 }
375 
376 /*
377  * Return 1 if the address is a local broadcast address.
378  */
379 in_broadcast(in)
380 	struct in_addr in;
381 {
382 	register struct in_ifaddr *ia;
383 
384 	/*
385 	 * Look through the list of addresses for a match
386 	 * with a broadcast address.
387 	 */
388 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
389 	    if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr ==
390 		in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST))
391 		     return (1);
392 	return (0);
393 }
394 #endif
395