This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / netinet / in.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
38e82238 33 * from: @(#)in.c 7.17 (Berkeley) 4/20/91
d4af9a63 34 * $Id: in.c,v 1.7 1993/12/19 00:52:34 wollman Exp $
15637ed4
RG
35 */
36
37#include "param.h"
2cb63509 38#include "systm.h"
15637ed4
RG
39#include "ioctl.h"
40#include "mbuf.h"
41#include "socket.h"
42#include "socketvar.h"
43#include "in_systm.h"
44#include "net/if.h"
45#include "net/route.h"
15637ed4
RG
46#include "in.h"
47#include "in_var.h"
48
49#ifdef INET
8ace4366 50
4c45483e
GW
51static void in_ifscrub(struct ifnet *, struct in_ifaddr *);
52
15637ed4
RG
53/*
54 * Formulate an Internet address from network + host.
55 */
56struct in_addr
57in_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 */
82u_long
83in_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 * Compute and save network mask as sockaddr from an internet address.
111 */
4c45483e 112void
15637ed4
RG
113in_sockmaskof(in, sockmask)
114 struct in_addr in;
115 register struct sockaddr_in *sockmask;
116{
117 register u_long net;
118 register u_long mask;
119 {
120 register u_long i = ntohl(in.s_addr);
121
122 if (i == 0)
123 net = 0, mask = 0;
124 else if (IN_CLASSA(i))
125 net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
126 else if (IN_CLASSB(i))
127 net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
128 else if (IN_CLASSC(i))
129 net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
130 else
131 net = i, mask = -1;
132 }
133 {
134 register struct in_ifaddr *ia;
135 /*
136 * Check whether network is a subnet;
137 * if so, return subnet number.
138 */
139 for (ia = in_ifaddr; ia; ia = ia->ia_next)
140 if (net == ia->ia_net)
141 mask = ia->ia_subnetmask;
142 }
143 {
144 register char *cpbase = (char *)&(sockmask->sin_addr);
145 register char *cp = (char *)(1 + &(sockmask->sin_addr));
146
147 sockmask->sin_addr.s_addr = htonl(mask);
148 sockmask->sin_len = 0;
149 while (--cp >= cpbase)
150 if (*cp) {
151 sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
152 break;
153 }
154 }
155}
156
157/*
158 * Return the host portion of an internet address.
159 */
160u_long
161in_lnaof(in)
162 struct in_addr in;
163{
164 register u_long i = ntohl(in.s_addr);
165 register u_long net, host;
166 register struct in_ifaddr *ia;
167
168 if (IN_CLASSA(i)) {
169 net = i & IN_CLASSA_NET;
170 host = i & IN_CLASSA_HOST;
171 } else if (IN_CLASSB(i)) {
172 net = i & IN_CLASSB_NET;
173 host = i & IN_CLASSB_HOST;
174 } else if (IN_CLASSC(i)) {
175 net = i & IN_CLASSC_NET;
176 host = i & IN_CLASSC_HOST;
177 } else
178 return (i);
179
180 /*
181 * Check whether network is a subnet;
182 * if so, use the modified interpretation of `host'.
183 */
184 for (ia = in_ifaddr; ia; ia = ia->ia_next)
185 if (net == ia->ia_net)
186 return (host &~ ia->ia_subnetmask);
187 return (host);
188}
189
15637ed4
RG
190/*
191 * Return 1 if an internet address is for a ``local'' host
192 * (one to which we have a connection). If subnetsarelocal
193 * is true, this includes other subnets of the local net.
194 * Otherwise, it includes only the directly-connected (sub)nets.
195 */
4c45483e 196int
15637ed4
RG
197in_localaddr(in)
198 struct in_addr in;
199{
200 register u_long i = ntohl(in.s_addr);
201 register struct in_ifaddr *ia;
202
203 if (subnetsarelocal) {
204 for (ia = in_ifaddr; ia; ia = ia->ia_next)
205 if ((i & ia->ia_netmask) == ia->ia_net)
206 return (1);
207 } else {
208 for (ia = in_ifaddr; ia; ia = ia->ia_next)
209 if ((i & ia->ia_subnetmask) == ia->ia_subnet)
210 return (1);
211 }
212 return (0);
213}
214
215/*
216 * Determine whether an IP address is in a reserved set of addresses
217 * that may not be forwarded, or whether datagrams to that destination
218 * may be forwarded.
219 */
4c45483e 220int
15637ed4
RG
221in_canforward(in)
222 struct in_addr in;
223{
224 register u_long i = ntohl(in.s_addr);
225 register u_long net;
226
227 if (IN_EXPERIMENTAL(i))
228 return (0);
229 if (IN_CLASSA(i)) {
230 net = i & IN_CLASSA_NET;
d4af9a63 231 if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
15637ed4
RG
232 return (0);
233 }
234 return (1);
235}
236
fde1aeb2 237static int in_interfaces; /* number of external internet interfaces */
15637ed4
RG
238
239/*
240 * Generic internet control operations (ioctl's).
241 * Ifp is 0 if not an interface-specific ioctl.
242 */
243/* ARGSUSED */
4c45483e 244int
15637ed4
RG
245in_control(so, cmd, data, ifp)
246 struct socket *so;
247 int cmd;
248 caddr_t data;
249 register struct ifnet *ifp;
250{
251 register struct ifreq *ifr = (struct ifreq *)data;
252 register struct in_ifaddr *ia = 0;
253 register struct ifaddr *ifa;
254 struct in_ifaddr *oia;
255 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
256 struct mbuf *m;
257 struct sockaddr_in oldaddr;
258 int error, hostIsNew, maskIsNew;
259 u_long i;
260
261 /*
262 * Find address for this interface, if it exists.
263 */
264 if (ifp)
265 for (ia = in_ifaddr; ia; ia = ia->ia_next)
266 if (ia->ia_ifp == ifp)
267 break;
268
269 switch (cmd) {
270
271 case SIOCAIFADDR:
272 case SIOCDIFADDR:
273 if (ifra->ifra_addr.sin_family == AF_INET)
274 for (oia = ia; ia; ia = ia->ia_next) {
275 if (ia->ia_ifp == ifp &&
276 ia->ia_addr.sin_addr.s_addr ==
277 ifra->ifra_addr.sin_addr.s_addr)
278 break;
279 }
280 if (cmd == SIOCDIFADDR && ia == 0)
281 return (EADDRNOTAVAIL);
282 /* FALLTHROUGH */
283 case SIOCSIFADDR:
284 case SIOCSIFNETMASK:
285 case SIOCSIFDSTADDR:
286 if ((so->so_state & SS_PRIV) == 0)
287 return (EPERM);
288
289 if (ifp == 0)
290 panic("in_control");
291 if (ia == (struct in_ifaddr *)0) {
292 m = m_getclr(M_WAIT, MT_IFADDR);
293 if (m == (struct mbuf *)NULL)
294 return (ENOBUFS);
295 if (ia = in_ifaddr) {
296 for ( ; ia->ia_next; ia = ia->ia_next)
297 ;
298 ia->ia_next = mtod(m, struct in_ifaddr *);
299 } else
300 in_ifaddr = mtod(m, struct in_ifaddr *);
301 ia = mtod(m, struct in_ifaddr *);
302 if (ifa = ifp->if_addrlist) {
303 for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
304 ;
305 ifa->ifa_next = (struct ifaddr *) ia;
306 } else
307 ifp->if_addrlist = (struct ifaddr *) ia;
308 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
309 ia->ia_ifa.ifa_dstaddr
310 = (struct sockaddr *)&ia->ia_dstaddr;
311 ia->ia_ifa.ifa_netmask
312 = (struct sockaddr *)&ia->ia_sockmask;
313 ia->ia_sockmask.sin_len = 8;
314 if (ifp->if_flags & IFF_BROADCAST) {
315 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
316 ia->ia_broadaddr.sin_family = AF_INET;
317 }
318 ia->ia_ifp = ifp;
319 if (ifp != &loif)
320 in_interfaces++;
321 }
322 break;
323
324 case SIOCSIFBRDADDR:
325 if ((so->so_state & SS_PRIV) == 0)
326 return (EPERM);
327 /* FALLTHROUGH */
328
329 case SIOCGIFADDR:
330 case SIOCGIFNETMASK:
331 case SIOCGIFDSTADDR:
332 case SIOCGIFBRDADDR:
333 if (ia == (struct in_ifaddr *)0)
334 return (EADDRNOTAVAIL);
335 break;
336
337 default:
338 return (EOPNOTSUPP);
339 break;
340 }
341 switch (cmd) {
342
343 case SIOCGIFADDR:
344 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
345 break;
346
347 case SIOCGIFBRDADDR:
348 if ((ifp->if_flags & IFF_BROADCAST) == 0)
349 return (EINVAL);
350 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
351 break;
352
353 case SIOCGIFDSTADDR:
354 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
355 return (EINVAL);
356 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
357 break;
358
359 case SIOCGIFNETMASK:
360 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
361 break;
362
363 case SIOCSIFDSTADDR:
364 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
365 return (EINVAL);
366 oldaddr = ia->ia_dstaddr;
367 ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
368 if (ifp->if_ioctl &&
4c45483e
GW
369 (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR,
370 (caddr_t)ia))) {
15637ed4
RG
371 ia->ia_dstaddr = oldaddr;
372 return (error);
373 }
374 if (ia->ia_flags & IFA_ROUTE) {
375 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
376 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
377 ia->ia_ifa.ifa_dstaddr =
378 (struct sockaddr *)&ia->ia_dstaddr;
379 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
380 }
381 break;
382
383 case SIOCSIFBRDADDR:
384 if ((ifp->if_flags & IFF_BROADCAST) == 0)
385 return (EINVAL);
386 ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
387 break;
388
389 case SIOCSIFADDR:
390 return (in_ifinit(ifp, ia,
391 (struct sockaddr_in *) &ifr->ifr_addr, 1));
392
393 case SIOCSIFNETMASK:
394 i = ifra->ifra_addr.sin_addr.s_addr;
395 ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
396 break;
397
398 case SIOCAIFADDR:
399 maskIsNew = 0;
400 hostIsNew = 1;
401 error = 0;
402 if (ia->ia_addr.sin_family == AF_INET) {
403 if (ifra->ifra_addr.sin_len == 0) {
404 ifra->ifra_addr = ia->ia_addr;
405 hostIsNew = 0;
406 } else if (ifra->ifra_addr.sin_addr.s_addr ==
407 ia->ia_addr.sin_addr.s_addr)
408 hostIsNew = 0;
409 }
410 if (ifra->ifra_mask.sin_len) {
411 in_ifscrub(ifp, ia);
412 ia->ia_sockmask = ifra->ifra_mask;
413 ia->ia_subnetmask =
414 ntohl(ia->ia_sockmask.sin_addr.s_addr);
415 maskIsNew = 1;
416 }
417 if ((ifp->if_flags & IFF_POINTOPOINT) &&
418 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
419 in_ifscrub(ifp, ia);
420 ia->ia_dstaddr = ifra->ifra_dstaddr;
421 maskIsNew = 1; /* We lie; but the effect's the same */
422 }
423 if (ifra->ifra_addr.sin_family == AF_INET &&
424 (hostIsNew || maskIsNew))
425 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
426 if ((ifp->if_flags & IFF_BROADCAST) &&
427 (ifra->ifra_broadaddr.sin_family == AF_INET))
428 ia->ia_broadaddr = ifra->ifra_broadaddr;
429 return (error);
430
431 case SIOCDIFADDR:
432 in_ifscrub(ifp, ia);
433 if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
434 ifp->if_addrlist = ifa->ifa_next;
435 else {
436 while (ifa->ifa_next &&
437 (ifa->ifa_next != (struct ifaddr *)ia))
438 ifa = ifa->ifa_next;
439 if (ifa->ifa_next)
440 ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
441 else
442 printf("Couldn't unlink inifaddr from ifp\n");
443 }
444 oia = ia;
445 if (oia == (ia = in_ifaddr))
446 in_ifaddr = ia->ia_next;
447 else {
448 while (ia->ia_next && (ia->ia_next != oia))
449 ia = ia->ia_next;
450 if (ia->ia_next)
451 ia->ia_next = oia->ia_next;
452 else
453 printf("Didn't unlink inifadr from list\n");
454 }
455 (void) m_free(dtom(oia));
456 break;
457
458 default:
459 if (ifp == 0 || ifp->if_ioctl == 0)
460 return (EOPNOTSUPP);
461 return ((*ifp->if_ioctl)(ifp, cmd, data));
462 }
463 return (0);
464}
465
466/*
467 * Delete any existing route for an interface.
468 */
4c45483e 469static void
15637ed4
RG
470in_ifscrub(ifp, ia)
471 register struct ifnet *ifp;
472 register struct in_ifaddr *ia;
473{
474
475 if ((ia->ia_flags & IFA_ROUTE) == 0)
476 return;
477 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
478 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
479 else
480 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
481 ia->ia_flags &= ~IFA_ROUTE;
482}
483
484/*
485 * Initialize an interface's internet address
486 * and routing table entry.
487 */
4c45483e 488int
15637ed4
RG
489in_ifinit(ifp, ia, sin, scrub)
490 register struct ifnet *ifp;
491 register struct in_ifaddr *ia;
492 struct sockaddr_in *sin;
4c45483e 493 int scrub;
15637ed4
RG
494{
495 register u_long i = ntohl(sin->sin_addr.s_addr);
496 struct sockaddr_in oldaddr;
497 int s = splimp(), error, flags = RTF_UP;
498
499 oldaddr = ia->ia_addr;
500 ia->ia_addr = *sin;
501 /*
502 * Give the interface a chance to initialize
503 * if this is its first address,
504 * and to validate the address if necessary.
505 */
4c45483e
GW
506 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR,
507 (caddr_t)ia))) {
15637ed4
RG
508 splx(s);
509 ia->ia_addr = oldaddr;
510 return (error);
511 }
512 splx(s);
513 if (scrub) {
514 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
515 in_ifscrub(ifp, ia);
516 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
517 }
518 if (IN_CLASSA(i))
519 ia->ia_netmask = IN_CLASSA_NET;
520 else if (IN_CLASSB(i))
521 ia->ia_netmask = IN_CLASSB_NET;
522 else
523 ia->ia_netmask = IN_CLASSC_NET;
524 ia->ia_net = i & ia->ia_netmask;
525 /*
526 * The subnet mask includes at least the standard network part,
527 * but may already have been set to a larger value.
528 */
529 ia->ia_subnetmask |= ia->ia_netmask;
530 ia->ia_subnet = i & ia->ia_subnetmask;
531 ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
532 {
533 register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
534 register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
535 while (--cp >= cpbase)
536 if (*cp) {
537 ia->ia_sockmask.sin_len =
538 1 + cp - (char *) &(ia->ia_sockmask);
539 break;
540 }
541 }
542 /*
543 * Add route for the network.
544 */
545 if (ifp->if_flags & IFF_BROADCAST) {
546 ia->ia_broadaddr.sin_addr =
547 in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
548 ia->ia_netbroadcast.s_addr =
549 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
550 } else if (ifp->if_flags & IFF_LOOPBACK) {
551 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
552 flags |= RTF_HOST;
553 } else if (ifp->if_flags & IFF_POINTOPOINT) {
554 if (ia->ia_dstaddr.sin_family != AF_INET)
555 return (0);
556 flags |= RTF_HOST;
557 }
558 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
559 ia->ia_flags |= IFA_ROUTE;
560 return (error);
561}
562
563/*
564 * Return address info for specified internet network.
565 */
566struct in_ifaddr *
567in_iaonnetof(net)
568 u_long net;
569{
570 register struct in_ifaddr *ia;
571
572 for (ia = in_ifaddr; ia; ia = ia->ia_next)
573 if (ia->ia_subnet == net)
574 return (ia);
575 return ((struct in_ifaddr *)0);
576}
577
578/*
579 * Return 1 if the address might be a local broadcast address.
580 */
4c45483e 581int
15637ed4
RG
582in_broadcast(in)
583 struct in_addr in;
584{
585 register struct in_ifaddr *ia;
586 u_long t;
587
588 /*
589 * Look through the list of addresses for a match
590 * with a broadcast address.
591 */
592 for (ia = in_ifaddr; ia; ia = ia->ia_next)
593 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
594 if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
595 return (1);
596 /*
597 * Check for old-style (host 0) broadcast.
598 */
599 if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
600 return (1);
601 }
602 if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
603 return (1);
604 return (0);
605}
606#endif