- Implement EnumServicesStatusW.
[reactos.git] / reactos / drivers / lib / oskittcp / oskittcp / route.c
1 /*
2 * Copyright (c) 1980, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)route.c 8.2 (Berkeley) 11/15/93
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/proc.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/domain.h>
44 #include <sys/protosw.h>
45 #include <sys/ioctl.h>
46
47 #include <net/if.h>
48 #include <net/route.h>
49 #include <net/raw_cb.h>
50
51 #include <netinet/in.h>
52 #include <netinet/in_var.h>
53 #ifndef __REACTOS__
54 #include <netinet/ip_mroute.h>
55 #endif
56 #include <oskittcp.h>
57
58 #define SA(p) ((struct sockaddr *)(p))
59
60 int rttrash; /* routes not in table but not freed */
61 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
62
63 void
64 rtable_init(table)
65 void **table;
66 {
67 struct domain *dom;
68 for (dom = domains; dom; dom = dom->dom_next)
69 if (dom->dom_rtattach)
70 dom->dom_rtattach(&table[dom->dom_family],
71 dom->dom_rtoffset);
72 }
73
74 void
75 route_init()
76 {
77 rn_init(); /* initialize all zeroes, all ones, mask table */
78 rtable_init((void **)rt_tables);
79 }
80
81 /*
82 * Packet routing routines.
83 */
84 void
85 rtalloc(ro)
86 register struct route *ro;
87 {
88 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
89 return; /* XXX */
90 ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL);
91 }
92
93 void
94 rtalloc_ign(ro, ignore)
95 register struct route *ro;
96 u_long ignore;
97 {
98 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
99 return; /* XXX */
100 ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore);
101 }
102
103 struct rtentry *
104 rtalloc1(dst, report, ignflags)
105 register struct sockaddr *dst;
106 int report;
107 u_long ignflags;
108 {
109 register struct radix_node_head *rnh = rt_tables[dst->sa_family];
110 register struct rtentry *rt;
111 register struct radix_node *rn;
112 struct rtentry *newrt = 0;
113 struct rt_addrinfo info;
114 u_long nflags;
115 int s = splnet(), err = 0, msgtype = RTM_MISS;
116
117 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
118 ((rn->rn_flags & RNF_ROOT) == 0)) {
119 newrt = rt = (struct rtentry *)rn;
120 nflags = rt->rt_flags & ~ignflags;
121 if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) {
122 err = rtrequest(RTM_RESOLVE, dst, SA(0),
123 SA(0), 0, &newrt);
124 if (err) {
125 newrt = rt;
126 rt->rt_refcnt++;
127 goto miss;
128 }
129 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
130 msgtype = RTM_RESOLVE;
131 goto miss;
132 }
133 } else
134 rt->rt_refcnt++;
135 } else {
136 rtstat.rts_unreach++;
137 miss: if (report) {
138 bzero((caddr_t)&info, sizeof(info));
139 info.rti_info[RTAX_DST] = dst;
140 rt_missmsg(msgtype, &info, 0, err);
141 }
142 }
143 splx(s);
144 return (newrt);
145 }
146
147 void
148 rtfree(rt)
149 register struct rtentry *rt;
150 {
151 register struct radix_node_head *rnh =
152 rt_tables[rt_key(rt)->sa_family];
153 register struct ifaddr *ifa;
154
155 if (rt == 0 || rnh == 0)
156 panic("rtfree");
157 rt->rt_refcnt--;
158 if(rnh->rnh_close && rt->rt_refcnt == 0) {
159 rnh->rnh_close((struct radix_node *)rt, rnh);
160 }
161 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
162 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
163 panic ("rtfree 2");
164 rttrash--;
165 if (rt->rt_refcnt < 0) {
166 printf("rtfree: %p not freed (neg refs)\n", rt);
167 return;
168 }
169 ifa = rt->rt_ifa;
170 IFAFREE(ifa);
171 if (rt->rt_parent) {
172 RTFREE(rt->rt_parent);
173 }
174 Free(rt_key(rt));
175 Free(rt);
176 }
177 }
178
179 void
180 ifafree(ifa)
181 register struct ifaddr *ifa;
182 {
183 if (ifa == NULL)
184 panic("ifafree");
185 if (ifa->ifa_refcnt == 0)
186 free(ifa, M_IFADDR);
187 else
188 ifa->ifa_refcnt--;
189 }
190
191 /*
192 * Force a routing table entry to the specified
193 * destination to go through the given gateway.
194 * Normally called as a result of a routing redirect
195 * message from the network layer.
196 *
197 * N.B.: must be called at splnet
198 *
199 */
200 void
201 rtredirect(dst, gateway, netmask, flags, src, rtp)
202 struct sockaddr *dst, *gateway, *netmask, *src;
203 int flags;
204 struct rtentry **rtp;
205 {
206 register struct rtentry *rt;
207 int error = 0;
208 short *stat = 0;
209 struct rt_addrinfo info;
210 struct ifaddr *ifa;
211
212 /* verify the gateway is directly reachable */
213 if ((ifa = ifa_ifwithnet(gateway)) == 0) {
214 error = ENETUNREACH;
215 goto out;
216 }
217 rt = rtalloc1(dst, 0, 0UL);
218 /*
219 * If the redirect isn't from our current router for this dst,
220 * it's either old or wrong. If it redirects us to ourselves,
221 * we have a routing loop, perhaps as a result of an interface
222 * going down recently.
223 */
224 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
225 if (!(flags & RTF_DONE) && rt &&
226 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
227 error = EINVAL;
228 else if (ifa_ifwithaddr(gateway)) {
229 OS_DbgPrint(OSK_MID_TRACE,("EHOSTUNREACH\n"));
230 error = EHOSTUNREACH;
231 }
232 if (error)
233 goto done;
234 /*
235 * Create a new entry if we just got back a wildcard entry
236 * or the the lookup failed. This is necessary for hosts
237 * which use routing redirects generated by smart gateways
238 * to dynamically build the routing tables.
239 */
240 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
241 goto create;
242 /*
243 * Don't listen to the redirect if it's
244 * for a route to an interface.
245 */
246 if (rt->rt_flags & RTF_GATEWAY) {
247 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
248 /*
249 * Changing from route to net => route to host.
250 * Create new route, rather than smashing route to net.
251 */
252 create:
253 flags |= RTF_GATEWAY | RTF_DYNAMIC;
254 error = rtrequest((int)RTM_ADD, dst, gateway,
255 netmask, flags,
256 (struct rtentry **)0);
257 stat = &rtstat.rts_dynamic;
258 } else {
259 /*
260 * Smash the current notion of the gateway to
261 * this destination. Should check about netmask!!!
262 */
263 rt->rt_flags |= RTF_MODIFIED;
264 flags |= RTF_MODIFIED;
265 stat = &rtstat.rts_newgateway;
266 rt_setgate(rt, rt_key(rt), gateway);
267 }
268 } else {
269 OS_DbgPrint(OSK_MID_TRACE,("EHOSTUNREACH\n"));
270 error = EHOSTUNREACH;
271 }
272 done:
273 if (rt) {
274 if (rtp && !error)
275 *rtp = rt;
276 else
277 rtfree(rt);
278 }
279 out:
280 if (error)
281 rtstat.rts_badredirect++;
282 else if (stat != NULL)
283 (*stat)++;
284 bzero((caddr_t)&info, sizeof(info));
285 info.rti_info[RTAX_DST] = dst;
286 info.rti_info[RTAX_GATEWAY] = gateway;
287 info.rti_info[RTAX_NETMASK] = netmask;
288 info.rti_info[RTAX_AUTHOR] = src;
289 rt_missmsg(RTM_REDIRECT, &info, flags, error);
290 }
291
292 /*
293 * Routing table ioctl interface.
294 */
295 int
296 rtioctl(req, data, p)
297 int req;
298 caddr_t data;
299 struct proc *p;
300 {
301 #ifdef INET
302 /* Multicast goop, grrr... */
303 return mrt_ioctl(req, data, p);
304 #else /* INET */
305 return ENXIO;
306 #endif /* INET */
307 }
308
309 struct ifaddr *
310 ifa_ifwithroute(flags, dst, gateway)
311 int flags;
312 struct sockaddr *dst, *gateway;
313 {
314 register struct ifaddr *ifa;
315
316 OS_DbgPrint(OSK_MID_TRACE,("Called: flags %\n", flags));
317 OskitDumpBuffer( (void *)dst, sizeof(*dst) );
318 OskitDumpBuffer( (void *)gateway, sizeof(*gateway) );
319
320 if ((flags & RTF_GATEWAY) == 0) {
321 /*
322 * If we are adding a route to an interface,
323 * and the interface is a pt to pt link
324 * we should search for the destination
325 * as our clue to the interface. Otherwise
326 * we can use the local address.
327 */
328 ifa = 0;
329 if (flags & RTF_HOST) {
330 ifa = ifa_ifwithdstaddr(dst);
331 }
332 if (ifa == 0)
333 ifa = ifa_ifwithaddr(gateway);
334 } else {
335 /*
336 * If we are adding a route to a remote net
337 * or host, the gateway may still be on the
338 * other end of a pt to pt link.
339 */
340 ifa = ifa_ifwithdstaddr(gateway);
341 }
342 if (ifa == 0)
343 ifa = ifa_ifwithnet(gateway);
344 if (ifa == 0) {
345 struct rtentry *rt = rtalloc1(dst, 0, 0UL);
346 if (rt == 0)
347 return (0);
348 rt->rt_refcnt--;
349 if ((ifa = rt->rt_ifa) == 0)
350 return (0);
351 }
352 #ifndef __REACTOS__
353 if (ifa->ifa_addr->sa_family != dst->sa_family) {
354 struct ifaddr *oifa = ifa;
355 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
356 if (ifa == 0)
357 ifa = oifa;
358 }
359 #endif
360
361 OS_DbgPrint(OSK_MID_TRACE,("Leaving: %x\n"));
362
363 return (ifa);
364 }
365
366 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
367
368 #ifndef __REACTOS__
369 static int rt_fixdelete(struct radix_node *, void *);
370 #endif
371 static int rt_fixchange(struct radix_node *, void *);
372
373 struct rtfc_arg {
374 struct rtentry *rt0;
375 struct radix_node_head *rnh;
376 };
377
378 int
379 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
380 int req, flags;
381 struct sockaddr *dst, *gateway, *netmask;
382 struct rtentry **ret_nrt;
383 {
384 int s = splnet(); int error = 0;
385 register struct rtentry *rt;
386 register struct radix_node *rn;
387 register struct radix_node_head *rnh;
388 struct ifaddr *ifa;
389 struct sockaddr *ndst;
390 #ifndef __REACTOS__
391 u_long prflags = 0UL;
392 #endif
393 #define senderr(x) { error = x ; goto bad; }
394
395 if ((rnh = rt_tables[dst->sa_family]) == 0)
396 senderr(ESRCH);
397 if (flags & RTF_HOST)
398 netmask = 0;
399 switch (req) {
400 #ifndef __REACTOS__
401 case RTM_DELETE:
402 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
403 senderr(ESRCH);
404 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
405 panic ("rtrequest delete");
406 rt = (struct rtentry *)rn;
407
408 /*
409 * Now search what's left of the subtree for any cloned
410 * routes which might have been formed from this node.
411 */
412 if ((rt->rt_flags & RTF_PRCLONING) && netmask) {
413 rnh->rnh_walktree_from(rnh, dst, netmask,
414 rt_fixdelete, rt);
415 }
416
417 if (rt->rt_gwroute) {
418 rt = rt->rt_gwroute; RTFREE(rt);
419 (rt = (struct rtentry *)rn)->rt_gwroute = 0;
420 }
421
422 /*
423 * NB: RTF_UP must be set during the search above,
424 * because we might delete the last ref, causing
425 * rt to get freed prematurely.
426 */
427 rt->rt_flags &= ~RTF_UP;
428
429 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
430 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
431 rttrash++;
432 if (ret_nrt)
433 *ret_nrt = rt;
434 else if (rt->rt_refcnt <= 0) {
435 rt->rt_refcnt++;
436 rtfree(rt);
437 }
438 break;
439 #endif
440
441 case RTM_RESOLVE:
442 if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
443 senderr(EINVAL);
444 ifa = rt->rt_ifa;
445 flags = rt->rt_flags &
446 ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC);
447 flags |= RTF_WASCLONED;
448 gateway = rt->rt_gateway;
449 if ((netmask = rt->rt_genmask) == 0)
450 flags |= RTF_HOST;
451 goto makeroute;
452
453 #ifndef __REACTOS__
454 case RTM_ADD:
455 if ((flags & RTF_GATEWAY) && !gateway)
456 panic("rtrequest: GATEWAY but no gateway");
457
458 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
459 senderr(ENETUNREACH);
460 #endif
461
462 makeroute:
463 R_Malloc(rt, struct rtentry *, sizeof(*rt));
464 if (rt == 0)
465 senderr(ENOBUFS);
466 Bzero(rt, sizeof(*rt));
467 rt->rt_flags = RTF_UP | flags;
468 if (rt_setgate(rt, dst, gateway)) {
469 Free(rt);
470 senderr(ENOBUFS);
471 }
472 ndst = rt_key(rt);
473 if (netmask) {
474 rt_maskedcopy(dst, ndst, netmask);
475 } else
476 Bcopy(dst, ndst, dst->sa_len);
477
478 /*
479 * This moved from below so that rnh->rnh_addaddr() can
480 * examine the ifa and ifp if it so desires.
481 */
482 ifa->ifa_refcnt++;
483 rt->rt_ifa = ifa;
484 #ifndef __REACTOS__
485 rt->rt_ifp = ifa->ifa_ifp;
486 #endif
487
488 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
489 rnh, rt->rt_nodes);
490 if (rn == 0) {
491 struct rtentry *rt2;
492 /*
493 * Uh-oh, we already have one of these in the tree.
494 * We do a special hack: if the route that's already
495 * there was generated by the protocol-cloning
496 * mechanism, then we just blow it away and retry
497 * the insertion of the new one.
498 */
499 rt2 = rtalloc1(dst, 0, RTF_PRCLONING);
500 if (rt2 && rt2->rt_parent) {
501 rtrequest(RTM_DELETE,
502 (struct sockaddr *)rt_key(rt2),
503 rt2->rt_gateway,
504 rt_mask(rt2), rt2->rt_flags, 0);
505 RTFREE(rt2);
506 rn = rnh->rnh_addaddr((caddr_t)ndst,
507 (caddr_t)netmask,
508 rnh, rt->rt_nodes);
509 } else if (rt2) {
510 RTFREE(rt2);
511 }
512 }
513
514 if (rn == 0) {
515 if (rt->rt_gwroute)
516 rtfree(rt->rt_gwroute);
517 if (rt->rt_ifa) {
518 IFAFREE(rt->rt_ifa);
519 }
520 Free(rt_key(rt));
521 Free(rt);
522 senderr(EEXIST);
523 }
524 rt->rt_parent = 0;
525
526 if (req == RTM_RESOLVE) {
527 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
528 if ((*ret_nrt)->rt_flags & RTF_PRCLONING) {
529 rt->rt_parent = (*ret_nrt);
530 (*ret_nrt)->rt_refcnt++;
531 }
532 }
533 #ifndef __REACTOS__
534 if (ifa->ifa_rtrequest)
535 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
536 #endif
537 /*
538 * We repeat the same procedure from rt_setgate() here because
539 * it doesn't fire when we call it there because the node
540 * hasn't been added to the tree yet.
541 */
542 if (!(rt->rt_flags & RTF_HOST)) {
543 struct rtfc_arg arg;
544 arg.rnh = rnh;
545 arg.rt0 = rt;
546 rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
547 rt_fixchange, &arg);
548 }
549
550 if (ret_nrt) {
551 *ret_nrt = rt;
552 rt->rt_refcnt++;
553 }
554 break;
555 }
556 bad:
557 splx(s);
558 return (error);
559 }
560
561 /*
562 * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family''
563 * (i.e., the routes related to it by the operation of cloning). This
564 * routine is iterated over all potential former-child-routes by way of
565 * rnh->rnh_walktree_from() above, and those that actually are children of
566 * the late parent (passed in as VP here) are themselves deleted.
567 */
568 #ifndef __REACTOS__
569 static int
570 rt_fixdelete(struct radix_node *rn, void *vp)
571 {
572 struct rtentry *rt = (struct rtentry *)rn;
573 struct rtentry *rt0 = vp;
574
575 if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) {
576 return rtrequest(RTM_DELETE, rt_key(rt),
577 (struct sockaddr *)0, rt_mask(rt),
578 rt->rt_flags, (struct rtentry **)0);
579 }
580 return 0;
581 }
582 #endif
583
584 /*
585 * This routine is called from rt_setgate() to do the analogous thing for
586 * adds and changes. There is the added complication in this case of a
587 * middle insert; i.e., insertion of a new network route between an older
588 * network route and (cloned) host routes. For this reason, a simple check
589 * of rt->rt_parent is insufficient; each candidate route must be tested
590 * against the (mask, value) of the new route (passed as before in vp)
591 * to see if the new route matches it. Unfortunately, this has the obnoxious
592 * property of also triggering for insertion /above/ a pre-existing network
593 * route and clones. Sigh. This may be fixed some day.
594 *
595 * XXX - it may be possible to do fixdelete() for changes and reserve this
596 * routine just for adds. I'm not sure why I thought it was necessary to do
597 * changes this way.
598 */
599 #ifdef DEBUG
600 int rtfcdebug = 0;
601 #endif
602
603 static int
604 rt_fixchange(struct radix_node *rn, void *vp)
605 {
606 struct rtentry *rt = (struct rtentry *)rn;
607 struct rtfc_arg *ap = vp;
608 struct rtentry *rt0 = ap->rt0;
609 struct radix_node_head *rnh = ap->rnh;
610 u_char *xk1, *xm1, *xk2;
611 int i, len;
612
613 #ifdef DEBUG
614 if (rtfcdebug)
615 printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
616 #endif
617
618 if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
619 #ifdef DEBUG
620 if(rtfcdebug) printf("no parent or pinned\n");
621 #endif
622 return 0;
623 }
624
625 if (rt->rt_parent == rt0) {
626 #ifdef DEBUG
627 if(rtfcdebug) printf("parent match\n");
628 #endif
629 return rtrequest(RTM_DELETE, rt_key(rt),
630 (struct sockaddr *)0, rt_mask(rt),
631 rt->rt_flags, (struct rtentry **)0);
632 }
633
634 /*
635 * There probably is a function somewhere which does this...
636 * if not, there should be.
637 */
638 len = imin(((struct sockaddr *)rt_key(rt0))->sa_len,
639 ((struct sockaddr *)rt_key(rt))->sa_len);
640
641 xk1 = (u_char *)rt_key(rt0);
642 xm1 = (u_char *)rt_mask(rt0);
643 xk2 = (u_char *)rt_key(rt);
644
645 for (i = rnh->rnh_treetop->rn_off; i < len; i++) {
646 if ((xk2[i] & xm1[i]) != xk1[i]) {
647 #ifdef DEBUG
648 if(rtfcdebug) printf("no match\n");
649 #endif
650 return 0;
651 }
652 }
653
654 /*
655 * OK, this node is a clone, and matches the node currently being
656 * changed/added under the node's mask. So, get rid of it.
657 */
658 #ifdef DEBUG
659 if(rtfcdebug) printf("deleting\n");
660 #endif
661 return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
662 rt_mask(rt), rt->rt_flags, (struct rtentry **)0);
663 }
664
665 int
666 rt_setgate(rt0, dst, gate)
667 struct rtentry *rt0;
668 struct sockaddr *dst, *gate;
669 {
670 caddr_t new, old;
671 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
672 register struct rtentry *rt = rt0;
673 struct radix_node_head *rnh = rt_tables[dst->sa_family];
674
675 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
676 old = (caddr_t)rt_key(rt);
677 R_Malloc(new, caddr_t, dlen + glen);
678 if (new == 0)
679 return 1;
680 rt->rt_nodes->rn_key = new;
681 } else {
682 new = rt->rt_nodes->rn_key;
683 old = 0;
684 }
685 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
686 if (old) {
687 Bcopy(dst, new, dlen);
688 Free(old);
689 }
690 if (rt->rt_gwroute) {
691 rt = rt->rt_gwroute; RTFREE(rt);
692 rt = rt0; rt->rt_gwroute = 0;
693 }
694 /*
695 * Cloning loop avoidance:
696 * In the presence of protocol-cloning and bad configuration,
697 * it is possible to get stuck in bottomless mutual recursion
698 * (rtrequest rt_setgate rtalloc1). We avoid this by not allowing
699 * protocol-cloning to operate for gateways (which is probably the
700 * correct choice anyway), and avoid the resulting reference loops
701 * by disallowing any route to run through itself as a gateway.
702 * This is obviuosly mandatory when we get rt->rt_output().
703 */
704 if (rt->rt_flags & RTF_GATEWAY) {
705 rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING);
706 if (rt->rt_gwroute == rt) {
707 RTFREE(rt->rt_gwroute);
708 rt->rt_gwroute = 0;
709 return 1; /* failure */
710 }
711 }
712
713 /*
714 * This isn't going to do anything useful for host routes, so
715 * don't bother. Also make sure we have a reasonable mask
716 * (we don't yet have one during adds).
717 */
718 if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
719 struct rtfc_arg arg;
720 arg.rnh = rnh;
721 arg.rt0 = rt;
722 rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
723 rt_fixchange, &arg);
724 }
725
726 return 0;
727 }
728
729 void
730 rt_maskedcopy(src, dst, netmask)
731 struct sockaddr *src, *dst, *netmask;
732 {
733 register u_char *cp1 = (u_char *)src;
734 register u_char *cp2 = (u_char *)dst;
735 register u_char *cp3 = (u_char *)netmask;
736 u_char *cplim = cp2 + *cp3;
737 u_char *cplim2 = cp2 + *cp1;
738
739 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
740 cp3 += 2;
741 if (cplim > cplim2)
742 cplim = cplim2;
743 while (cp2 < cplim)
744 *cp2++ = *cp1++ & *cp3++;
745 if (cp2 < cplim2)
746 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
747 }
748
749 /*
750 * Set up a routing table entry, normally
751 * for an interface.
752 */
753 int
754 rtinit(ifa, cmd, flags)
755 register struct ifaddr *ifa;
756 int cmd, flags;
757 {
758 int error = EADDRNOTAVAIL;
759 #ifndef __REACTOS__
760 register struct rtentry *rt;
761 register struct sockaddr *dst;
762 register struct sockaddr *deldst;
763 struct mbuf *m = 0;
764 struct rtentry *nrt = 0;
765
766 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
767 if (cmd == RTM_DELETE) {
768 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
769 m = m_get(M_WAIT, MT_SONAME);
770 deldst = mtod(m, struct sockaddr *);
771 rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
772 dst = deldst;
773 }
774 rt = rtalloc1(dst, 0, 0UL);
775 if (rt) {
776 rt->rt_refcnt--;
777 if (rt->rt_ifa != ifa) {
778 if (m)
779 (void) m_free(m);
780 return (flags & RTF_HOST ? EHOSTUNREACH
781 : ENETUNREACH);
782 }
783 }
784 }
785 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
786 flags | ifa->ifa_flags, &nrt);
787 if (m)
788 (void) m_free(m);
789 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
790 rt_newaddrmsg(cmd, ifa, error, nrt);
791 if (rt->rt_refcnt <= 0) {
792 rt->rt_refcnt++;
793 rtfree(rt);
794 }
795 }
796 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
797 rt->rt_refcnt--;
798 if (rt->rt_ifa != ifa) {
799 printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
800 rt->rt_ifa);
801 if (rt->rt_ifa->ifa_rtrequest)
802 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
803 IFAFREE(rt->rt_ifa);
804 rt->rt_ifa = ifa;
805 rt->rt_ifp = ifa->ifa_ifp;
806 ifa->ifa_refcnt++;
807 if (ifa->ifa_rtrequest)
808 ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
809 }
810 rt_newaddrmsg(cmd, ifa, error, nrt);
811 }
812 #endif
813 return (error);
814 }