checkpoint semi-working version with routing socket
[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 *
8bbafbd9 17 * @(#)route.c 7.7 (Berkeley) %G%
cb1c44c2 18 */
9d03c806 19
a0369dcf
JB
20#include "param.h"
21#include "systm.h"
22#include "mbuf.h"
23#include "protosw.h"
24#include "socket.h"
25#include "dir.h"
26#include "user.h"
27#include "ioctl.h"
28#include "errno.h"
f4d55810 29
a0369dcf
JB
30#include "if.h"
31#include "af.h"
32#include "route.h"
8bbafbd9
MK
33#include "radix.h"
34
35#include "radix.c"
36#ifdef INET
37#include "../netinet/in.h"
38#include "../netinet/in_var.h"
39#endif
9d03c806 40
a13c006d 41int rttrash; /* routes not in table but not freed */
a9ea8834 42struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
c50b0999 43int rthashsize = RTHASHSIZ; /* for netstat, etc. */
a9ea8834 44
8bbafbd9
MK
45static int rtinits_done = 0;
46struct radix_node_head *ns_rnhead, *in_rnhead;
47rtinitheads()
48{
49 if (rtinits_done == 0 &&
50 rn_inithead(&ns_rnhead, 16, AF_NS) &&
51 rn_inithead(&in_rnhead, 32, AF_INET))
52 rtinits_done = 1;
53}
54
9d03c806
SL
55/*
56 * Packet routing routines.
57 */
f6311fb6 58rtalloc(ro)
9d03c806
SL
59 register struct route *ro;
60{
8bbafbd9
MK
61 register struct radix_node_head *rnh;
62 register struct radix_node *rn;
63 register struct rtentry *rt = 0;
64 u_char af = ro->ro_dst.sa_family;
65 int s;
9d03c806 66
7eb1f827
MK
67 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
68 return; /* XXX */
c50b0999 69 s = splnet();
8bbafbd9
MK
70 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
71 rnh = rnh->rnh_next;
72 if (rnh && rnh->rnh_treetop &&
73 (rn = rn_match((char *)&(ro->ro_dst), rnh->rnh_treetop)) &&
74 ((rn->rn_flags & RNF_ROOT) == 0)) {
75 rt = &(((struct nrtentry *)rn)->nrt_rt);
c50b0999 76 rt->rt_refcnt++;
8bbafbd9
MK
77 } else
78 rtstat.rts_unreach++;
79 ro->ro_rt = rt;
c50b0999 80 splx(s);
9d03c806
SL
81}
82
f6311fb6 83rtfree(rt)
c124e997
SL
84 register struct rtentry *rt;
85{
8bbafbd9
MK
86 register struct nrtentry *nrt;
87 u_char *af;
c124e997 88 if (rt == 0)
a1edc12b 89 panic("rtfree");
c124e997 90 rt->rt_refcnt--;
8bbafbd9 91 if (rt->rt_refcnt <= 0 && (rt->rt_flags&RTF_UP) == 0) {
a13c006d 92 rttrash--;
8bbafbd9
MK
93 nrt = (struct nrtentry *) (((struct radix_node *)rt) - 2);
94 if (nrt->nrt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
95 panic ("rtfree 2");
96 free((caddr_t)nrt, M_RTABLE);
a13c006d 97 }
c124e997
SL
98}
99
464f931f
SL
100/*
101 * Force a routing table entry to the specified
102 * destination to go through the given gateway.
103 * Normally called as a result of a routing redirect
104 * message from the network layer.
105 *
8bbafbd9 106 * N.B.: must be called at splnet
464f931f 107 *
464f931f 108 */
92c26501
MK
109rtredirect(dst, gateway, flags, src)
110 struct sockaddr *dst, *gateway, *src;
7eb1f827 111 int flags;
464f931f
SL
112{
113 struct route ro;
114 register struct rtentry *rt;
115
116 /* verify the gateway is directly reachable */
cba69651 117 if (ifa_ifwithnet(gateway) == 0) {
a9ea8834 118 rtstat.rts_badredirect++;
464f931f 119 return;
a9ea8834 120 }
464f931f 121 ro.ro_dst = *dst;
a9ea8834 122 ro.ro_rt = 0;
464f931f
SL
123 rtalloc(&ro);
124 rt = ro.ro_rt;
92c26501 125#define equal(a1, a2) \
a7b1cd9a 126 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
92c26501
MK
127 /*
128 * If the redirect isn't from our current router for this dst,
2e9c4868
MK
129 * it's either old or wrong. If it redirects us to ourselves,
130 * we have a routing loop, perhaps as a result of an interface
131 * going down recently.
92c26501 132 */
2e9c4868 133 if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) {
92c26501 134 rtstat.rts_badredirect++;
703b8607
MK
135 if (rt)
136 rtfree(rt);
92c26501
MK
137 return;
138 }
a9ea8834 139 /*
8bbafbd9 140 * Old comment:
48afbdc5
SL
141 * Create a new entry if we just got back a wildcard entry
142 * or the the lookup failed. This is necessary for hosts
143 * which use routing redirects generated by smart gateways
144 * to dynamically build the routing tables.
8bbafbd9
MK
145 *
146 * New comment:
147 * If we survived the previous tests, it doesn't matter
148 * what sort of entry we got when we looked it up;
149 * we should just go ahead and free the reference to
150 * the route we created. rtalloc will not give a
151 * pointer to the root node. And if we got a pointer
152 * to a default gateway, we should free the reference
153 * in any case.
154 if (rt) {
48afbdc5
SL
155 rtfree(rt);
156 rt = 0;
157 }
8bbafbd9 158 */
a9ea8834 159 if (rt == 0) {
157d4f92 160 rtinit(dst, gateway, (int)SIOCADDRT,
92c26501 161 (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
a9ea8834
SL
162 rtstat.rts_dynamic++;
163 return;
164 }
464f931f
SL
165 /*
166 * Don't listen to the redirect if it's
167 * for a route to an interface.
464f931f 168 */
a9ea8834 169 if (rt->rt_flags & RTF_GATEWAY) {
7eb1f827
MK
170 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
171 /*
66798f86 172 * Changing from route to net => route to host.
7eb1f827
MK
173 * Create new route, rather than smashing route to net.
174 */
157d4f92
MK
175 rtinit(dst, gateway, (int)SIOCADDRT,
176 flags | RTF_DYNAMIC);
3b66e456 177 rtstat.rts_dynamic++;
7eb1f827
MK
178 } else {
179 /*
180 * Smash the current notion of the gateway to
3b66e456 181 * this destination.
7eb1f827 182 */
8bbafbd9 183 rt->rt_gateway = *gateway; /*XXX -- size? */
31150b52
MK
184 rt->rt_flags |= RTF_MODIFIED;
185 rtstat.rts_newgateway++;
7eb1f827 186 }
92c26501
MK
187 } else
188 rtstat.rts_badredirect++;
ff320836 189 rtfree(rt);
464f931f
SL
190}
191
a62dd253
SL
192/*
193 * Routing table ioctl interface.
194 */
195rtioctl(cmd, data)
196 int cmd;
197 caddr_t data;
198{
199
200 if (cmd != SIOCADDRT && cmd != SIOCDELRT)
201 return (EINVAL);
202 if (!suser())
203 return (u.u_error);
204 return (rtrequest(cmd, (struct rtentry *)data));
205}
8bbafbd9
MK
206/*
207 * This routine will go away soon.
208 * Tries to guess which netmask is appropriate for a given net.
209 */
210static struct sockaddr_in rtgmask = { 8, 0 };
211
212char *
213rtgetmask(sa, ifa)
214register struct sockaddr *sa;
215register struct ifaddr *ifa;
216{
217 u_long i, net, mask, subnet;
218
219 switch (sa->sa_family) {
220#ifdef INET
221 register struct in_ifaddr *ia;
222
223 case AF_INET:
224
225 i = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
226 if (i == 0) {
227 rtgmask.sin_addr.s_addr = 0;
228 return ((char *)&rtgmask);
229 } else if (IN_CLASSA(i)) {
230 net = i & IN_CLASSA_NET;
231 mask = IN_CLASSA_NET;
232 } else if (IN_CLASSB(i)) {
233 net = i & IN_CLASSB_NET;
234 mask = IN_CLASSB_NET;
235 } else if (IN_CLASSC(i)) {
236 net = i & IN_CLASSC_NET;
237 mask = IN_CLASSC_NET;
238 } else {
239 net = i;
240 mask = 0xffffffff;
241 }
242
243 /*
244 * Check whether network is a subnet;
245 * if so, return subnet number.
246 */
247 for (ia = in_ifaddr; ia; ia = ia->ia_next)
248 if (net == ia->ia_net) {
249 ifa = &ia->ia_ifa;
250 break;
251 }
252 if (ia == 0) {
253 rtgmask.sin_addr.s_addr = ntohl(mask);
254 return ((char *)&rtgmask);
255 }
256#endif
257 }
258 return ((char *)ifa->ifa_netmask);
259}
a62dd253 260
9d03c806 261/*
c124e997 262 * Carry out a request to change the routing table. Called by
a9ea8834
SL
263 * interfaces at boot time to make their ``local routes'' known,
264 * for ioctl's, and as the result of routing redirects.
9d03c806 265 */
a13c006d 266rtrequest(req, entry)
9d03c806 267 int req;
a13c006d 268 register struct rtentry *entry;
9d03c806 269{
a13c006d 270 register struct rtentry *rt;
8bbafbd9
MK
271 int s, error = 0, found;
272 u_char af;
cba69651 273 struct ifaddr *ifa;
ae674e00 274 struct ifaddr *ifa_ifwithdstaddr();
8bbafbd9
MK
275 register struct nrtentry *nrt;
276 register struct radix_node *rn;
277 register struct radix_node_head *rnh;
278 struct radix_node *head;
279 char *netmask;
9d03c806 280
a7b1cd9a
MK
281#ifdef COMPAT_43
282#if BYTE_ORDER != BIG_ENDIAN
8bbafbd9 283 s = splnet();
a7b1cd9a
MK
284 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
285 entry->rt_dst.sa_family = entry->rt_dst.sa_len;
286 entry->rt_dst.sa_len = 16;
287 }
288 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) {
289 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len;
290 entry->rt_gateway.sa_len = 16;
291 }
292#else
293 if (entry->rt_dst.sa_len == 0)
294 entry->rt_dst.sa_len = 16;
295 if (entry->rt_gateway.sa_len == 0)
296 entry->rt_gateway.sa_len = 16;
297#endif
298#endif
8bbafbd9
MK
299 if (rtinits_done == 0)
300 rtinitheads();
a13c006d 301 af = entry->rt_dst.sa_family;
8bbafbd9
MK
302 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
303 rnh = rnh->rnh_next;
304 if (rnh == 0) {
305 error = ESRCH;
306 goto bad;
307 }
308 head = rnh->rnh_treetop;
309 if ((entry->rt_flags & RTF_GATEWAY) == 0) {
310 /*
311 * If we are adding a route to an interface,
312 * and the interface is a pt to pt link
313 * we should search for the destination
314 * as our clue to the interface. Otherwise
315 * we can use the local address.
316 */
317 ifa = 0;
318 if (entry->rt_flags & RTF_HOST)
319 ifa = ifa_ifwithdstaddr(&entry->rt_dst);
320 if (ifa == 0)
321 ifa = ifa_ifwithaddr(&entry->rt_gateway);
d7887ae9 322 } else {
8bbafbd9
MK
323 /*
324 * If we are adding a route to a remote net
325 * or host, the gateway may still be on the
326 * other end of a pt to pt link.
327 */
328 ifa = ifa_ifwithdstaddr(&entry->rt_gateway);
d7887ae9 329 }
8bbafbd9
MK
330 if (ifa == 0) {
331 ifa = ifa_ifwithnet(&entry->rt_gateway);
332 if (ifa == 0 && req == SIOCADDRT) {
333 error = ENETUNREACH;
334 goto bad;
9d03c806 335 }
c124e997 336 }
8bbafbd9
MK
337 if (entry->rt_flags & RTF_HOST)
338 netmask = 0;
339 else
340 netmask = rtgetmask(&entry->rt_dst, ifa);
9d03c806
SL
341 switch (req) {
342
343 case SIOCDELRT:
8bbafbd9
MK
344 if ((rn = rn_delete((char *)&entry->rt_dst,
345 netmask, head)) == 0) {
d7887ae9
BJ
346 error = ESRCH;
347 goto bad;
348 }
8bbafbd9
MK
349 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
350 panic ("rtrequest delete");
351 nrt = (struct nrtentry *)rn;
352 nrt->nrt_rt.rt_flags &= ~RTF_UP;
353 if (nrt->nrt_rt.rt_refcnt > 0)
a13c006d 354 rttrash++;
8bbafbd9
MK
355 else
356 free((caddr_t)nrt, M_RTABLE);
9d03c806
SL
357 break;
358
359 case SIOCADDRT:
8bbafbd9
MK
360 Malloc(nrt, struct nrtentry *, sizeof *nrt);
361 if (nrt == 0) {
362 error = ENOBUFS;
d7887ae9
BJ
363 goto bad;
364 }
8bbafbd9
MK
365 Bzero(nrt, sizeof *nrt);
366 rn = rn_addroute((char *)&entry->rt_dst, netmask,
367 head, nrt->nrt_nodes);
368 if (rn == 0) {
369 free((caddr_t)nrt, M_RTABLE);
370 error = EEXIST;
d7887ae9 371 goto bad;
c124e997 372 }
8bbafbd9
MK
373 rt = &nrt->nrt_rt;
374 rn->rn_key = (char *)&(nrt->nrt_rt.rt_dst);
a13c006d
BJ
375 rt->rt_dst = entry->rt_dst;
376 rt->rt_gateway = entry->rt_gateway;
92c26501
MK
377 rt->rt_flags = RTF_UP |
378 (entry->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC));
a13c006d 379 rt->rt_use = 0;
8bbafbd9 380 rt->rt_refcnt = 0;
cba69651 381 rt->rt_ifp = ifa->ifa_ifp;
9d03c806
SL
382 break;
383 }
c124e997
SL
384bad:
385 splx(s);
386 return (error);
9d03c806 387}
f6311fb6
SL
388
389/*
390 * Set up a routing table entry, normally
391 * for an interface.
392 */
2a63f7ba 393rtinit(dst, gateway, cmd, flags)
f6311fb6 394 struct sockaddr *dst, *gateway;
2a63f7ba 395 int cmd, flags;
f6311fb6
SL
396{
397 struct rtentry route;
f6311fb6 398
a13c006d 399 bzero((caddr_t)&route, sizeof (route));
f6311fb6
SL
400 route.rt_dst = *dst;
401 route.rt_gateway = *gateway;
402 route.rt_flags = flags;
0c33c832 403 (void) rtrequest(cmd, &route);
f6311fb6 404}