revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / net / route.c
blobce4189de62a7ea28650d61bcf8ade3b13470fa44
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 - 2007 The AROS Dev Team
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.
23 /*
24 * Mach Operating System
25 * Copyright (c) 1992 Carnegie Mellon University
26 * All Rights Reserved.
28 * Permission to use, copy, modify and distribute this software and its
29 * documentation is hereby granted, provided that both the copyright
30 * notice and this permission notice appear in all copies of the
31 * software, derivative works or modified versions, and any portions
32 * thereof, and that both notices appear in supporting documentation.
34 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
35 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
36 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
38 * Carnegie Mellon requests users of this software to return to
40 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
41 * School of Computer Science
42 * Carnegie Mellon University
43 * Pittsburgh PA 15213-3890
45 * any improvements or extensions that they make and grant Carnegie Mellon
46 * the rights to redistribute these changes.
50 * Copyright (c) 1980, 1986, 1991 Regents of the University of California.
51 * All rights reserved.
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions
55 * are met:
56 * 1. Redistributions of source code must retain the above copyright
57 * notice, this list of conditions and the following disclaimer.
58 * 2. Redistributions in binary form must reproduce the above copyright
59 * notice, this list of conditions and the following disclaimer in the
60 * documentation and/or other materials provided with the distribution.
61 * 3. All advertising materials mentioning features or use of this software
62 * must display the following acknowledgement:
63 * This product includes software developed by the University of
64 * California, Berkeley and its contributors.
65 * 4. Neither the name of the University nor the names of its contributors
66 * may be used to endorse or promote products derived from this software
67 * without specific prior written permission.
69 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
70 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
71 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
72 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
73 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
74 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
75 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
76 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
77 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
78 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
79 * SUCH DAMAGE.
81 * @(#)route.c 7.22 (Berkeley) 6/27/91
84 #include <conf.h>
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/malloc.h>
89 #include <sys/mbuf.h>
90 #include <sys/socket.h>
91 #include <sys/socketvar.h>
92 #include <sys/domain.h>
93 #include <sys/protosw.h>
94 #include <sys/ioctl.h>
95 #include <sys/synch.h>
97 #include <net/if.h>
98 #include <net/if_protos.h>
99 #include <net/route.h>
100 #include <net/raw_cb.h>
102 #include <netinet/in.h>
103 #include <netinet/in_var.h>
105 #if NS
106 #include <netns/ns.h>
107 #endif
108 #include <net/netisr.h>
110 #include <net/rtsock_protos.h>
111 #include <net/radix_protos.h>
112 #include <net/route_protos.h>
113 #include <netinet/in_protos.h>
115 #define SA(p) ((struct sockaddr *)(p))
117 extern struct rtstat rtstat;
120 /* --- commons from route.h --- */
121 struct route_cb route_cb = {0};
122 #if 0 /* obsolete */
123 struct mbuf *rthost[RTHASHSIZ] = {NULL};
124 struct mbuf *rtnet[RTHASHSIZ] = {NULL};
125 #endif
126 struct rtstat rtstat = {0};
127 /* --- commons from route.h --- */
129 int rttrash = 0; /* routes not in table but not freed */
130 struct sockaddr wildcard = {0}; /* zero valued cookie for wildcard searches */
131 #if 0 /* obsolete */
132 int rthashsize = RTHASHSIZ; /* for netstat, etc. */
133 #endif
135 static int rtinits_done = 0;
136 struct radix_node_head *ns_rnhead = 0, *in_rnhead = 0;
137 struct radix_node *rn_match(), *rn_delete(), *rn_addroute();
139 void
140 rtinitheads()
142 if (rtinits_done == 0 &&
143 #if NS
144 rn_inithead(&ns_rnhead, 16, AF_NS) &&
145 #endif
146 rn_inithead(&in_rnhead, 32, AF_INET))
147 rtinits_done = 1;
151 * Packet routing routines.
153 void
154 rtalloc(ro)
155 register struct route *ro;
157 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
158 return; /* XXX */
159 ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
162 struct rtentry *
163 rtalloc1(dst, report)
164 register struct sockaddr *dst;
165 int report;
167 register struct radix_node_head *rnh;
168 register struct rtentry *rt;
169 register struct radix_node *rn;
170 struct rtentry *newrt = 0;
171 int err = 0, msgtype = RTM_MISS;
172 spl_t s = splnet();
174 for (rnh = radix_node_head; rnh && (dst->sa_family != rnh->rnh_af); )
175 rnh = rnh->rnh_next;
176 DROUTE(log(LOG_DEBUG,"Found radix node head: 0x%08lx", rnh);)
177 DROUTE(log(LOG_DEBUG,"rnh_treetop = 0x%08lx", rnh->rnh_treetop);)
178 if (rnh && rnh->rnh_treetop &&
179 (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) &&
180 ((rn->rn_flags & RNF_ROOT) == 0)) {
181 newrt = rt = (struct rtentry *)rn;
182 if (report && (rt->rt_flags & RTF_CLONING)) {
183 if ((err = rtrequest(RTM_RESOLVE, dst, SA(0),
184 SA(0), 0, &newrt)) ||
185 ((rt->rt_flags & RTF_XRESOLVE)
186 && (msgtype = RTM_RESOLVE))) /* intended! */
187 goto miss;
188 } else
189 rt->rt_refcnt++;
190 } else {
191 DROUTE(log(LOG_DEBUG,"Route lookup failure, rn = 0x%08lx", rn);)
192 rtstat.rts_unreach++;
193 miss: if (report)
194 rt_missmsg(msgtype, dst, SA(0), SA(0), SA(0), 0, err);
196 splx(s);
197 return (newrt);
200 void
201 rtfree(rt)
202 register struct rtentry *rt;
204 if (rt == 0)
205 panic("rtfree");
206 rt->rt_refcnt--;
207 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
208 rttrash--;
209 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
210 panic ("rtfree 2");
211 Free(rt);
216 * Force a routing table entry to the specified
217 * destination to go through the given gateway.
218 * Normally called as a result of a routing redirect
219 * message from the network layer.
221 * N.B.: must be called at splnet
224 void
225 rtredirect(dst, gateway, netmask, flags, src, rtp)
226 struct sockaddr *dst, *gateway, *netmask, *src;
227 int flags;
228 struct rtentry **rtp;
230 register struct rtentry *rt = NULL;
231 int error = 0;
232 short *stat = 0;
234 /* verify the gateway is directly reachable */
235 if (ifa_ifwithnet(gateway) == 0) {
236 error = ENETUNREACH;
237 goto done;
239 rt = rtalloc1(dst, 0);
241 * If the redirect isn't from our current router for this dst,
242 * it's either old or wrong. If it redirects us to ourselves,
243 * we have a routing loop, perhaps as a result of an interface
244 * going down recently.
246 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
247 if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway))
248 error = EINVAL;
249 else if (ifa_ifwithaddr(gateway))
250 error = EHOSTUNREACH;
251 if (error)
252 goto done;
254 * Create a new entry if we just got back a wildcard entry
255 * or the the lookup failed. This is necessary for hosts
256 * which use routing redirects generated by smart gateways
257 * to dynamically build the routing tables.
259 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
260 goto create;
262 * Don't listen to the redirect if it's
263 * for a route to an interface.
265 if (rt->rt_flags & RTF_GATEWAY) {
266 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
268 * Changing from route to net => route to host.
269 * Create new route, rather than smashing route to net.
271 create:
272 flags |= RTF_GATEWAY | RTF_DYNAMIC;
273 error = rtrequest((int)RTM_ADD, dst, gateway,
274 SA(0), flags,
275 (struct rtentry **)0);
276 stat = &rtstat.rts_dynamic;
277 } else {
279 * Smash the current notion of the gateway to
280 * this destination. Should check about netmask!!!
282 if (gateway->sa_len <= rt->rt_gateway->sa_len) {
283 Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
284 rt->rt_flags |= RTF_MODIFIED;
285 flags |= RTF_MODIFIED;
286 stat = &rtstat.rts_newgateway;
287 } else
288 error = ENOSPC;
290 } else
291 error = EHOSTUNREACH;
292 done:
293 if (rt) {
294 if (rtp && !error)
295 *rtp = rt;
296 else
297 rtfree(rt);
299 if (error)
300 rtstat.rts_badredirect++;
301 else {
302 if (stat)
303 (*stat)++;
305 rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error);
309 * Routing table ioctl interface.
312 rtioctl(req, data)
313 int req;
314 caddr_t data;
316 #if !defined(COMPAT_43) && !defined(AMITCP)
317 return (EOPNOTSUPP);
318 #else
319 register struct ortentry *entry = (struct ortentry *)data;
320 int error;
321 struct sockaddr netmask;
323 if (req == SIOCADDRT)
324 req = RTM_ADD;
325 else if (req == SIOCDELRT)
326 req = RTM_DELETE;
327 else
328 return (EINVAL);
330 #ifndef AMITCP /* no protection on AmigaOS */
331 if (error = suser(p->p_ucred, &p->p_acflag))
332 return (error);
333 #endif /* AMITCP */
335 #if BYTE_ORDER != BIG_ENDIAN
336 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
337 entry->rt_dst.sa_family = entry->rt_dst.sa_len;
338 entry->rt_dst.sa_len = 16;
340 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) {
341 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len;
342 entry->rt_gateway.sa_len = 16;
344 #else
345 if (entry->rt_dst.sa_len == 0)
346 entry->rt_dst.sa_len = 16;
347 if (entry->rt_gateway.sa_len == 0)
348 entry->rt_gateway.sa_len = 16;
349 #endif
350 if ((entry->rt_flags & RTF_HOST) == 0)
351 switch (entry->rt_dst.sa_family) {
352 #if INET
353 case AF_INET:
355 #if 0
357 * Should not use icmpmask, since it is accessed from
358 * different tasks!
360 extern struct sockaddr_in icmpmask;
361 struct sockaddr_in *dst_in =
362 (struct sockaddr_in *)&entry->rt_dst;
364 in_sockmaskof(dst_in->sin_addr, &icmpmask);
365 netmask = (struct sockaddr *)&icmpmask;
366 #else
367 struct sockaddr_in *dst_saddr = (struct sockaddr_in *)&entry->rt_dst;
368 in_sockmaskof(dst_saddr->sin_addr, (struct sockaddr_in *)&netmask);
369 #endif
371 break;
372 #endif
373 #if NS
374 case AF_NS:
376 extern struct sockaddr_ns ns_netmask;
377 netmask = (struct sockaddr)ns_netmask;
379 #endif
381 error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway),
382 (entry->rt_flags & RTF_HOST) ? NULL : &netmask,
383 entry->rt_flags, (struct rtentry **)0);
384 rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL),
385 &(entry->rt_dst), &(entry->rt_gateway),
386 (entry->rt_flags & RTF_HOST) ? NULL : &netmask,
387 SA(0), entry->rt_flags, error);
388 return (error);
389 #endif
392 struct ifaddr *
393 ifa_ifwithroute(flags, dst, gateway)
394 int flags;
395 struct sockaddr *dst, *gateway;
397 register struct ifaddr *ifa;
398 if ((flags & RTF_GATEWAY) == 0) {
400 * If we are adding a route to an interface,
401 * and the interface is a pt to pt link
402 * we should search for the destination
403 * as our clue to the interface. Otherwise
404 * we can use the local address.
406 ifa = 0;
407 if (flags & RTF_HOST)
408 ifa = ifa_ifwithdstaddr(dst);
409 if (ifa == 0)
410 ifa = ifa_ifwithaddr(gateway);
411 } else {
413 * If we are adding a route to a remote net
414 * or host, the gateway may still be on the
415 * other end of a pt to pt link.
417 ifa = ifa_ifwithdstaddr(gateway);
419 if (ifa == 0)
420 ifa = ifa_ifwithnet(gateway);
421 if (ifa == 0) {
422 struct rtentry *rt = rtalloc1(dst, 0);
423 if (rt == 0)
424 return (0);
425 rt->rt_refcnt--;
426 if ((ifa = rt->rt_ifa) == 0)
427 return (0);
429 if (ifa->ifa_addr->sa_family != dst->sa_family) {
430 struct ifaddr *oifa = ifa, *ifaof_ifpforaddr();
431 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
432 if (ifa == 0)
433 ifa = oifa;
435 return (ifa);
438 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
441 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
442 int req, flags;
443 struct sockaddr *dst, *gateway, *netmask;
444 struct rtentry **ret_nrt;
446 int len, error = 0;
447 spl_t s = splnet();
448 register struct rtentry *rt;
449 register struct radix_node *rn;
450 register struct radix_node_head *rnh;
451 struct ifaddr *ifa, *ifa_ifwithdstaddr();
452 struct sockaddr *ndst;
453 u_char af = dst->sa_family;
454 #define senderr(x) { error = x ; goto bad; }
456 if (rtinits_done == 0)
457 rtinitheads();
458 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
459 rnh = rnh->rnh_next;
460 if (rnh == 0)
461 senderr(ESRCH);
462 if (flags & RTF_HOST)
463 netmask = 0;
464 switch (req) {
465 case RTM_DELETE:
466 if (ret_nrt && (rt = *ret_nrt)) {
467 RTFREE(rt);
468 *ret_nrt = 0;
470 if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask,
471 rnh->rnh_treetop)) == 0)
472 senderr(ESRCH);
473 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
474 panic ("rtrequest delete");
475 rt = (struct rtentry *)rn;
476 rt->rt_flags &= ~RTF_UP;
477 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
478 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
479 rttrash++;
480 if (rt->rt_refcnt <= 0)
481 rtfree(rt);
482 break;
484 case RTM_RESOLVE:
485 if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
486 senderr(EINVAL);
487 ifa = rt->rt_ifa;
488 flags = rt->rt_flags & ~RTF_CLONING;
489 gateway = rt->rt_gateway;
490 if ((netmask = rt->rt_genmask) == 0)
491 flags |= RTF_HOST;
492 goto makeroute;
494 case RTM_ADD:
495 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
496 senderr(ENETUNREACH);
497 makeroute:
498 len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
499 + ROUNDUP(dst->sa_len);
500 R_Malloc(rt, struct rtentry *, len);
501 if (rt == 0)
502 senderr(ENOBUFS);
503 Bzero(rt, len);
504 ndst = (struct sockaddr *)(rt + 1);
505 if (netmask) {
506 rt_maskedcopy(dst, ndst, netmask);
507 } else
508 Bcopy(dst, ndst, dst->sa_len);
509 rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask,
510 rnh->rnh_treetop, rt->rt_nodes);
511 if (rn == 0) {
512 Free(rt);
513 senderr(EEXIST);
515 rt->rt_ifa = ifa;
516 rt->rt_ifp = ifa->ifa_ifp;
517 rt->rt_flags = RTF_UP | flags;
518 rt->rt_gateway = (struct sockaddr *)
519 (rn->rn_key + ROUNDUP(dst->sa_len));
520 Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
521 if (req == RTM_RESOLVE)
522 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
523 if (ifa->ifa_rtrequest)
524 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
525 if (ret_nrt) {
526 *ret_nrt = rt;
527 rt->rt_refcnt++;
529 break;
531 bad:
532 splx(s);
533 return (error);
536 void
537 rt_maskedcopy(src, dst, netmask)
538 struct sockaddr *src, *dst, *netmask;
540 register u_char *cp1 = (u_char *)src;
541 register u_char *cp2 = (u_char *)dst;
542 register u_char *cp3 = (u_char *)netmask;
543 u_char *cplim = cp2 + *cp3;
544 u_char *cplim2 = cp2 + *cp1;
546 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
547 cp3 += 2;
548 if (cplim > cplim2)
549 cplim = cplim2;
550 while (cp2 < cplim)
551 *cp2++ = *cp1++ & *cp3++;
552 if (cp2 < cplim2)
553 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
556 * Set up a routing table entry, normally
557 * for an interface.
560 rtinit(ifa, cmd, flags)
561 register struct ifaddr *ifa;
562 int cmd, flags;
564 register struct rtentry *rt;
565 register struct sockaddr *dst;
566 register struct sockaddr *deldst;
567 struct mbuf *m = 0;
568 int error;
570 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
571 if (ifa->ifa_flags & IFA_ROUTE) {
572 if ((rt = ifa->ifa_rt) && (rt->rt_flags & RTF_UP) == 0) {
573 RTFREE(rt);
574 ifa->ifa_rt = 0;
577 if (cmd == RTM_DELETE) {
578 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
579 m = m_get(M_WAIT, MT_SONAME);
580 deldst = mtod(m, struct sockaddr *);
581 rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
582 dst = deldst;
584 if (rt = rtalloc1(dst, 0)) {
585 rt->rt_refcnt--;
586 if (rt->rt_ifa != ifa) {
587 if (m)
588 (void) m_free(m);
589 return (flags & RTF_HOST ? EHOSTUNREACH
590 : ENETUNREACH);
594 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
595 flags | ifa->ifa_flags, &ifa->ifa_rt);
596 if (m)
597 (void) m_free(m);
598 if (cmd == RTM_ADD && error == 0 && (rt = ifa->ifa_rt)
599 && rt->rt_ifa != ifa) {
600 rt->rt_ifa = ifa;
601 rt->rt_ifp = ifa->ifa_ifp;
603 return (error);