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