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