add IFF_LOCAL
[unix-history] / usr / src / sys / net / route.c
CommitLineData
7eb1f827 1/* route.c 6.3 83/12/15 */
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;
0b33b6b5 28 register u_long 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
7eb1f827
MK
36 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
37 return; /* XXX */
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 */
7eb1f827 112rtredirect(dst, gateway, flags)
464f931f 113 struct sockaddr *dst, *gateway;
7eb1f827 114 int flags;
464f931f
SL
115{
116 struct route ro;
117 register struct rtentry *rt;
118
119 /* verify the gateway is directly reachable */
a9ea8834
SL
120 if (if_ifwithnet(gateway) == 0) {
121 rtstat.rts_badredirect++;
464f931f 122 return;
a9ea8834 123 }
464f931f 124 ro.ro_dst = *dst;
a9ea8834 125 ro.ro_rt = 0;
464f931f
SL
126 rtalloc(&ro);
127 rt = ro.ro_rt;
a9ea8834 128 /*
48afbdc5
SL
129 * Create a new entry if we just got back a wildcard entry
130 * or the the lookup failed. This is necessary for hosts
131 * which use routing redirects generated by smart gateways
132 * to dynamically build the routing tables.
a9ea8834 133 */
48afbdc5
SL
134 if (rt &&
135 (*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) {
136 rtfree(rt);
137 rt = 0;
138 }
a9ea8834
SL
139 if (rt == 0) {
140 rtinit(dst, gateway, RTF_GATEWAY);
141 rtstat.rts_dynamic++;
142 return;
143 }
464f931f
SL
144 /*
145 * Don't listen to the redirect if it's
146 * for a route to an interface.
464f931f 147 */
a9ea8834 148 if (rt->rt_flags & RTF_GATEWAY) {
7eb1f827
MK
149 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
150 /*
151 * Changing from route to gateway => route to host.
152 * Create new route, rather than smashing route to net.
153 */
154 rtfree(rt);
155 rtinit(dst, gateway, flags);
156 rtstat.rts_newgateway++;
157 } else {
158 /*
159 * Smash the current notion of the gateway to
160 * this destination. This is probably not right,
161 * as it's conceivable a flurry of redirects could
162 * cause the gateway value to fluctuate wildly during
163 * dynamic routing reconfiguration.
164 */
165 rt->rt_gateway = *gateway;
166 rtfree(rt);
167 rtstat.rts_newgateway++;
168 }
a9ea8834 169 }
464f931f
SL
170}
171
a62dd253
SL
172/*
173 * Routing table ioctl interface.
174 */
175rtioctl(cmd, data)
176 int cmd;
177 caddr_t data;
178{
179
180 if (cmd != SIOCADDRT && cmd != SIOCDELRT)
181 return (EINVAL);
182 if (!suser())
183 return (u.u_error);
184 return (rtrequest(cmd, (struct rtentry *)data));
185}
186
9d03c806 187/*
c124e997 188 * Carry out a request to change the routing table. Called by
a9ea8834
SL
189 * interfaces at boot time to make their ``local routes'' known,
190 * for ioctl's, and as the result of routing redirects.
9d03c806 191 */
a13c006d 192rtrequest(req, entry)
9d03c806 193 int req;
a13c006d 194 register struct rtentry *entry;
9d03c806 195{
9d03c806 196 register struct mbuf *m, **mprev;
a13c006d 197 register struct rtentry *rt;
9d03c806 198 struct afhash h;
0b33b6b5 199 int s, error = 0, (*match)();
e8de4b5e 200 u_int af;
0b33b6b5 201 u_long hash;
a13c006d 202 struct ifnet *ifp;
9d03c806 203
a13c006d 204 af = entry->rt_dst.sa_family;
e65dcd4c
SL
205 if (af >= AF_MAX)
206 return (EAFNOSUPPORT);
a13c006d
BJ
207 (*afswitch[af].af_hash)(&entry->rt_dst, &h);
208 if (entry->rt_flags & RTF_HOST) {
d7887ae9
BJ
209 hash = h.afh_hosthash;
210 mprev = &rthost[hash % RTHASHSIZ];
211 } else {
212 hash = h.afh_nethash;
213 mprev = &rtnet[hash % RTHASHSIZ];
214 }
215 match = afswitch[af].af_netmatch;
c124e997 216 s = splimp();
9d03c806
SL
217 for (; m = *mprev; mprev = &m->m_next) {
218 rt = mtod(m, struct rtentry *);
fc74f0c9 219 if (rt->rt_hash != hash)
9d03c806 220 continue;
a13c006d
BJ
221 if (entry->rt_flags & RTF_HOST) {
222#define equal(a1, a2) \
223 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
224 if (!equal(&rt->rt_dst, &entry->rt_dst))
9d03c806
SL
225 continue;
226 } else {
a13c006d
BJ
227 if (rt->rt_dst.sa_family != entry->rt_dst.sa_family ||
228 (*match)(&rt->rt_dst, &entry->rt_dst) == 0)
9d03c806
SL
229 continue;
230 }
a13c006d 231 if (equal(&rt->rt_gateway, &entry->rt_gateway))
d7887ae9 232 break;
c124e997 233 }
9d03c806
SL
234 switch (req) {
235
236 case SIOCDELRT:
d7887ae9
BJ
237 if (m == 0) {
238 error = ESRCH;
239 goto bad;
240 }
a13c006d 241 *mprev = m->m_next;
d7887ae9 242 if (rt->rt_refcnt > 0) {
a13c006d
BJ
243 rt->rt_flags &= ~RTF_UP;
244 rttrash++;
245 m->m_next = 0;
246 } else
247 (void) m_free(m);
9d03c806
SL
248 break;
249
250 case SIOCADDRT:
a13c006d 251 if (m) {
d7887ae9
BJ
252 error = EEXIST;
253 goto bad;
254 }
a13c006d
BJ
255 ifp = if_ifwithaddr(&entry->rt_gateway);
256 if (ifp == 0) {
257 ifp = if_ifwithnet(&entry->rt_gateway);
258 if (ifp == 0) {
259 error = ENETUNREACH;
260 goto bad;
261 }
262 }
cce93e4b 263 m = m_get(M_DONTWAIT, MT_RTABLE);
c124e997
SL
264 if (m == 0) {
265 error = ENOBUFS;
d7887ae9 266 goto bad;
c124e997 267 }
a13c006d 268 *mprev = m;
9d03c806 269 m->m_off = MMINOFF;
f6311fb6 270 m->m_len = sizeof (struct rtentry);
9d03c806 271 rt = mtod(m, struct rtentry *);
d7887ae9 272 rt->rt_hash = hash;
a13c006d
BJ
273 rt->rt_dst = entry->rt_dst;
274 rt->rt_gateway = entry->rt_gateway;
275 rt->rt_flags =
276 RTF_UP | (entry->rt_flags & (RTF_HOST|RTF_GATEWAY));
fc74f0c9 277 rt->rt_refcnt = 0;
a13c006d
BJ
278 rt->rt_use = 0;
279 rt->rt_ifp = ifp;
9d03c806
SL
280 break;
281 }
c124e997
SL
282bad:
283 splx(s);
284 return (error);
9d03c806 285}
f6311fb6
SL
286
287/*
288 * Set up a routing table entry, normally
289 * for an interface.
290 */
291rtinit(dst, gateway, flags)
292 struct sockaddr *dst, *gateway;
293 int flags;
294{
295 struct rtentry route;
0c33c832 296 int cmd;
f6311fb6 297
0c33c832
SL
298 if (flags == -1) {
299 cmd = (int)SIOCDELRT;
300 flags = 0;
301 } else {
302 cmd = (int)SIOCADDRT;
303 }
a13c006d 304 bzero((caddr_t)&route, sizeof (route));
f6311fb6
SL
305 route.rt_dst = *dst;
306 route.rt_gateway = *gateway;
307 route.rt_flags = flags;
0c33c832 308 (void) rtrequest(cmd, &route);
f6311fb6 309}