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