2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
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,
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
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
81 * @(#)route.c 7.22 (Berkeley) 6/27/91
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/malloc.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>
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>
106 #include <netns/ns.h>
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};
123 struct mbuf
*rthost
[RTHASHSIZ
] = {NULL
};
124 struct mbuf
*rtnet
[RTHASHSIZ
] = {NULL
};
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 */
132 int rthashsize
= RTHASHSIZ
; /* for netstat, etc. */
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();
142 if (rtinits_done
== 0 &&
144 rn_inithead(&ns_rnhead
, 16, AF_NS
) &&
146 rn_inithead(&in_rnhead
, 32, AF_INET
))
151 * Packet routing routines.
155 register struct route
*ro
;
157 if (ro
->ro_rt
&& ro
->ro_rt
->rt_ifp
&& (ro
->ro_rt
->rt_flags
& RTF_UP
))
159 ro
->ro_rt
= rtalloc1(&ro
->ro_dst
, 1);
163 rtalloc1(dst
, report
)
164 register struct sockaddr
*dst
;
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
;
174 for (rnh
= radix_node_head
; rnh
&& (dst
->sa_family
!= rnh
->rnh_af
); )
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! */
191 DROUTE(log(LOG_DEBUG
,"Route lookup failure, rn = 0x%08lx", rn
);)
192 rtstat
.rts_unreach
++;
194 rt_missmsg(msgtype
, dst
, SA(0), SA(0), SA(0), 0, err
);
202 register struct rtentry
*rt
;
207 if (rt
->rt_refcnt
<= 0 && (rt
->rt_flags
& RTF_UP
) == 0) {
209 if (rt
->rt_nodes
->rn_flags
& (RNF_ACTIVE
| RNF_ROOT
))
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
225 rtredirect(dst
, gateway
, netmask
, flags
, src
, rtp
)
226 struct sockaddr
*dst
, *gateway
, *netmask
, *src
;
228 struct rtentry
**rtp
;
230 register struct rtentry
*rt
= NULL
;
234 /* verify the gateway is directly reachable */
235 if (ifa_ifwithnet(gateway
) == 0) {
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
))
249 else if (ifa_ifwithaddr(gateway
))
250 error
= EHOSTUNREACH
;
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))
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.
272 flags
|= RTF_GATEWAY
| RTF_DYNAMIC
;
273 error
= rtrequest((int)RTM_ADD
, dst
, gateway
,
275 (struct rtentry
**)0);
276 stat
= &rtstat
.rts_dynamic
;
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
;
291 error
= EHOSTUNREACH
;
300 rtstat
.rts_badredirect
++;
305 rt_missmsg(RTM_REDIRECT
, dst
, gateway
, netmask
, src
, flags
, error
);
309 * Routing table ioctl interface.
316 #if !defined(COMPAT_43) && !defined(AMITCP)
319 register struct ortentry
*entry
= (struct ortentry
*)data
;
321 struct sockaddr netmask
;
323 if (req
== SIOCADDRT
)
325 else if (req
== SIOCDELRT
)
330 #ifndef AMITCP /* no protection on AmigaOS */
331 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
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;
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;
350 if ((entry
->rt_flags
& RTF_HOST
) == 0)
351 switch (entry
->rt_dst
.sa_family
) {
357 * Should not use icmpmask, since it is accessed from
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
;
367 struct sockaddr_in
*dst_saddr
= (struct sockaddr_in
*)&entry
->rt_dst
;
368 in_sockmaskof(dst_saddr
->sin_addr
, (struct sockaddr_in
*)&netmask
);
376 extern struct sockaddr_ns ns_netmask
;
377 netmask
= (struct sockaddr
)ns_netmask
;
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
);
393 ifa_ifwithroute(flags
, dst
, gateway
)
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.
407 if (flags
& RTF_HOST
)
408 ifa
= ifa_ifwithdstaddr(dst
);
410 ifa
= ifa_ifwithaddr(gateway
);
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
);
420 ifa
= ifa_ifwithnet(gateway
);
422 struct rtentry
*rt
= rtalloc1(dst
, 0);
426 if ((ifa
= rt
->rt_ifa
) == 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
);
438 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
441 rtrequest(req
, dst
, gateway
, netmask
, flags
, ret_nrt
)
443 struct sockaddr
*dst
, *gateway
, *netmask
;
444 struct rtentry
**ret_nrt
;
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)
458 for (rnh
= radix_node_head
; rnh
&& (af
!= rnh
->rnh_af
); )
462 if (flags
& RTF_HOST
)
466 if (ret_nrt
&& (rt
= *ret_nrt
)) {
470 if ((rn
= rn_delete((caddr_t
)dst
, (caddr_t
)netmask
,
471 rnh
->rnh_treetop
)) == 0)
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));
480 if (rt
->rt_refcnt
<= 0)
485 if (ret_nrt
== 0 || (rt
= *ret_nrt
) == 0)
488 flags
= rt
->rt_flags
& ~RTF_CLONING
;
489 gateway
= rt
->rt_gateway
;
490 if ((netmask
= rt
->rt_genmask
) == 0)
495 if ((ifa
= ifa_ifwithroute(flags
, dst
, gateway
)) == 0)
496 senderr(ENETUNREACH
);
498 len
= sizeof (*rt
) + ROUNDUP(gateway
->sa_len
)
499 + ROUNDUP(dst
->sa_len
);
500 R_Malloc(rt
, struct rtentry
*, len
);
504 ndst
= (struct sockaddr
*)(rt
+ 1);
506 rt_maskedcopy(dst
, ndst
, netmask
);
508 Bcopy(dst
, ndst
, dst
->sa_len
);
509 rn
= rn_addroute((caddr_t
)ndst
, (caddr_t
)netmask
,
510 rnh
->rnh_treetop
, rt
->rt_nodes
);
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));
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 */
551 *cp2
++ = *cp1
++ & *cp3
++;
553 bzero((caddr_t
)cp2
, (unsigned)(cplim2
- cp2
));
556 * Set up a routing table entry, normally
560 rtinit(ifa
, cmd
, flags
)
561 register struct ifaddr
*ifa
;
564 register struct rtentry
*rt
;
565 register struct sockaddr
*dst
;
566 register struct sockaddr
*deldst
;
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) {
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
);
584 if (rt
= rtalloc1(dst
, 0)) {
586 if (rt
->rt_ifa
!= ifa
) {
589 return (flags
& RTF_HOST
? EHOSTUNREACH
594 error
= rtrequest(cmd
, dst
, ifa
->ifa_addr
, ifa
->ifa_netmask
,
595 flags
| ifa
->ifa_flags
, &ifa
->ifa_rt
);
598 if (cmd
== RTM_ADD
&& error
== 0 && (rt
= ifa
->ifa_rt
)
599 && rt
->rt_ifa
!= ifa
) {
601 rt
->rt_ifp
= ifa
->ifa_ifp
;