Commit | Line | Data |
---|---|---|
cb1c44c2 | 1 | /* |
ada378d8 | 2 | * Copyright (c) 1980, 1986, 1991 Regents of the University of California. |
5b519e94 | 3 | * All rights reserved. |
cb1c44c2 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
5b519e94 | 6 | * |
9e2e06fb | 7 | * @(#)route.c 7.31 (Berkeley) %G% |
cb1c44c2 | 8 | */ |
a0369dcf JB |
9 | #include "param.h" |
10 | #include "systm.h" | |
ea372425 MK |
11 | #include "proc.h" |
12 | #include "mbuf.h" | |
13 | #include "socket.h" | |
14 | #include "socketvar.h" | |
15 | #include "domain.h" | |
16 | #include "protosw.h" | |
ea372425 | 17 | #include "ioctl.h" |
f4d55810 | 18 | |
a0369dcf JB |
19 | #include "if.h" |
20 | #include "af.h" | |
21 | #include "route.h" | |
ea372425 | 22 | #include "raw_cb.h" |
8f194ccc | 23 | |
8bbafbd9 MK |
24 | #include "../netinet/in.h" |
25 | #include "../netinet/in_var.h" | |
ea372425 | 26 | |
4fcdb761 | 27 | #ifdef NS |
b72a6efb | 28 | #include "../netns/ns.h" |
4fcdb761 | 29 | #endif |
8f194ccc | 30 | |
983eada9 | 31 | #define SA(p) ((struct sockaddr *)(p)) |
ea372425 | 32 | |
a13c006d | 33 | int rttrash; /* routes not in table but not freed */ |
a9ea8834 SL |
34 | struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ |
35 | ||
5c48f39f KS |
36 | rtable_init(table) |
37 | void **table; | |
38 | { | |
39 | struct domain *dom; | |
40 | for (dom = domains; dom; dom = dom->dom_next) | |
41 | if (dom->dom_rtattach) | |
42 | dom->dom_rtattach(&table[dom->dom_family], | |
43 | dom->dom_rtoffset); | |
44 | } | |
8f194ccc | 45 | |
5c48f39f | 46 | route_init() |
8bbafbd9 | 47 | { |
5c48f39f KS |
48 | rn_init(); /* initialize all zeroes, all ones, mask table */ |
49 | rtable_init((void **)rt_tables); | |
8bbafbd9 MK |
50 | } |
51 | ||
9d03c806 SL |
52 | /* |
53 | * Packet routing routines. | |
54 | */ | |
f6311fb6 | 55 | rtalloc(ro) |
9d03c806 | 56 | register struct route *ro; |
ea372425 MK |
57 | { |
58 | if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) | |
59 | return; /* XXX */ | |
60 | ro->ro_rt = rtalloc1(&ro->ro_dst, 1); | |
61 | } | |
62 | ||
63 | struct rtentry * | |
64 | rtalloc1(dst, report) | |
983eada9 | 65 | register struct sockaddr *dst; |
ea372425 | 66 | int report; |
9d03c806 | 67 | { |
2a0319dc | 68 | register struct radix_node_head *rnh = rt_tables[dst->sa_family]; |
983eada9 | 69 | register struct rtentry *rt; |
8bbafbd9 | 70 | register struct radix_node *rn; |
983eada9 | 71 | struct rtentry *newrt = 0; |
d93f9386 | 72 | struct rt_addrinfo info; |
9bdb9951 | 73 | int s = splnet(), err = 0, msgtype = RTM_MISS; |
9d03c806 | 74 | |
8bbafbd9 | 75 | if (rnh && rnh->rnh_treetop && |
2a0319dc | 76 | (rn = rnh->rnh_match((caddr_t)dst, rnh->rnh_treetop)) && |
8bbafbd9 | 77 | ((rn->rn_flags & RNF_ROOT) == 0)) { |
983eada9 | 78 | newrt = rt = (struct rtentry *)rn; |
044f6a7f | 79 | if (report && (rt->rt_flags & RTF_CLONING)) { |
9e2e06fb KS |
80 | err = rtrequest(RTM_RESOLVE, dst, SA(0), |
81 | SA(0), 0, &newrt); | |
82 | if (err) { | |
83 | newrt = rt; | |
84 | rt->rt_refcnt++; | |
85 | goto miss; | |
86 | } | |
87 | if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { | |
88 | msgtype = RTM_RESOLVE; | |
89 | goto miss; | |
90 | } | |
044f6a7f KS |
91 | } else |
92 | rt->rt_refcnt++; | |
ea372425 | 93 | } else { |
8bbafbd9 | 94 | rtstat.rts_unreach++; |
d93f9386 KS |
95 | miss: if (report) { |
96 | bzero((caddr_t)&info, sizeof(info)); | |
97 | info.rti_info[RTAX_DST] = dst; | |
98 | rt_missmsg(msgtype, &info, 0, err); | |
99 | } | |
ea372425 | 100 | } |
c50b0999 | 101 | splx(s); |
983eada9 | 102 | return (newrt); |
9d03c806 SL |
103 | } |
104 | ||
f6311fb6 | 105 | rtfree(rt) |
c124e997 SL |
106 | register struct rtentry *rt; |
107 | { | |
044f6a7f | 108 | register struct ifaddr *ifa; |
9e2e06fb | 109 | |
c124e997 | 110 | if (rt == 0) |
a1edc12b | 111 | panic("rtfree"); |
c124e997 | 112 | rt->rt_refcnt--; |
044f6a7f | 113 | if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { |
ea372425 | 114 | if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) |
8bbafbd9 | 115 | panic ("rtfree 2"); |
9e2e06fb KS |
116 | rttrash--; |
117 | if (rt->rt_refcnt < 0) { | |
118 | printf("rtfree: %x not freed (neg refs)\n", rt); | |
119 | return; | |
120 | } | |
121 | ifa = rt->rt_ifa; | |
122 | IFAFREE(ifa); | |
4d306fe6 KS |
123 | Free(rt_key(rt)); |
124 | Free(rt); | |
a13c006d | 125 | } |
c124e997 | 126 | } |
9e2e06fb KS |
127 | |
128 | int ifafree_verbose = 1; | |
129 | /* | |
130 | * We are still debugging potential overfreeing of ifaddr's | |
131 | */ | |
dcdf065d KS |
132 | void |
133 | ifafree(ifa) | |
134 | register struct ifaddr *ifa; | |
135 | { | |
136 | if (ifa == 0) | |
137 | panic("ifafree"); | |
9e2e06fb KS |
138 | if (ifa->ifa_refcnt < 0) |
139 | printf("ifafree: %x ref %d\n", ifa, ifa->ifa_refcnt); | |
140 | if (ifa->ifa_refcnt == 0 && ifafree_verbose) | |
141 | printf("ifafree: %x not freed.\n", ifa); | |
dcdf065d | 142 | ifa->ifa_refcnt--; |
dcdf065d KS |
143 | } |
144 | ||
464f931f SL |
145 | /* |
146 | * Force a routing table entry to the specified | |
147 | * destination to go through the given gateway. | |
148 | * Normally called as a result of a routing redirect | |
149 | * message from the network layer. | |
150 | * | |
8bbafbd9 | 151 | * N.B.: must be called at splnet |
464f931f | 152 | * |
464f931f | 153 | */ |
b72a6efb KS |
154 | rtredirect(dst, gateway, netmask, flags, src, rtp) |
155 | struct sockaddr *dst, *gateway, *netmask, *src; | |
7eb1f827 | 156 | int flags; |
b72a6efb | 157 | struct rtentry **rtp; |
464f931f | 158 | { |
464f931f | 159 | register struct rtentry *rt; |
b72a6efb KS |
160 | int error = 0; |
161 | short *stat = 0; | |
d93f9386 | 162 | struct rt_addrinfo info; |
464f931f SL |
163 | |
164 | /* verify the gateway is directly reachable */ | |
cba69651 | 165 | if (ifa_ifwithnet(gateway) == 0) { |
b72a6efb | 166 | error = ENETUNREACH; |
9294a79f | 167 | goto out; |
a9ea8834 | 168 | } |
b72a6efb | 169 | rt = rtalloc1(dst, 0); |
92c26501 MK |
170 | /* |
171 | * If the redirect isn't from our current router for this dst, | |
2e9c4868 MK |
172 | * it's either old or wrong. If it redirects us to ourselves, |
173 | * we have a routing loop, perhaps as a result of an interface | |
174 | * going down recently. | |
92c26501 | 175 | */ |
b72a6efb KS |
176 | #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) |
177 | if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway)) | |
178 | error = EINVAL; | |
179 | else if (ifa_ifwithaddr(gateway)) | |
180 | error = EHOSTUNREACH; | |
181 | if (error) | |
182 | goto done; | |
a9ea8834 | 183 | /* |
48afbdc5 SL |
184 | * Create a new entry if we just got back a wildcard entry |
185 | * or the the lookup failed. This is necessary for hosts | |
186 | * which use routing redirects generated by smart gateways | |
187 | * to dynamically build the routing tables. | |
8bbafbd9 | 188 | */ |
b72a6efb KS |
189 | if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) |
190 | goto create; | |
464f931f SL |
191 | /* |
192 | * Don't listen to the redirect if it's | |
193 | * for a route to an interface. | |
464f931f | 194 | */ |
a9ea8834 | 195 | if (rt->rt_flags & RTF_GATEWAY) { |
7eb1f827 MK |
196 | if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { |
197 | /* | |
66798f86 | 198 | * Changing from route to net => route to host. |
7eb1f827 MK |
199 | * Create new route, rather than smashing route to net. |
200 | */ | |
b72a6efb KS |
201 | create: |
202 | flags |= RTF_GATEWAY | RTF_DYNAMIC; | |
203 | error = rtrequest((int)RTM_ADD, dst, gateway, | |
983eada9 | 204 | SA(0), flags, |
b72a6efb KS |
205 | (struct rtentry **)0); |
206 | stat = &rtstat.rts_dynamic; | |
7eb1f827 MK |
207 | } else { |
208 | /* | |
209 | * Smash the current notion of the gateway to | |
b72a6efb | 210 | * this destination. Should check about netmask!!! |
7eb1f827 | 211 | */ |
4d306fe6 KS |
212 | rt->rt_flags |= RTF_MODIFIED; |
213 | flags |= RTF_MODIFIED; | |
214 | stat = &rtstat.rts_newgateway; | |
215 | rt_setgate(rt, rt_key(rt), gateway); | |
7eb1f827 | 216 | } |
92c26501 | 217 | } else |
b72a6efb KS |
218 | error = EHOSTUNREACH; |
219 | done: | |
220 | if (rt) { | |
221 | if (rtp && !error) | |
222 | *rtp = rt; | |
223 | else | |
224 | rtfree(rt); | |
225 | } | |
9294a79f | 226 | out: |
b72a6efb | 227 | if (error) |
92c26501 | 228 | rtstat.rts_badredirect++; |
9294a79f KS |
229 | else if (stat != NULL) |
230 | (*stat)++; | |
d93f9386 KS |
231 | bzero((caddr_t)&info, sizeof(info)); |
232 | info.rti_info[RTAX_DST] = dst; | |
233 | info.rti_info[RTAX_GATEWAY] = gateway; | |
234 | info.rti_info[RTAX_NETMASK] = netmask; | |
235 | info.rti_info[RTAX_AUTHOR] = src; | |
236 | rt_missmsg(RTM_REDIRECT, &info, flags, error); | |
464f931f SL |
237 | } |
238 | ||
a62dd253 | 239 | /* |
b72a6efb KS |
240 | * Routing table ioctl interface. |
241 | */ | |
8f194ccc | 242 | rtioctl(req, data, p) |
ea372425 | 243 | int req; |
a62dd253 | 244 | caddr_t data; |
8f194ccc | 245 | struct proc *p; |
a62dd253 | 246 | { |
ea372425 MK |
247 | #ifndef COMPAT_43 |
248 | return (EOPNOTSUPP); | |
249 | #else | |
250 | register struct ortentry *entry = (struct ortentry *)data; | |
251 | int error; | |
252 | struct sockaddr *netmask = 0; | |
a62dd253 | 253 | |
ea372425 MK |
254 | if (req == SIOCADDRT) |
255 | req = RTM_ADD; | |
256 | else if (req == SIOCDELRT) | |
257 | req = RTM_DELETE; | |
258 | else | |
a62dd253 | 259 | return (EINVAL); |
ea372425 | 260 | |
8f194ccc | 261 | if (error = suser(p->p_ucred, &p->p_acflag)) |
06c16dfa | 262 | return (error); |
a7b1cd9a MK |
263 | #if BYTE_ORDER != BIG_ENDIAN |
264 | if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) { | |
265 | entry->rt_dst.sa_family = entry->rt_dst.sa_len; | |
266 | entry->rt_dst.sa_len = 16; | |
267 | } | |
268 | if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) { | |
269 | entry->rt_gateway.sa_family = entry->rt_gateway.sa_len; | |
270 | entry->rt_gateway.sa_len = 16; | |
271 | } | |
272 | #else | |
273 | if (entry->rt_dst.sa_len == 0) | |
274 | entry->rt_dst.sa_len = 16; | |
275 | if (entry->rt_gateway.sa_len == 0) | |
276 | entry->rt_gateway.sa_len = 16; | |
277 | #endif | |
ea372425 MK |
278 | if ((entry->rt_flags & RTF_HOST) == 0) |
279 | switch (entry->rt_dst.sa_family) { | |
280 | #ifdef INET | |
281 | case AF_INET: | |
282 | { | |
283 | extern struct sockaddr_in icmpmask; | |
ea372425 MK |
284 | struct sockaddr_in *dst_in = |
285 | (struct sockaddr_in *)&entry->rt_dst; | |
ea372425 | 286 | |
b72a6efb | 287 | in_sockmaskof(dst_in->sin_addr, &icmpmask); |
ea372425 MK |
288 | netmask = (struct sockaddr *)&icmpmask; |
289 | } | |
290 | break; | |
291 | #endif | |
292 | #ifdef NS | |
293 | case AF_NS: | |
294 | { | |
295 | extern struct sockaddr_ns ns_netmask; | |
296 | netmask = (struct sockaddr *)&ns_netmask; | |
297 | } | |
298 | #endif | |
299 | } | |
300 | error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask, | |
b72a6efb | 301 | entry->rt_flags, (struct rtentry **)0); |
d93f9386 | 302 | /* rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL), |
ea372425 | 303 | &(entry->rt_dst), &(entry->rt_gateway), |
d93f9386 | 304 | netmask, SA(0), entry->rt_flags, error); */ |
ea372425 | 305 | return (error); |
a7b1cd9a | 306 | #endif |
ea372425 | 307 | } |
d6bc9b28 KS |
308 | |
309 | struct ifaddr * | |
310 | ifa_ifwithroute(flags, dst, gateway) | |
311 | int flags; | |
312 | struct sockaddr *dst, *gateway; | |
313 | { | |
ada378d8 | 314 | register struct ifaddr *ifa; |
d6bc9b28 KS |
315 | if ((flags & RTF_GATEWAY) == 0) { |
316 | /* | |
317 | * If we are adding a route to an interface, | |
318 | * and the interface is a pt to pt link | |
319 | * we should search for the destination | |
320 | * as our clue to the interface. Otherwise | |
321 | * we can use the local address. | |
322 | */ | |
323 | ifa = 0; | |
324 | if (flags & RTF_HOST) | |
325 | ifa = ifa_ifwithdstaddr(dst); | |
326 | if (ifa == 0) | |
327 | ifa = ifa_ifwithaddr(gateway); | |
328 | } else { | |
329 | /* | |
330 | * If we are adding a route to a remote net | |
331 | * or host, the gateway may still be on the | |
332 | * other end of a pt to pt link. | |
333 | */ | |
334 | ifa = ifa_ifwithdstaddr(gateway); | |
335 | } | |
336 | if (ifa == 0) | |
337 | ifa = ifa_ifwithnet(gateway); | |
ada378d8 KS |
338 | if (ifa == 0) { |
339 | struct rtentry *rt = rtalloc1(dst, 0); | |
340 | if (rt == 0) | |
341 | return (0); | |
342 | rt->rt_refcnt--; | |
343 | if ((ifa = rt->rt_ifa) == 0) | |
344 | return (0); | |
345 | } | |
346 | if (ifa->ifa_addr->sa_family != dst->sa_family) { | |
347 | struct ifaddr *oifa = ifa, *ifaof_ifpforaddr(); | |
348 | ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); | |
349 | if (ifa == 0) | |
350 | ifa = oifa; | |
351 | } | |
d6bc9b28 KS |
352 | return (ifa); |
353 | } | |
354 | ||
1c8ed0c8 | 355 | #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
ea372425 MK |
356 | |
357 | rtrequest(req, dst, gateway, netmask, flags, ret_nrt) | |
358 | int req, flags; | |
359 | struct sockaddr *dst, *gateway, *netmask; | |
360 | struct rtentry **ret_nrt; | |
361 | { | |
4d306fe6 | 362 | int s = splnet(); int error = 0; |
ea372425 MK |
363 | register struct rtentry *rt; |
364 | register struct radix_node *rn; | |
365 | register struct radix_node_head *rnh; | |
366 | struct ifaddr *ifa, *ifa_ifwithdstaddr(); | |
044f6a7f | 367 | struct sockaddr *ndst; |
044f6a7f | 368 | #define senderr(x) { error = x ; goto bad; } |
ea372425 | 369 | |
2a0319dc | 370 | if ((rnh = rt_tables[dst->sa_family]) == 0) |
044f6a7f KS |
371 | senderr(ESRCH); |
372 | if (flags & RTF_HOST) | |
373 | netmask = 0; | |
9d03c806 | 374 | switch (req) { |
ea372425 | 375 | case RTM_DELETE: |
2a0319dc | 376 | if ((rn = rnh->rnh_delete((caddr_t)dst, (caddr_t)netmask, |
044f6a7f KS |
377 | rnh->rnh_treetop)) == 0) |
378 | senderr(ESRCH); | |
8bbafbd9 MK |
379 | if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) |
380 | panic ("rtrequest delete"); | |
ea372425 MK |
381 | rt = (struct rtentry *)rn; |
382 | rt->rt_flags &= ~RTF_UP; | |
4d306fe6 KS |
383 | if (rt->rt_gwroute) { |
384 | rt = rt->rt_gwroute; RTFREE(rt); | |
385 | (rt = (struct rtentry *)rn)->rt_gwroute = 0; | |
386 | } | |
044f6a7f | 387 | if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) |
983eada9 | 388 | ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); |
044f6a7f | 389 | rttrash++; |
d93f9386 KS |
390 | if (ret_nrt) |
391 | *ret_nrt = rt; | |
9e2e06fb KS |
392 | else if (rt->rt_refcnt <= 0) { |
393 | rt->rt_refcnt++; | |
044f6a7f | 394 | rtfree(rt); |
9e2e06fb | 395 | } |
9d03c806 SL |
396 | break; |
397 | ||
983eada9 | 398 | case RTM_RESOLVE: |
d6bc9b28 | 399 | if (ret_nrt == 0 || (rt = *ret_nrt) == 0) |
983eada9 KS |
400 | senderr(EINVAL); |
401 | ifa = rt->rt_ifa; | |
402 | flags = rt->rt_flags & ~RTF_CLONING; | |
403 | gateway = rt->rt_gateway; | |
404 | if ((netmask = rt->rt_genmask) == 0) | |
405 | flags |= RTF_HOST; | |
406 | goto makeroute; | |
407 | ||
ea372425 | 408 | case RTM_ADD: |
d6bc9b28 KS |
409 | if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) |
410 | senderr(ENETUNREACH); | |
411 | makeroute: | |
4d306fe6 | 412 | R_Malloc(rt, struct rtentry *, sizeof(*rt)); |
044f6a7f KS |
413 | if (rt == 0) |
414 | senderr(ENOBUFS); | |
4d306fe6 KS |
415 | Bzero(rt, sizeof(*rt)); |
416 | rt->rt_flags = RTF_UP | flags; | |
417 | if (rt_setgate(rt, dst, gateway)) { | |
418 | Free(rt); | |
419 | senderr(ENOBUFS); | |
420 | } | |
421 | ndst = rt_key(rt); | |
044f6a7f KS |
422 | if (netmask) { |
423 | rt_maskedcopy(dst, ndst, netmask); | |
424 | } else | |
425 | Bcopy(dst, ndst, dst->sa_len); | |
2a0319dc | 426 | rn = rnh->rnh_add((caddr_t)ndst, (caddr_t)netmask, |
ea372425 | 427 | rnh->rnh_treetop, rt->rt_nodes); |
8bbafbd9 | 428 | if (rn == 0) { |
4d306fe6 KS |
429 | if (rt->rt_gwroute) |
430 | rtfree(rt->rt_gwroute); | |
af45b283 | 431 | Free(rt_key(rt)); |
4d306fe6 | 432 | Free(rt); |
044f6a7f | 433 | senderr(EEXIST); |
c124e997 | 434 | } |
dcdf065d | 435 | ifa->ifa_refcnt++; |
b72a6efb | 436 | rt->rt_ifa = ifa; |
983eada9 | 437 | rt->rt_ifp = ifa->ifa_ifp; |
983eada9 KS |
438 | if (req == RTM_RESOLVE) |
439 | rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ | |
044f6a7f | 440 | if (ifa->ifa_rtrequest) |
983eada9 KS |
441 | ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); |
442 | if (ret_nrt) { | |
443 | *ret_nrt = rt; | |
444 | rt->rt_refcnt++; | |
445 | } | |
9d03c806 SL |
446 | break; |
447 | } | |
c124e997 SL |
448 | bad: |
449 | splx(s); | |
450 | return (error); | |
9d03c806 | 451 | } |
044f6a7f | 452 | |
4d306fe6 KS |
453 | rt_setgate(rt0, dst, gate) |
454 | struct rtentry *rt0; | |
455 | struct sockaddr *dst, *gate; | |
456 | { | |
457 | caddr_t new, old; | |
458 | int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); | |
459 | register struct rtentry *rt = rt0; | |
460 | ||
461 | if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { | |
462 | old = (caddr_t)rt_key(rt); | |
463 | R_Malloc(new, caddr_t, dlen + glen); | |
464 | if (new == 0) | |
465 | return 1; | |
466 | rt->rt_nodes->rn_key = new; | |
467 | } else { | |
468 | new = rt->rt_nodes->rn_key; | |
469 | old = 0; | |
470 | } | |
471 | Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); | |
472 | if (old) { | |
473 | Bcopy(dst, new, dlen); | |
474 | Free(old); | |
475 | } | |
476 | if (rt->rt_gwroute) { | |
477 | rt = rt->rt_gwroute; RTFREE(rt); | |
478 | rt = rt0; rt->rt_gwroute = 0; | |
479 | } | |
480 | if (rt->rt_flags & RTF_GATEWAY) { | |
481 | rt->rt_gwroute = rtalloc1(gate, 1); | |
482 | } | |
483 | return 0; | |
484 | } | |
485 | ||
044f6a7f KS |
486 | rt_maskedcopy(src, dst, netmask) |
487 | struct sockaddr *src, *dst, *netmask; | |
488 | { | |
be74b489 KS |
489 | register u_char *cp1 = (u_char *)src; |
490 | register u_char *cp2 = (u_char *)dst; | |
491 | register u_char *cp3 = (u_char *)netmask; | |
492 | u_char *cplim = cp2 + *cp3; | |
493 | u_char *cplim2 = cp2 + *cp1; | |
044f6a7f KS |
494 | |
495 | *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ | |
be74b489 KS |
496 | cp3 += 2; |
497 | if (cplim > cplim2) | |
498 | cplim = cplim2; | |
499 | while (cp2 < cplim) | |
044f6a7f | 500 | *cp2++ = *cp1++ & *cp3++; |
be74b489 KS |
501 | if (cp2 < cplim2) |
502 | bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); | |
044f6a7f | 503 | } |
f6311fb6 SL |
504 | /* |
505 | * Set up a routing table entry, normally | |
506 | * for an interface. | |
507 | */ | |
ea372425 MK |
508 | rtinit(ifa, cmd, flags) |
509 | register struct ifaddr *ifa; | |
2a63f7ba | 510 | int cmd, flags; |
f6311fb6 | 511 | { |
9bdb9951 KS |
512 | register struct rtentry *rt; |
513 | register struct sockaddr *dst; | |
514 | register struct sockaddr *deldst; | |
515 | struct mbuf *m = 0; | |
d93f9386 | 516 | struct rtentry *nrt = 0; |
9bdb9951 KS |
517 | int error; |
518 | ||
519 | dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; | |
9bdb9951 KS |
520 | if (cmd == RTM_DELETE) { |
521 | if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { | |
522 | m = m_get(M_WAIT, MT_SONAME); | |
523 | deldst = mtod(m, struct sockaddr *); | |
524 | rt_maskedcopy(dst, deldst, ifa->ifa_netmask); | |
525 | dst = deldst; | |
526 | } | |
527 | if (rt = rtalloc1(dst, 0)) { | |
528 | rt->rt_refcnt--; | |
529 | if (rt->rt_ifa != ifa) { | |
530 | if (m) | |
531 | (void) m_free(m); | |
532 | return (flags & RTF_HOST ? EHOSTUNREACH | |
533 | : ENETUNREACH); | |
534 | } | |
535 | } | |
536 | } | |
537 | error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, | |
d93f9386 | 538 | flags | ifa->ifa_flags, &nrt); |
9bdb9951 KS |
539 | if (m) |
540 | (void) m_free(m); | |
d93f9386 | 541 | if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { |
9e2e06fb KS |
542 | rt_newaddrmsg(cmd, ifa, error, nrt); |
543 | if (rt->rt_refcnt <= 0) { | |
544 | rt->rt_refcnt++; | |
d93f9386 | 545 | rtfree(rt); |
9e2e06fb | 546 | } |
d93f9386 KS |
547 | } |
548 | if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { | |
d93f9386 | 549 | rt->rt_refcnt--; |
9e2e06fb KS |
550 | if (rt->rt_ifa != ifa) { |
551 | printf("rtinit: wrong ifa (%x) was (%x)\n", ifa, | |
552 | rt->rt_ifa); | |
553 | if (rt->rt_ifa->ifa_rtrequest) | |
554 | rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); | |
555 | IFAFREE(rt->rt_ifa); | |
556 | rt->rt_ifa = ifa; | |
557 | rt->rt_ifp = ifa->ifa_ifp; | |
558 | ifa->ifa_refcnt++; | |
559 | if (ifa->ifa_rtrequest) | |
560 | ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); | |
561 | } | |
562 | rt_newaddrmsg(cmd, ifa, error, nrt); | |
9bdb9951 KS |
563 | } |
564 | return (error); | |
f6311fb6 | 565 | } |