date and time created 88/12/14 15:29:27 by sklower
[unix-history] / usr / src / sys / netinet / in.c
... / ...
CommitLineData
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) %G%
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
37inet_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
51inet_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 */
61struct in_addr
62in_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 */
87u_long
88in_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 */
117u_long
118in_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
150int 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 */
157in_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 */
180in_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
196int in_interfaces; /* number of external internet interfaces */
197extern 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 */
204in_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 */
341in_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 */
426struct in_ifaddr *
427in_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 */
441in_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