tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / netinet / in.c
blob2d9dc6e8e44a3683d4d474053bbfbbd420911b89
1 /*
2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
4 * All rights reserved.
5 * Copyright (C) 2005 Neil Cafferkey
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
24 * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
55 * @(#)in.c 7.17 (Berkeley) 4/20/91
58 #include <conf.h>
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/ioctl.h>
63 #include <sys/malloc.h>
64 #include <sys/mbuf.h>
65 #include <sys/socket.h>
66 #include <sys/socketvar.h>
67 #include <sys/synch.h>
69 #include <netinet/in_systm.h>
70 #include <net/if.h>
71 #include <net/route.h>
72 #include <netinet/in.h>
73 #include <netinet/in_var.h>
75 #include <netinet/in_protos.h>
77 #if INET
79 * Formulate an Internet address from network + host.
81 struct in_addr
82 in_makeaddr(net, host)
83 u_long net, host;
85 register struct in_ifaddr *ia;
86 register u_long mask;
87 union {
88 u_long addr;
89 struct in_addr in_addr;
90 } __tmp;
92 if (IN_CLASSA(net))
93 mask = IN_CLASSA_HOST;
94 else if (IN_CLASSB(net))
95 mask = IN_CLASSB_HOST;
96 else
97 mask = IN_CLASSC_HOST;
98 for (ia = in_ifaddr; ia; ia = ia->ia_next)
99 if ((ia->ia_netmask & net) == ia->ia_net) {
100 mask = ~ia->ia_subnetmask;
101 break;
103 __tmp.addr = htonl(net | (host & mask));
104 return __tmp.in_addr;
108 * Return the network number from an internet address.
110 u_long
111 in_netof(in)
112 struct in_addr in;
114 register u_long i = ntohl(in.s_addr);
115 register u_long net;
116 register struct in_ifaddr *ia;
118 if (IN_CLASSA(i))
119 net = i & IN_CLASSA_NET;
120 else if (IN_CLASSB(i))
121 net = i & IN_CLASSB_NET;
122 else if (IN_CLASSC(i))
123 net = i & IN_CLASSC_NET;
124 else
125 return (0);
128 * Check whether network is a subnet;
129 * if so, return subnet number.
131 for (ia = in_ifaddr; ia; ia = ia->ia_next)
132 if (net == ia->ia_net)
133 return (i & ia->ia_subnetmask);
134 return (net);
138 * Compute and save network mask as sockaddr from an internet address.
140 void
141 in_sockmaskof(in, sockmask)
142 struct in_addr in;
143 register struct sockaddr_in *sockmask;
145 register u_long net;
146 register u_long mask;
148 register u_long i = ntohl(in.s_addr);
150 if (i == 0)
151 net = 0, mask = 0;
152 else if (IN_CLASSA(i))
153 net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
154 else if (IN_CLASSB(i))
155 net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
156 else if (IN_CLASSC(i))
157 net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
158 else
159 net = i, mask = -1;
162 register struct in_ifaddr *ia;
164 * Check whether network is a subnet;
165 * if so, return subnet number.
167 for (ia = in_ifaddr; ia; ia = ia->ia_next)
168 if (net == ia->ia_net)
169 mask = ia->ia_subnetmask;
172 register char *cpbase = (char *)&(sockmask->sin_addr);
173 register char *cp = (char *)(1 + &(sockmask->sin_addr));
175 sockmask->sin_addr.s_addr = htonl(mask);
176 sockmask->sin_len = 0;
177 while (--cp >= cpbase)
178 if (*cp) {
179 sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
180 break;
186 * Return the host portion of an internet address.
188 u_long
189 in_lnaof(in)
190 struct in_addr in;
192 register u_long i = ntohl(in.s_addr);
193 register u_long net, host;
194 register struct in_ifaddr *ia;
196 if (IN_CLASSA(i)) {
197 net = i & IN_CLASSA_NET;
198 host = i & IN_CLASSA_HOST;
199 } else if (IN_CLASSB(i)) {
200 net = i & IN_CLASSB_NET;
201 host = i & IN_CLASSB_HOST;
202 } else if (IN_CLASSC(i)) {
203 net = i & IN_CLASSC_NET;
204 host = i & IN_CLASSC_HOST;
205 } else
206 return (i);
209 * Check whether network is a subnet;
210 * if so, use the modified interpretation of `host'.
212 for (ia = in_ifaddr; ia; ia = ia->ia_next)
213 if (net == ia->ia_net)
214 return (host &~ ia->ia_subnetmask);
215 return (host);
218 #ifndef SUBNETSARELOCAL
219 #define SUBNETSARELOCAL 1
220 #endif
221 int subnetsarelocal = SUBNETSARELOCAL;
223 * Return 1 if an internet address is for a ``local'' host
224 * (one to which we have a connection). If subnetsarelocal
225 * is true, this includes other subnets of the local net.
226 * Otherwise, it includes only the directly-connected (sub)nets.
229 in_localaddr(in)
230 struct in_addr in;
232 register u_long i = ntohl(in.s_addr);
233 register struct in_ifaddr *ia;
235 if (subnetsarelocal) {
236 for (ia = in_ifaddr; ia; ia = ia->ia_next)
237 if ((i & ia->ia_netmask) == ia->ia_net)
238 return (1);
239 } else {
240 for (ia = in_ifaddr; ia; ia = ia->ia_next)
241 if ((i & ia->ia_subnetmask) == ia->ia_subnet)
242 return (1);
244 return (0);
248 * Determine whether an IP address is in a reserved set of addresses
249 * that may not be forwarded, or whether datagrams to that destination
250 * may be forwarded.
253 in_canforward(in)
254 struct in_addr in;
256 register u_long i = ntohl(in.s_addr);
257 register u_long net;
259 if (IN_EXPERIMENTAL(i))
260 return (0);
261 if (IN_CLASSA(i)) {
262 net = i & IN_CLASSA_NET;
263 if (net == 0 || net == IN_LOOPBACKNET)
264 return (0);
266 return (1);
269 int in_interfaces; /* number of external internet interfaces */
270 extern struct ifnet loif;
273 * Generic internet control operations (ioctl's).
274 * Ifp is 0 if not an interface-specific ioctl.
277 in_control(so, cmd, data, ifp)
278 struct socket *so;
279 int cmd;
280 caddr_t data;
281 register struct ifnet *ifp;
283 register struct ifreq *ifr = (struct ifreq *)data;
284 register struct in_ifaddr *ia = 0;
285 register struct ifaddr *ifa;
286 struct in_ifaddr *oia;
287 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
288 struct mbuf *m;
289 struct sockaddr_in oldaddr;
290 int error, hostIsNew, maskIsNew;
291 u_long i;
294 * Find address for this interface, if it exists.
296 if (ifp)
297 for (ia = in_ifaddr; ia; ia = ia->ia_next)
298 if (ia->ia_ifp == ifp)
299 break;
301 switch (cmd) {
303 case SIOCAIFADDR:
304 case SIOCDIFADDR:
305 if (ifra->ifra_addr.sin_family == AF_INET)
306 for (oia = ia; ia; ia = ia->ia_next) {
307 if (ia->ia_ifp == ifp &&
308 ia->ia_addr.sin_addr.s_addr ==
309 ifra->ifra_addr.sin_addr.s_addr)
310 break;
312 if (cmd == SIOCDIFADDR && ia == 0)
313 return (EADDRNOTAVAIL);
314 /* FALLTHROUGH */
315 case SIOCSIFADDR:
316 case SIOCSIFNETMASK:
317 case SIOCSIFDSTADDR:
318 /* if ((so->so_state & SS_PRIV) == 0)
319 return (EPERM);*/
321 if (ifp == 0)
322 panic("in_control");
323 if (ia == (struct in_ifaddr *)0) {
324 m = m_getclr(M_WAIT, MT_IFADDR);
325 if (m == (struct mbuf *)NULL)
326 return (ENOBUFS);
327 if (ia = in_ifaddr) {
328 for ( ; ia->ia_next; ia = ia->ia_next)
330 ia->ia_next = mtod(m, struct in_ifaddr *);
331 } else
332 in_ifaddr = mtod(m, struct in_ifaddr *);
333 ia = mtod(m, struct in_ifaddr *);
334 if (ifa = ifp->if_addrlist) {
335 for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
337 ifa->ifa_next = (struct ifaddr *) ia;
338 } else
339 ifp->if_addrlist = (struct ifaddr *) ia;
340 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
341 ia->ia_ifa.ifa_dstaddr
342 = (struct sockaddr *)&ia->ia_dstaddr;
343 ia->ia_ifa.ifa_netmask
344 = (struct sockaddr *)&ia->ia_sockmask;
345 ia->ia_sockmask.sin_len = 8;
346 if (ifp->if_flags & IFF_BROADCAST) {
347 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
348 ia->ia_broadaddr.sin_family = AF_INET;
350 ia->ia_ifp = ifp;
351 if (ifp != &loif)
352 in_interfaces++;
354 break;
356 case SIOCSIFBRDADDR:
357 /* if ((so->so_state & SS_PRIV) == 0)
358 return (EPERM);*/
359 /* FALLTHROUGH */
361 case SIOCGIFADDR:
362 case SIOCGIFNETMASK:
363 case SIOCGIFDSTADDR:
364 case SIOCGIFBRDADDR:
365 if (ia == (struct in_ifaddr *)0)
366 return (EADDRNOTAVAIL);
367 break;
369 default:
370 return (EOPNOTSUPP);
371 break;
373 switch (cmd) {
375 case SIOCGIFADDR:
377 struct sockaddr_in *ifr_saddr = (struct sockaddr_in *)&ifr->ifr_addr;
378 *ifr_saddr = ia->ia_addr;
380 break;
382 case SIOCGIFBRDADDR:
384 struct sockaddr_in *ifrdst_saddr = (struct sockaddr_in *)&ifr->ifr_dstaddr;
385 if ((ifp->if_flags & IFF_BROADCAST) == 0)
386 return (EINVAL);
387 *ifrdst_saddr = ia->ia_broadaddr;
389 break;
391 case SIOCGIFDSTADDR:
393 struct sockaddr_in *ifrdst_saddr = (struct sockaddr_in *)&ifr->ifr_dstaddr;
394 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
395 return (EINVAL);
396 *ifrdst_saddr = ia->ia_dstaddr;
398 break;
400 case SIOCGIFNETMASK:
402 struct sockaddr_in *ifr_saddr = (struct sockaddr_in *)&ifr->ifr_addr;
403 *ifr_saddr = ia->ia_sockmask;
405 break;
407 case SIOCSIFDSTADDR:
409 struct sockaddr_in *ifrdst_saddr = (struct sockaddr_in *)&ifr->ifr_dstaddr;
410 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
411 return (EINVAL);
412 oldaddr = ia->ia_dstaddr;
413 ia->ia_dstaddr = *ifrdst_saddr;
414 if (ifp->if_ioctl &&
415 (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
416 ia->ia_dstaddr = oldaddr;
417 return (error);
419 if (ia->ia_flags & IFA_ROUTE) {
420 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
421 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
422 ia->ia_ifa.ifa_dstaddr =
423 (struct sockaddr *)&ia->ia_dstaddr;
424 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
427 break;
429 case SIOCSIFBRDADDR:
431 struct sockaddr_in *ifrbrd_saddr = (struct sockaddr_in *)&ifr->ifr_broadaddr;
432 if ((ifp->if_flags & IFF_BROADCAST) == 0)
433 return (EINVAL);
434 ia->ia_broadaddr = *ifrbrd_saddr;
436 break;
438 case SIOCSIFADDR:
439 return (in_ifinit(ifp, ia,
440 (struct sockaddr_in *) &ifr->ifr_addr, 1));
442 case SIOCSIFNETMASK:
443 i = ifra->ifra_addr.sin_addr.s_addr;
444 ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
445 break;
447 case SIOCAIFADDR:
448 maskIsNew = 0;
449 hostIsNew = 1;
450 error = 0;
451 if (ia->ia_addr.sin_family == AF_INET) {
452 if (ifra->ifra_addr.sin_len == 0) {
453 ifra->ifra_addr = ia->ia_addr;
454 hostIsNew = 0;
455 } else if (ifra->ifra_addr.sin_addr.s_addr ==
456 ia->ia_addr.sin_addr.s_addr)
457 hostIsNew = 0;
459 if (ifra->ifra_mask.sin_len) {
460 in_ifscrub(ifp, ia);
461 ia->ia_sockmask = ifra->ifra_mask;
462 ia->ia_subnetmask =
463 ntohl(ia->ia_sockmask.sin_addr.s_addr);
464 maskIsNew = 1;
466 if ((ifp->if_flags & IFF_POINTOPOINT) &&
467 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
468 in_ifscrub(ifp, ia);
469 ia->ia_dstaddr = ifra->ifra_dstaddr;
470 maskIsNew = 1; /* We lie; but the effect's the same */
472 if (ifra->ifra_addr.sin_family == AF_INET &&
473 (hostIsNew || maskIsNew))
474 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
475 if ((ifp->if_flags & IFF_BROADCAST) &&
476 (ifra->ifra_broadaddr.sin_family == AF_INET))
477 ia->ia_broadaddr = ifra->ifra_broadaddr;
478 return (error);
480 case SIOCDIFADDR:
481 in_ifscrub(ifp, ia);
482 if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
483 ifp->if_addrlist = ifa->ifa_next;
484 else {
485 while (ifa->ifa_next &&
486 (ifa->ifa_next != (struct ifaddr *)ia))
487 ifa = ifa->ifa_next;
488 if (ifa->ifa_next)
489 ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
490 else
491 printf("Couldn't unlink inifaddr from ifp\n");
493 oia = ia;
494 if (oia == (ia = in_ifaddr))
495 in_ifaddr = ia->ia_next;
496 else {
497 while (ia->ia_next && (ia->ia_next != oia))
498 ia = ia->ia_next;
499 if (ia->ia_next)
500 ia->ia_next = oia->ia_next;
501 else
502 printf("Didn't unlink inifadr from list\n");
504 (void) m_free(dtom(oia));
505 break;
507 default:
508 if (ifp == 0 || ifp->if_ioctl == 0)
509 return (EOPNOTSUPP);
510 return ((*ifp->if_ioctl)(ifp, cmd, data));
512 return (0);
516 * Delete any existing route for an interface.
518 void
519 in_ifscrub(ifp, ia)
520 register struct ifnet *ifp;
521 register struct in_ifaddr *ia;
524 if ((ia->ia_flags & IFA_ROUTE) == 0)
525 return;
526 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
527 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
528 else
529 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
530 ia->ia_flags &= ~IFA_ROUTE;
534 * Initialize an interface's internet address
535 * and routing table entry.
538 in_ifinit(ifp, ia, sin, scrub)
539 register struct ifnet *ifp;
540 register struct in_ifaddr *ia;
541 struct sockaddr_in *sin;
542 int scrub;
544 register u_long i = ntohl(sin->sin_addr.s_addr);
545 struct sockaddr_in oldaddr;
546 int error, flags = RTF_UP;
547 spl_t s = splimp();
549 oldaddr = ia->ia_addr;
550 ia->ia_addr = *sin;
552 * Give the interface a chance to initialize
553 * if this is its first address,
554 * and to validate the address if necessary.
556 if (ifp->if_ioctl
557 && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
558 splx(s);
559 ia->ia_addr = oldaddr;
560 return (error);
562 splx(s);
563 if (scrub) {
564 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
565 in_ifscrub(ifp, ia);
566 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
568 if (IN_CLASSA(i))
569 ia->ia_netmask = IN_CLASSA_NET;
570 else if (IN_CLASSB(i))
571 ia->ia_netmask = IN_CLASSB_NET;
572 else
573 ia->ia_netmask = IN_CLASSC_NET;
575 * The subnet mask usually includes at least the standard network part,
576 * but may may be smaller in the case of supernetting.
577 * If it is set, we believe it.
579 if (ia->ia_subnetmask == 0) {
580 ia->ia_subnetmask = ia->ia_netmask;
581 ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
582 } else
583 ia->ia_netmask &= ia->ia_subnetmask;
584 ia->ia_net = i & ia->ia_netmask;
585 ia->ia_subnet = i & ia->ia_subnetmask;
587 register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
588 register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
589 while (--cp >= cpbase)
590 if (*cp) {
591 ia->ia_sockmask.sin_len =
592 1 + cp - (char *) &(ia->ia_sockmask);
593 break;
597 * Add route for the network.
599 if (ifp->if_flags & IFF_BROADCAST) {
600 ia->ia_broadaddr.sin_addr =
601 in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
602 ia->ia_netbroadcast.s_addr =
603 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
604 } else if (ifp->if_flags & IFF_LOOPBACK) {
605 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
606 flags |= RTF_HOST;
607 } else if (ifp->if_flags & IFF_POINTOPOINT) {
608 if (ia->ia_dstaddr.sin_family != AF_INET)
609 return (0);
610 flags |= RTF_HOST;
612 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
613 ia->ia_flags |= IFA_ROUTE;
614 return (error);
618 * Return address info for specified internet network.
620 struct in_ifaddr *
621 in_iaonnetof(net)
622 u_long net;
624 register struct in_ifaddr *ia;
626 for (ia = in_ifaddr; ia; ia = ia->ia_next)
627 if (ia->ia_subnet == net)
628 return (ia);
629 return ((struct in_ifaddr *)0);
633 * Return 1 if the address might be a local broadcast address.
636 in_broadcast(in)
637 struct in_addr in;
639 register struct in_ifaddr *ia;
640 u_long t;
643 * Look through the list of addresses for a match
644 * with a broadcast address.
646 for (ia = in_ifaddr; ia; ia = ia->ia_next)
647 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
648 if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
649 return (1);
651 * Check for old-style (host 0) broadcast.
653 if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
654 return (1);
656 if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
657 return (1);
658 return (0);
660 #endif