date and time created 88/12/14 15:29:27 by sklower
[unix-history] / usr / src / sys / net / route.c
CommitLineData
cb1c44c2 1/*
1810611d 2 * Copyright (c) 1980, 1986 Regents of the University of California.
5b519e94 3 * All rights reserved.
cb1c44c2 4 *
5b519e94 5 * Redistribution and use in source and binary forms are permitted
50c7758a
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5b519e94 16 *
ea372425 17 * @(#)route.c 7.8 (Berkeley) %G%
cb1c44c2 18 */
ea372425
MK
19#include "../machine/reg.h"
20
a0369dcf
JB
21#include "param.h"
22#include "systm.h"
a0369dcf
JB
23#include "dir.h"
24#include "user.h"
ea372425
MK
25#include "inode.h"
26#include "proc.h"
27#include "mbuf.h"
28#include "socket.h"
29#include "socketvar.h"
30#include "domain.h"
31#include "protosw.h"
a0369dcf 32#include "errno.h"
ea372425 33#include "ioctl.h"
f4d55810 34
a0369dcf
JB
35#include "if.h"
36#include "af.h"
37#include "route.h"
ea372425 38#include "raw_cb.h"
8bbafbd9
MK
39#include "../netinet/in.h"
40#include "../netinet/in_var.h"
ea372425
MK
41
42#include "../machine/mtpr.h"
43#include "netisr.h"
44
45#include "rtsock.c"
9d03c806 46
a13c006d 47int rttrash; /* routes not in table but not freed */
a9ea8834 48struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
c50b0999 49int rthashsize = RTHASHSIZ; /* for netstat, etc. */
a9ea8834 50
8bbafbd9
MK
51static int rtinits_done = 0;
52struct radix_node_head *ns_rnhead, *in_rnhead;
ea372425 53struct radix_node *rn_match(), *rn_delete(), *rn_addroute();
8bbafbd9
MK
54rtinitheads()
55{
56 if (rtinits_done == 0 &&
57 rn_inithead(&ns_rnhead, 16, AF_NS) &&
58 rn_inithead(&in_rnhead, 32, AF_INET))
59 rtinits_done = 1;
60}
61
9d03c806
SL
62/*
63 * Packet routing routines.
64 */
f6311fb6 65rtalloc(ro)
9d03c806 66 register struct route *ro;
ea372425
MK
67{
68 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
69 return; /* XXX */
70 ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
71}
72
73struct rtentry *
74rtalloc1(dst, report)
75 struct sockaddr *dst;
76 int report;
9d03c806 77{
8bbafbd9
MK
78 register struct radix_node_head *rnh;
79 register struct radix_node *rn;
80 register struct rtentry *rt = 0;
ea372425
MK
81 u_char af = dst->sa_family;
82 int s = splnet();
9d03c806 83
8bbafbd9
MK
84 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
85 rnh = rnh->rnh_next;
86 if (rnh && rnh->rnh_treetop &&
ea372425 87 (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) &&
8bbafbd9 88 ((rn->rn_flags & RNF_ROOT) == 0)) {
ea372425 89 rt = (struct rtentry *)rn;
c50b0999 90 rt->rt_refcnt++;
ea372425 91 } else {
8bbafbd9 92 rtstat.rts_unreach++;
ea372425
MK
93 if (report && route_cb.any_count)
94 rt_missmsg(RTM_MISS, dst, (struct sockaddr *)0,
95 (struct sockaddr *)0, (struct sockaddr *)0, 0);
96 }
c50b0999 97 splx(s);
ea372425 98 return (rt);
9d03c806
SL
99}
100
f6311fb6 101rtfree(rt)
c124e997
SL
102 register struct rtentry *rt;
103{
8bbafbd9 104 u_char *af;
c124e997 105 if (rt == 0)
a1edc12b 106 panic("rtfree");
c124e997 107 rt->rt_refcnt--;
8bbafbd9 108 if (rt->rt_refcnt <= 0 && (rt->rt_flags&RTF_UP) == 0) {
a13c006d 109 rttrash--;
ea372425 110 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
8bbafbd9 111 panic ("rtfree 2");
ea372425 112 free((caddr_t)rt, M_RTABLE);
a13c006d 113 }
c124e997
SL
114}
115
464f931f
SL
116/*
117 * Force a routing table entry to the specified
118 * destination to go through the given gateway.
119 * Normally called as a result of a routing redirect
120 * message from the network layer.
121 *
8bbafbd9 122 * N.B.: must be called at splnet
464f931f 123 *
464f931f 124 */
ea372425 125rtredirect(dst, gateway, netmask, flags, src)
92c26501 126 struct sockaddr *dst, *gateway, *src;
7eb1f827 127 int flags;
464f931f 128{
464f931f
SL
129 register struct rtentry *rt;
130
131 /* verify the gateway is directly reachable */
cba69651 132 if (ifa_ifwithnet(gateway) == 0) {
a9ea8834 133 rtstat.rts_badredirect++;
464f931f 134 return;
a9ea8834 135 }
ea372425 136 rt = rtalloc1(dst, 1);
92c26501 137#define equal(a1, a2) \
a7b1cd9a 138 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
92c26501
MK
139 /*
140 * If the redirect isn't from our current router for this dst,
2e9c4868
MK
141 * it's either old or wrong. If it redirects us to ourselves,
142 * we have a routing loop, perhaps as a result of an interface
143 * going down recently.
92c26501 144 */
2e9c4868 145 if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) {
92c26501 146 rtstat.rts_badredirect++;
703b8607
MK
147 if (rt)
148 rtfree(rt);
92c26501
MK
149 return;
150 }
a9ea8834 151 /*
8bbafbd9 152 * Old comment:
48afbdc5
SL
153 * Create a new entry if we just got back a wildcard entry
154 * or the the lookup failed. This is necessary for hosts
155 * which use routing redirects generated by smart gateways
156 * to dynamically build the routing tables.
8bbafbd9
MK
157 *
158 * New comment:
159 * If we survived the previous tests, it doesn't matter
160 * what sort of entry we got when we looked it up;
161 * we should just go ahead and free the reference to
162 * the route we created. rtalloc will not give a
163 * pointer to the root node. And if we got a pointer
164 * to a default gateway, we should free the reference
165 * in any case.
166 if (rt) {
48afbdc5
SL
167 rtfree(rt);
168 rt = 0;
169 }
ea372425
MK
170 if (route_cb.any_count)
171 rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src,
172 (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
8bbafbd9 173 */
a9ea8834 174 if (rt == 0) {
ea372425
MK
175 rtrequest((int)RTM_ADD, dst, gateway, 0,
176 (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC, 0);
a9ea8834
SL
177 rtstat.rts_dynamic++;
178 return;
179 }
464f931f
SL
180 /*
181 * Don't listen to the redirect if it's
182 * for a route to an interface.
464f931f 183 */
a9ea8834 184 if (rt->rt_flags & RTF_GATEWAY) {
7eb1f827
MK
185 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
186 /*
66798f86 187 * Changing from route to net => route to host.
7eb1f827
MK
188 * Create new route, rather than smashing route to net.
189 */
ea372425
MK
190 rtrequest((int)RTM_ADD, dst, gateway, 0,
191 (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC, 0);
3b66e456 192 rtstat.rts_dynamic++;
7eb1f827
MK
193 } else {
194 /*
195 * Smash the current notion of the gateway to
3b66e456 196 * this destination.
7eb1f827 197 */
ea372425
MK
198 if (gateway->sa_len <= rt->rt_gateway->sa_len) {
199 Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
200 rt->rt_flags |= RTF_MODIFIED;
201 rtstat.rts_newgateway++;
202 } else
203 rtstat.rts_badredirect++;
7eb1f827 204 }
92c26501
MK
205 } else
206 rtstat.rts_badredirect++;
ff320836 207 rtfree(rt);
464f931f
SL
208}
209
a62dd253
SL
210/*
211 * Routing table ioctl interface.
212 */
ea372425
MK
213rtioctl(req, data)
214 int req;
a62dd253
SL
215 caddr_t data;
216{
ea372425
MK
217#ifndef COMPAT_43
218 return (EOPNOTSUPP);
219#else
220 register struct ortentry *entry = (struct ortentry *)data;
221 int error;
222 struct sockaddr *netmask = 0;
a62dd253 223
ea372425
MK
224 if (req == SIOCADDRT)
225 req = RTM_ADD;
226 else if (req == SIOCDELRT)
227 req = RTM_DELETE;
228 else
a62dd253 229 return (EINVAL);
ea372425 230
a62dd253
SL
231 if (!suser())
232 return (u.u_error);
a7b1cd9a
MK
233#if BYTE_ORDER != BIG_ENDIAN
234 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
235 entry->rt_dst.sa_family = entry->rt_dst.sa_len;
236 entry->rt_dst.sa_len = 16;
237 }
238 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) {
239 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len;
240 entry->rt_gateway.sa_len = 16;
241 }
242#else
243 if (entry->rt_dst.sa_len == 0)
244 entry->rt_dst.sa_len = 16;
245 if (entry->rt_gateway.sa_len == 0)
246 entry->rt_gateway.sa_len = 16;
247#endif
ea372425
MK
248 if ((entry->rt_flags & RTF_HOST) == 0)
249 switch (entry->rt_dst.sa_family) {
250#ifdef INET
251 case AF_INET:
252 {
253 extern struct sockaddr_in icmpmask;
254 u_long in_maskof();
255 struct sockaddr_in *dst_in =
256 (struct sockaddr_in *)&entry->rt_dst;
257 u_long i = ntohl(dst_in->sin_addr.s_addr);
258
259 icmpmask.sin_addr.s_addr = ntohl(in_maskof(i));
260 netmask = (struct sockaddr *)&icmpmask;
261 }
262 break;
263#endif
264#ifdef NS
265 case AF_NS:
266 {
267 extern struct sockaddr_ns ns_netmask;
268 netmask = (struct sockaddr *)&ns_netmask;
269 }
270#endif
271 }
272 error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask,
273 entry->rt_flags, 0);
274 rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL),
275 &(entry->rt_dst), &(entry->rt_gateway),
276 netmask, (struct sockaddr *)error, entry->rt_flags);
277 return (error);
a7b1cd9a 278#endif
ea372425
MK
279}
280
281rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
282 int req, flags;
283 struct sockaddr *dst, *gateway, *netmask;
284 struct rtentry **ret_nrt;
285{
286 int s = splnet(), len, error = 0;
287 register struct rtentry *rt;
288 register struct radix_node *rn;
289 register struct radix_node_head *rnh;
290 struct ifaddr *ifa, *ifa_ifwithdstaddr();
291 u_char af = dst->sa_family;
292
8bbafbd9
MK
293 if (rtinits_done == 0)
294 rtinitheads();
8bbafbd9
MK
295 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
296 rnh = rnh->rnh_next;
297 if (rnh == 0) {
298 error = ESRCH;
299 goto bad;
300 }
9d03c806 301 switch (req) {
ea372425
MK
302 case RTM_DELETE:
303 if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask,
304 rnh->rnh_treetop)) == 0) {
d7887ae9
BJ
305 error = ESRCH;
306 goto bad;
307 }
8bbafbd9
MK
308 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
309 panic ("rtrequest delete");
ea372425
MK
310 rt = (struct rtentry *)rn;
311 rt->rt_flags &= ~RTF_UP;
312 if (rt->rt_refcnt > 0)
a13c006d 313 rttrash++;
8bbafbd9 314 else
ea372425 315 free((caddr_t)rt, M_RTABLE);
9d03c806
SL
316 break;
317
ea372425
MK
318 case RTM_ADD:
319 if ((flags & RTF_GATEWAY) == 0) {
320 /*
321 * If we are adding a route to an interface,
322 * and the interface is a pt to pt link
323 * we should search for the destination
324 * as our clue to the interface. Otherwise
325 * we can use the local address.
326 */
327 ifa = 0;
328 if (flags & RTF_HOST)
329 ifa = ifa_ifwithdstaddr(dst);
330 if (ifa == 0)
331 ifa = ifa_ifwithaddr(gateway);
332 } else {
333 /*
334 * If we are adding a route to a remote net
335 * or host, the gateway may still be on the
336 * other end of a pt to pt link.
337 */
338 ifa = ifa_ifwithdstaddr(gateway);
339 }
340 if (ifa == 0) {
341 ifa = ifa_ifwithnet(gateway);
342 if (ifa == 0 && req == RTM_ADD) {
343 error = ENETUNREACH;
344 goto bad;
345 }
346 }
347 len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
348 + ROUNDUP(dst->sa_len);
349 R_Malloc(rt, struct rtentry *, len);
350 if (rt == 0) {
8bbafbd9 351 error = ENOBUFS;
d7887ae9
BJ
352 goto bad;
353 }
ea372425
MK
354 Bzero(rt, len);
355 rn = rn_addroute((caddr_t)dst, (caddr_t)netmask,
356 rnh->rnh_treetop, rt->rt_nodes);
8bbafbd9 357 if (rn == 0) {
ea372425 358 free((caddr_t)rt, M_RTABLE);
8bbafbd9 359 error = EEXIST;
d7887ae9 360 goto bad;
c124e997 361 }
ea372425
MK
362 if (ret_nrt)
363 *ret_nrt = rt; /* == (struct rtentry *)rn */
364 rt->rt_ifp = ifa->ifa_ifp;
a13c006d 365 rt->rt_use = 0;
8bbafbd9 366 rt->rt_refcnt = 0;
ea372425
MK
367 rt->rt_flags = RTF_UP |
368 (flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC));
369 rn->rn_key = (caddr_t) (rt + 1); /* == rt_dst */
370 Bcopy(dst, rn->rn_key, dst->sa_len);
371 rt->rt_gateway = (struct sockaddr *)
372 (rn->rn_key + ROUNDUP(dst->sa_len));
373 Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
9d03c806
SL
374 break;
375 }
c124e997
SL
376bad:
377 splx(s);
378 return (error);
9d03c806 379}
f6311fb6
SL
380/*
381 * Set up a routing table entry, normally
382 * for an interface.
383 */
ea372425
MK
384rtinit(ifa, cmd, flags)
385 register struct ifaddr *ifa;
2a63f7ba 386 int cmd, flags;
f6311fb6 387{
ea372425
MK
388 struct sockaddr net, *netp;
389 register caddr_t cp, cp2, cp3;
390 caddr_t cplim, freeit = 0;
391 int len;
f6311fb6 392
ea372425
MK
393 if (flags & RTF_HOST || ifa->ifa_netmask == 0) {
394 (void) rtrequest(cmd, ifa->ifa_dstaddr, ifa->ifa_addr,
395 0, flags, 0);
396 } else {
397 if ((len = ifa->ifa_addr->sa_len) >= sizeof (net)) {
398 R_Malloc(freeit, caddr_t, len);
399 if (freeit == 0)
400 return;
401 netp = (struct sockaddr *)freeit;
402 }
403 netp->sa_len = len;
404 cp2 = 1 + (caddr_t)ifa->ifa_addr;
405 netp->sa_family = *cp2++;
406 cp3 = (caddr_t) ifa->ifa_netmask->sa_data;
407 cp = (caddr_t) netp->sa_data;
408 cplim = cp + len - 2;
409 while (cp < cplim)
410 *cp++ = *cp2++ & *cp3++;
411 (void) rtrequest(cmd, netp, ifa->ifa_addr, ifa->ifa_netmask,
412 flags, 0);
413 if (freeit)
414 Free(freeit);
415 }
f6311fb6 416}
ea372425 417#include "radix.c"