in.c revision 1.28 1 /* $NetBSD: in.c,v 1.28 1996/05/22 14:42:27 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 #include <sys/systm.h>
45 #include <sys/proc.h>
46
47 #include <net/if.h>
48 #include <net/route.h>
49
50 #include <netinet/in_systm.h>
51 #include <netinet/in.h>
52 #include <netinet/in_var.h>
53 #include <netinet/if_ether.h>
54 #include <netinet/ip_mroute.h>
55 #include <netinet/igmp_var.h>
56
57 #include "ether.h"
58
59 #ifdef INET
60
61 #ifndef SUBNETSARELOCAL
62 #define SUBNETSARELOCAL 1
63 #endif
64 int subnetsarelocal = SUBNETSARELOCAL;
65 /*
66 * Return 1 if an internet address is for a ``local'' host
67 * (one to which we have a connection). If subnetsarelocal
68 * is true, this includes other subnets of the local net.
69 * Otherwise, it includes only the directly-connected (sub)nets.
70 */
71 int
72 in_localaddr(in)
73 struct in_addr in;
74 {
75 register struct in_ifaddr *ia;
76
77 if (subnetsarelocal) {
78 for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
79 if ((in.s_addr & ia->ia_netmask) == ia->ia_net)
80 return (1);
81 } else {
82 for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
83 if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet)
84 return (1);
85 }
86 return (0);
87 }
88
89 /*
90 * Determine whether an IP address is in a reserved set of addresses
91 * that may not be forwarded, or whether datagrams to that destination
92 * may be forwarded.
93 */
94 int
95 in_canforward(in)
96 struct in_addr in;
97 {
98 register u_int32_t net;
99
100 if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
101 return (0);
102 if (IN_CLASSA(in.s_addr)) {
103 net = in.s_addr & IN_CLASSA_NET;
104 if (net == 0 || net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
105 return (0);
106 }
107 return (1);
108 }
109
110 /*
111 * Trim a mask in a sockaddr
112 */
113 void
114 in_socktrim(ap)
115 struct sockaddr_in *ap;
116 {
117 register char *cplim = (char *) &ap->sin_addr;
118 register char *cp = (char *) (&ap->sin_addr + 1);
119
120 ap->sin_len = 0;
121 while (--cp >= cplim)
122 if (*cp) {
123 (ap)->sin_len = cp - (char *) (ap) + 1;
124 break;
125 }
126 }
127
128 int in_interfaces; /* number of external internet interfaces */
129
130 /*
131 * Generic internet control operations (ioctl's).
132 * Ifp is 0 if not an interface-specific ioctl.
133 */
134 /* ARGSUSED */
135 int
136 in_control(so, cmd, data, ifp, p)
137 struct socket *so;
138 u_long cmd;
139 caddr_t data;
140 register struct ifnet *ifp;
141 struct proc *p;
142 {
143 register struct ifreq *ifr = (struct ifreq *)data;
144 register struct in_ifaddr *ia = 0;
145 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
146 struct sockaddr_in oldaddr;
147 int error, hostIsNew, maskIsNew;
148
149 /*
150 * Find address for this interface, if it exists.
151 */
152 if (ifp)
153 for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
154 if (ia->ia_ifp == ifp)
155 break;
156
157 switch (cmd) {
158
159 case SIOCAIFADDR:
160 case SIOCDIFADDR:
161 if (ifra->ifra_addr.sin_family == AF_INET)
162 for (; ia != 0; ia = ia->ia_list.tqe_next) {
163 if (ia->ia_ifp == ifp &&
164 SAME_INADDR(&ia->ia_addr, &ifra->ifra_addr))
165 break;
166 }
167 if (cmd == SIOCDIFADDR && ia == 0)
168 return (EADDRNOTAVAIL);
169 /* FALLTHROUGH */
170 case SIOCSIFADDR:
171 case SIOCSIFNETMASK:
172 case SIOCSIFDSTADDR:
173 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
174 return (EPERM);
175
176 if (ifp == 0)
177 panic("in_control");
178 if (ia == 0) {
179 MALLOC(ia, struct in_ifaddr *, sizeof(*ia),
180 M_IFADDR, M_WAITOK);
181 if (ia == 0)
182 return (ENOBUFS);
183 bzero((caddr_t)ia, sizeof *ia);
184 TAILQ_INSERT_TAIL(&in_ifaddr, ia, ia_list);
185 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
186 ifa_list);
187 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
188 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
189 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
190 ia->ia_sockmask.sin_len = 8;
191 if (ifp->if_flags & IFF_BROADCAST) {
192 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
193 ia->ia_broadaddr.sin_family = AF_INET;
194 }
195 ia->ia_ifp = ifp;
196 LIST_INIT(&ia->ia_multiaddrs);
197 if ((ifp->if_flags & IFF_LOOPBACK) == 0)
198 in_interfaces++;
199 }
200 break;
201
202 case SIOCSIFBRDADDR:
203 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
204 return (EPERM);
205 /* FALLTHROUGH */
206
207 case SIOCGIFADDR:
208 case SIOCGIFNETMASK:
209 case SIOCGIFDSTADDR:
210 case SIOCGIFBRDADDR:
211 if (ia == 0)
212 return (EADDRNOTAVAIL);
213 break;
214 }
215 switch (cmd) {
216
217 case SIOCGIFADDR:
218 *satosin(&ifr->ifr_addr) = ia->ia_addr;
219 break;
220
221 case SIOCGIFBRDADDR:
222 if ((ifp->if_flags & IFF_BROADCAST) == 0)
223 return (EINVAL);
224 *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
225 break;
226
227 case SIOCGIFDSTADDR:
228 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
229 return (EINVAL);
230 *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
231 break;
232
233 case SIOCGIFNETMASK:
234 *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
235 break;
236
237 case SIOCSIFDSTADDR:
238 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
239 return (EINVAL);
240 oldaddr = ia->ia_dstaddr;
241 ia->ia_dstaddr = *satosin(&ifr->ifr_dstaddr);
242 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
243 (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
244 ia->ia_dstaddr = oldaddr;
245 return (error);
246 }
247 if (ia->ia_flags & IFA_ROUTE) {
248 ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr);
249 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
250 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
251 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
252 }
253 break;
254
255 case SIOCSIFBRDADDR:
256 if ((ifp->if_flags & IFF_BROADCAST) == 0)
257 return (EINVAL);
258 ia->ia_broadaddr = *satosin(&ifr->ifr_broadaddr);
259 break;
260
261 case SIOCSIFADDR:
262 return (in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1));
263
264 case SIOCSIFNETMASK:
265 ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr =
266 ifra->ifra_addr.sin_addr.s_addr;
267 break;
268
269 case SIOCAIFADDR:
270 maskIsNew = 0;
271 hostIsNew = 1;
272 error = 0;
273 if (ia->ia_addr.sin_family == AF_INET) {
274 if (ifra->ifra_addr.sin_len == 0) {
275 ifra->ifra_addr = ia->ia_addr;
276 hostIsNew = 0;
277 } else if (SAME_INADDR(&ia->ia_addr, &ifra->ifra_addr))
278 hostIsNew = 0;
279 }
280 if (ifra->ifra_mask.sin_len) {
281 in_ifscrub(ifp, ia);
282 ia->ia_sockmask = ifra->ifra_mask;
283 ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
284 maskIsNew = 1;
285 }
286 if ((ifp->if_flags & IFF_POINTOPOINT) &&
287 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
288 in_ifscrub(ifp, ia);
289 ia->ia_dstaddr = ifra->ifra_dstaddr;
290 maskIsNew = 1; /* We lie; but the effect's the same */
291 }
292 if (ifra->ifra_addr.sin_family == AF_INET &&
293 (hostIsNew || maskIsNew))
294 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
295 if ((ifp->if_flags & IFF_BROADCAST) &&
296 (ifra->ifra_broadaddr.sin_family == AF_INET))
297 ia->ia_broadaddr = ifra->ifra_broadaddr;
298 return (error);
299
300 case SIOCDIFADDR:
301 in_ifscrub(ifp, ia);
302 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
303 TAILQ_REMOVE(&in_ifaddr, ia, ia_list);
304 IFAFREE((&ia->ia_ifa));
305 break;
306
307 #ifdef MROUTING
308 case SIOCGETVIFCNT:
309 case SIOCGETSGCNT:
310 return (mrt_ioctl(cmd, data));
311 #endif /* MROUTING */
312
313 default:
314 if (ifp == 0 || ifp->if_ioctl == 0)
315 return (EOPNOTSUPP);
316 return ((*ifp->if_ioctl)(ifp, cmd, data));
317 }
318 return (0);
319 }
320
321 /*
322 * Delete any existing route for an interface.
323 */
324 void
325 in_ifscrub(ifp, ia)
326 register struct ifnet *ifp;
327 register struct in_ifaddr *ia;
328 {
329
330 if ((ia->ia_flags & IFA_ROUTE) == 0)
331 return;
332 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
333 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
334 else
335 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
336 ia->ia_flags &= ~IFA_ROUTE;
337 }
338
339 /*
340 * Initialize an interface's internet address
341 * and routing table entry.
342 */
343 int
344 in_ifinit(ifp, ia, sin, scrub)
345 register struct ifnet *ifp;
346 register struct in_ifaddr *ia;
347 struct sockaddr_in *sin;
348 int scrub;
349 {
350 register u_int32_t i = sin->sin_addr.s_addr;
351 struct sockaddr_in oldaddr;
352 int s = splimp(), flags = RTF_UP, error;
353
354 oldaddr = ia->ia_addr;
355 ia->ia_addr = *sin;
356 /*
357 * Give the interface a chance to initialize
358 * if this is its first address,
359 * and to validate the address if necessary.
360 */
361 if (ifp->if_ioctl &&
362 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
363 splx(s);
364 ia->ia_addr = oldaddr;
365 return (error);
366 }
367 splx(s);
368 if (scrub) {
369 ia->ia_ifa.ifa_addr = sintosa(&oldaddr);
370 in_ifscrub(ifp, ia);
371 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
372 }
373 if (IN_CLASSA(i))
374 ia->ia_netmask = IN_CLASSA_NET;
375 else if (IN_CLASSB(i))
376 ia->ia_netmask = IN_CLASSB_NET;
377 else
378 ia->ia_netmask = IN_CLASSC_NET;
379 /*
380 * The subnet mask usually includes at least the standard network part,
381 * but may may be smaller in the case of supernetting.
382 * If it is set, we believe it.
383 */
384 if (ia->ia_subnetmask == 0) {
385 ia->ia_subnetmask = ia->ia_netmask;
386 ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask;
387 } else
388 ia->ia_netmask &= ia->ia_subnetmask;
389 ia->ia_net = i & ia->ia_netmask;
390 ia->ia_subnet = i & ia->ia_subnetmask;
391 in_socktrim(&ia->ia_sockmask);
392 /*
393 * Add route for the network.
394 */
395 ia->ia_ifa.ifa_metric = ifp->if_metric;
396 if (ifp->if_flags & IFF_BROADCAST) {
397 ia->ia_broadaddr.sin_addr.s_addr =
398 ia->ia_subnet | ~ia->ia_subnetmask;
399 ia->ia_netbroadcast.s_addr =
400 ia->ia_net | ~ia->ia_netmask;
401 } else if (ifp->if_flags & IFF_LOOPBACK) {
402 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
403 flags |= RTF_HOST;
404 } else if (ifp->if_flags & IFF_POINTOPOINT) {
405 if (ia->ia_dstaddr.sin_family != AF_INET)
406 return (0);
407 flags |= RTF_HOST;
408 }
409 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
410 ia->ia_flags |= IFA_ROUTE;
411 /*
412 * If the interface supports multicast, join the "all hosts"
413 * multicast group on that interface.
414 */
415 if (ifp->if_flags & IFF_MULTICAST) {
416 struct in_addr addr;
417
418 addr.s_addr = INADDR_ALLHOSTS_GROUP;
419 in_addmulti(&addr, ifp);
420 }
421 return (error);
422 }
423
424
425 /*
426 * Return 1 if the address might be a local broadcast address.
427 */
428 int
429 in_broadcast(in, ifp)
430 struct in_addr in;
431 struct ifnet *ifp;
432 {
433 register struct ifaddr *ifa;
434
435 if (in.s_addr == INADDR_BROADCAST ||
436 in.s_addr == INADDR_ANY)
437 return 1;
438 if ((ifp->if_flags & IFF_BROADCAST) == 0)
439 return 0;
440 /*
441 * Look through the list of addresses for a match
442 * with a broadcast address.
443 */
444 #define ia (ifatoia(ifa))
445 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
446 if (ifa->ifa_addr->sa_family == AF_INET &&
447 (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
448 in.s_addr == ia->ia_netbroadcast.s_addr ||
449 /*
450 * Check for old-style (host 0) broadcast.
451 */
452 in.s_addr == ia->ia_subnet ||
453 in.s_addr == ia->ia_net))
454 return 1;
455 return (0);
456 #undef ia
457 }
458
459 /*
460 * Add an address to the list of IP multicast addresses for a given interface.
461 */
462 struct in_multi *
463 in_addmulti(ap, ifp)
464 register struct in_addr *ap;
465 register struct ifnet *ifp;
466 {
467 register struct in_multi *inm;
468 struct ifreq ifr;
469 struct in_ifaddr *ia;
470 int s = splsoftnet();
471
472 /*
473 * See if address already in list.
474 */
475 IN_LOOKUP_MULTI(*ap, ifp, inm);
476 if (inm != NULL) {
477 /*
478 * Found it; just increment the reference count.
479 */
480 ++inm->inm_refcount;
481 } else {
482 /*
483 * New address; allocate a new multicast record
484 * and link it into the interface's multicast list.
485 */
486 inm = (struct in_multi *)malloc(sizeof(*inm),
487 M_IPMADDR, M_NOWAIT);
488 if (inm == NULL) {
489 splx(s);
490 return (NULL);
491 }
492 inm->inm_addr = *ap;
493 inm->inm_ifp = ifp;
494 inm->inm_refcount = 1;
495 IFP_TO_IA(ifp, ia);
496 if (ia == NULL) {
497 free(inm, M_IPMADDR);
498 splx(s);
499 return (NULL);
500 }
501 inm->inm_ia = ia;
502 LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_list);
503 /*
504 * Ask the network driver to update its multicast reception
505 * filter appropriately for the new address.
506 */
507 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
508 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
509 satosin(&ifr.ifr_addr)->sin_addr = *ap;
510 if ((ifp->if_ioctl == NULL) ||
511 (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
512 LIST_REMOVE(inm, inm_list);
513 free(inm, M_IPMADDR);
514 splx(s);
515 return (NULL);
516 }
517 /*
518 * Let IGMP know that we have joined a new IP multicast group.
519 */
520 igmp_joingroup(inm);
521 }
522 splx(s);
523 return (inm);
524 }
525
526 /*
527 * Delete a multicast address record.
528 */
529 void
530 in_delmulti(inm)
531 register struct in_multi *inm;
532 {
533 struct ifreq ifr;
534 int s = splsoftnet();
535
536 if (--inm->inm_refcount == 0) {
537 /*
538 * No remaining claims to this record; let IGMP know that
539 * we are leaving the multicast group.
540 */
541 igmp_leavegroup(inm);
542 /*
543 * Unlink from list.
544 */
545 LIST_REMOVE(inm, inm_list);
546 /*
547 * Notify the network driver to update its multicast reception
548 * filter.
549 */
550 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
551 satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
552 (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
553 (caddr_t)&ifr);
554 free(inm, M_IPMADDR);
555 }
556 splx(s);
557 }
558
559 #endif
560