Add copyright
[unix-history] / usr / src / sys / net / route.c
CommitLineData
cb1c44c2
KM
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)route.c 6.10 (Berkeley) %G%
7 */
9d03c806 8
a0369dcf
JB
9#include "param.h"
10#include "systm.h"
11#include "mbuf.h"
12#include "protosw.h"
13#include "socket.h"
14#include "dir.h"
15#include "user.h"
16#include "ioctl.h"
17#include "errno.h"
f4d55810 18
a0369dcf
JB
19#include "if.h"
20#include "af.h"
21#include "route.h"
9d03c806 22
a13c006d 23int rttrash; /* routes not in table but not freed */
a9ea8834 24struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
c50b0999 25int rthashsize = RTHASHSIZ; /* for netstat, etc. */
a9ea8834 26
9d03c806
SL
27/*
28 * Packet routing routines.
29 */
f6311fb6 30rtalloc(ro)
9d03c806
SL
31 register struct route *ro;
32{
a9ea8834 33 register struct rtentry *rt;
9d03c806 34 register struct mbuf *m;
0b33b6b5 35 register u_long hash;
9d03c806 36 struct sockaddr *dst = &ro->ro_dst;
c50b0999 37 int (*match)(), doinghost, s;
a9ea8834 38 struct afhash h;
e8de4b5e 39 u_int af = dst->sa_family;
a9ea8834 40 struct mbuf **table;
9d03c806 41
7eb1f827
MK
42 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
43 return; /* XXX */
e65dcd4c
SL
44 if (af >= AF_MAX)
45 return;
9d03c806 46 (*afswitch[af].af_hash)(dst, &h);
fc74f0c9 47 match = afswitch[af].af_netmatch;
a9ea8834 48 hash = h.afh_hosthash, table = rthost, doinghost = 1;
c50b0999 49 s = splnet();
a9ea8834 50again:
b50b85d9 51 for (m = table[RTHASHMOD(hash)]; m; m = m->m_next) {
fc74f0c9
SL
52 rt = mtod(m, struct rtentry *);
53 if (rt->rt_hash != hash)
54 continue;
90137845
SL
55 if ((rt->rt_flags & RTF_UP) == 0 ||
56 (rt->rt_ifp->if_flags & IFF_UP) == 0)
57 continue;
a9ea8834
SL
58 if (doinghost) {
59 if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst,
60 sizeof (*dst)))
61 continue;
62 } else {
63 if (rt->rt_dst.sa_family != af ||
64 !(*match)(&rt->rt_dst, dst))
65 continue;
66 }
c50b0999
MK
67 rt->rt_refcnt++;
68 splx(s);
69 if (dst == &wildcard)
70 rtstat.rts_wildcard++;
71 ro->ro_rt = rt;
72 return;
9d03c806 73 }
c50b0999 74 if (doinghost) {
a9ea8834
SL
75 doinghost = 0;
76 hash = h.afh_nethash, table = rtnet;
77 goto again;
78 }
79 /*
80 * Check for wildcard gateway, by convention network 0.
81 */
c50b0999 82 if (dst != &wildcard) {
a9ea8834
SL
83 dst = &wildcard, hash = 0;
84 goto again;
85 }
c50b0999
MK
86 splx(s);
87 rtstat.rts_unreach++;
9d03c806
SL
88}
89
f6311fb6 90rtfree(rt)
c124e997
SL
91 register struct rtentry *rt;
92{
f6311fb6 93
c124e997 94 if (rt == 0)
a1edc12b 95 panic("rtfree");
c124e997 96 rt->rt_refcnt--;
a13c006d
BJ
97 if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) {
98 rttrash--;
99 (void) m_free(dtom(rt));
100 }
c124e997
SL
101}
102
464f931f
SL
103/*
104 * Force a routing table entry to the specified
105 * destination to go through the given gateway.
106 * Normally called as a result of a routing redirect
107 * message from the network layer.
108 *
109 * N.B.: must be called at splnet or higher
110 *
111 * Should notify all parties with a reference to
112 * the route that it's changed (so, for instance,
a9ea8834 113 * current round trip time estimates could be flushed),
464f931f
SL
114 * but we have no back pointers at the moment.
115 */
7eb1f827 116rtredirect(dst, gateway, flags)
464f931f 117 struct sockaddr *dst, *gateway;
7eb1f827 118 int flags;
464f931f
SL
119{
120 struct route ro;
121 register struct rtentry *rt;
122
123 /* verify the gateway is directly reachable */
cba69651 124 if (ifa_ifwithnet(gateway) == 0) {
a9ea8834 125 rtstat.rts_badredirect++;
464f931f 126 return;
a9ea8834 127 }
464f931f 128 ro.ro_dst = *dst;
a9ea8834 129 ro.ro_rt = 0;
464f931f
SL
130 rtalloc(&ro);
131 rt = ro.ro_rt;
a9ea8834 132 /*
48afbdc5
SL
133 * Create a new entry if we just got back a wildcard entry
134 * or the the lookup failed. This is necessary for hosts
135 * which use routing redirects generated by smart gateways
136 * to dynamically build the routing tables.
a9ea8834 137 */
48afbdc5
SL
138 if (rt &&
139 (*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) {
140 rtfree(rt);
141 rt = 0;
142 }
a9ea8834 143 if (rt == 0) {
66798f86 144 rtinit(dst, gateway, (flags & RTF_HOST) | RTF_GATEWAY);
a9ea8834
SL
145 rtstat.rts_dynamic++;
146 return;
147 }
464f931f
SL
148 /*
149 * Don't listen to the redirect if it's
150 * for a route to an interface.
464f931f 151 */
a9ea8834 152 if (rt->rt_flags & RTF_GATEWAY) {
7eb1f827
MK
153 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
154 /*
66798f86 155 * Changing from route to net => route to host.
7eb1f827
MK
156 * Create new route, rather than smashing route to net.
157 */
7eb1f827 158 rtinit(dst, gateway, flags);
7eb1f827
MK
159 } else {
160 /*
161 * Smash the current notion of the gateway to
162 * this destination. This is probably not right,
163 * as it's conceivable a flurry of redirects could
164 * cause the gateway value to fluctuate wildly during
165 * dynamic routing reconfiguration.
166 */
167 rt->rt_gateway = *gateway;
7eb1f827 168 }
66798f86 169 rtstat.rts_newgateway++;
a9ea8834 170 }
ff320836 171 rtfree(rt);
464f931f
SL
172}
173
a62dd253
SL
174/*
175 * Routing table ioctl interface.
176 */
177rtioctl(cmd, data)
178 int cmd;
179 caddr_t data;
180{
181
182 if (cmd != SIOCADDRT && cmd != SIOCDELRT)
183 return (EINVAL);
184 if (!suser())
185 return (u.u_error);
186 return (rtrequest(cmd, (struct rtentry *)data));
187}
188
9d03c806 189/*
c124e997 190 * Carry out a request to change the routing table. Called by
a9ea8834
SL
191 * interfaces at boot time to make their ``local routes'' known,
192 * for ioctl's, and as the result of routing redirects.
9d03c806 193 */
a13c006d 194rtrequest(req, entry)
9d03c806 195 int req;
a13c006d 196 register struct rtentry *entry;
9d03c806 197{
9d03c806 198 register struct mbuf *m, **mprev;
a13c006d 199 register struct rtentry *rt;
9d03c806 200 struct afhash h;
0b33b6b5 201 int s, error = 0, (*match)();
e8de4b5e 202 u_int af;
0b33b6b5 203 u_long hash;
cba69651 204 struct ifaddr *ifa;
9d03c806 205
a13c006d 206 af = entry->rt_dst.sa_family;
e65dcd4c
SL
207 if (af >= AF_MAX)
208 return (EAFNOSUPPORT);
a13c006d
BJ
209 (*afswitch[af].af_hash)(&entry->rt_dst, &h);
210 if (entry->rt_flags & RTF_HOST) {
d7887ae9 211 hash = h.afh_hosthash;
b50b85d9 212 mprev = &rthost[RTHASHMOD(hash)];
d7887ae9
BJ
213 } else {
214 hash = h.afh_nethash;
b50b85d9 215 mprev = &rtnet[RTHASHMOD(hash)];
d7887ae9
BJ
216 }
217 match = afswitch[af].af_netmatch;
c124e997 218 s = splimp();
9d03c806
SL
219 for (; m = *mprev; mprev = &m->m_next) {
220 rt = mtod(m, struct rtentry *);
fc74f0c9 221 if (rt->rt_hash != hash)
9d03c806 222 continue;
a13c006d
BJ
223 if (entry->rt_flags & RTF_HOST) {
224#define equal(a1, a2) \
225 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
226 if (!equal(&rt->rt_dst, &entry->rt_dst))
9d03c806
SL
227 continue;
228 } else {
a13c006d
BJ
229 if (rt->rt_dst.sa_family != entry->rt_dst.sa_family ||
230 (*match)(&rt->rt_dst, &entry->rt_dst) == 0)
9d03c806
SL
231 continue;
232 }
a13c006d 233 if (equal(&rt->rt_gateway, &entry->rt_gateway))
d7887ae9 234 break;
c124e997 235 }
9d03c806
SL
236 switch (req) {
237
238 case SIOCDELRT:
d7887ae9
BJ
239 if (m == 0) {
240 error = ESRCH;
241 goto bad;
242 }
a13c006d 243 *mprev = m->m_next;
d7887ae9 244 if (rt->rt_refcnt > 0) {
a13c006d
BJ
245 rt->rt_flags &= ~RTF_UP;
246 rttrash++;
247 m->m_next = 0;
248 } else
249 (void) m_free(m);
9d03c806
SL
250 break;
251
252 case SIOCADDRT:
a13c006d 253 if (m) {
d7887ae9
BJ
254 error = EEXIST;
255 goto bad;
256 }
cba69651
MK
257 ifa = ifa_ifwithaddr(&entry->rt_gateway);
258 if (ifa == 0) {
259 ifa = ifa_ifwithnet(&entry->rt_gateway);
260 if (ifa == 0) {
a13c006d
BJ
261 error = ENETUNREACH;
262 goto bad;
263 }
264 }
cce93e4b 265 m = m_get(M_DONTWAIT, MT_RTABLE);
c124e997
SL
266 if (m == 0) {
267 error = ENOBUFS;
d7887ae9 268 goto bad;
c124e997 269 }
a13c006d 270 *mprev = m;
9d03c806 271 m->m_off = MMINOFF;
f6311fb6 272 m->m_len = sizeof (struct rtentry);
9d03c806 273 rt = mtod(m, struct rtentry *);
d7887ae9 274 rt->rt_hash = hash;
a13c006d
BJ
275 rt->rt_dst = entry->rt_dst;
276 rt->rt_gateway = entry->rt_gateway;
277 rt->rt_flags =
278 RTF_UP | (entry->rt_flags & (RTF_HOST|RTF_GATEWAY));
fc74f0c9 279 rt->rt_refcnt = 0;
a13c006d 280 rt->rt_use = 0;
cba69651 281 rt->rt_ifp = ifa->ifa_ifp;
9d03c806
SL
282 break;
283 }
c124e997
SL
284bad:
285 splx(s);
286 return (error);
9d03c806 287}
f6311fb6
SL
288
289/*
290 * Set up a routing table entry, normally
291 * for an interface.
292 */
293rtinit(dst, gateway, flags)
294 struct sockaddr *dst, *gateway;
295 int flags;
296{
297 struct rtentry route;
0c33c832 298 int cmd;
f6311fb6 299
0c33c832
SL
300 if (flags == -1) {
301 cmd = (int)SIOCDELRT;
302 flags = 0;
303 } else {
304 cmd = (int)SIOCADDRT;
305 }
a13c006d 306 bzero((caddr_t)&route, sizeof (route));
f6311fb6
SL
307 route.rt_dst = *dst;
308 route.rt_gateway = *gateway;
309 route.rt_flags = flags;
0c33c832 310 (void) rtrequest(cmd, &route);
f6311fb6 311}