add/re-enable at_wini debug output
[minix3.git] / servers / inet / generic / ipr.c
blobf9137caef381cea5b0d04aa3adcfb311ad4aca6d
1 /*
2 ipr.c
4 Copyright 1995 Philip Homburg
5 */
7 #include "inet.h"
8 #include "clock.h"
10 #include "type.h"
11 #include "assert.h"
12 #include "buf.h"
13 #include "event.h"
14 #include "io.h"
15 #include "ip_int.h"
16 #include "ipr.h"
18 THIS_FILE
20 #define OROUTE_NR 128
21 #define OROUTE_STATIC_NR 16
22 #define OROUTE_HASH_ASS_NR 4
23 #define OROUTE_HASH_NR 32
24 #define OROUTE_HASH_MASK (OROUTE_HASH_NR-1)
26 #define hash_oroute(port_nr, ipaddr, hash_tmp) (hash_tmp= (ipaddr), \
27 hash_tmp= (hash_tmp >> 20) ^ hash_tmp, \
28 hash_tmp= (hash_tmp >> 10) ^ hash_tmp, \
29 hash_tmp= (hash_tmp >> 5) ^ hash_tmp, \
30 (hash_tmp + (port_nr)) & OROUTE_HASH_MASK)
32 typedef struct oroute_hash
34 ipaddr_t orh_addr;
35 oroute_t *orh_route;
36 } oroute_hash_t;
38 PRIVATE oroute_t oroute_table[OROUTE_NR];
39 PRIVATE oroute_t *oroute_head;
40 PRIVATE int static_oroute_nr;
41 PRIVATE oroute_hash_t oroute_hash_table[OROUTE_HASH_NR][OROUTE_HASH_ASS_NR];
43 #define IROUTE_NR 512
44 #define IROUTE_HASH_ASS_NR 4
45 #define IROUTE_HASH_NR 32
46 #define IROUTE_HASH_MASK (IROUTE_HASH_NR-1)
48 #define hash_iroute(port_nr, ipaddr, hash_tmp) (hash_tmp= (ipaddr), \
49 hash_tmp= (hash_tmp >> 20) ^ hash_tmp, \
50 hash_tmp= (hash_tmp >> 10) ^ hash_tmp, \
51 hash_tmp= (hash_tmp >> 5) ^ hash_tmp, \
52 (hash_tmp + (port_nr)) & IROUTE_HASH_MASK)
54 typedef struct iroute_hash
56 ipaddr_t irh_addr;
57 iroute_t *irh_route;
58 } iroute_hash_t;
60 PRIVATE iroute_t iroute_table[IROUTE_NR];
61 PRIVATE iroute_hash_t iroute_hash_table[IROUTE_HASH_NR][IROUTE_HASH_ASS_NR];
63 FORWARD oroute_t *oroute_find_ent ARGS(( int port_nr, ipaddr_t dest ));
64 FORWARD void oroute_del ARGS(( oroute_t *oroute ));
65 FORWARD oroute_t *sort_dists ARGS(( oroute_t *oroute ));
66 FORWARD oroute_t *sort_gws ARGS(( oroute_t *oroute ));
67 FORWARD void oroute_uncache_nw ARGS(( ipaddr_t dest, ipaddr_t netmask ));
68 FORWARD void iroute_uncache_nw ARGS(( ipaddr_t dest, ipaddr_t netmask ));
70 PUBLIC void ipr_init()
72 int i;
73 oroute_t *oroute;
74 iroute_t *iroute;
76 for (i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
77 oroute->ort_flags= ORTF_EMPTY;
78 static_oroute_nr= 0;
79 assert(OROUTE_HASH_ASS_NR == 4);
81 for (i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
82 iroute->irt_flags= IRTF_EMPTY;
83 assert(IROUTE_HASH_ASS_NR == 4);
87 PUBLIC iroute_t *iroute_frag(port_nr, dest)
88 int port_nr;
89 ipaddr_t dest;
91 int hash, i;
92 iroute_hash_t *iroute_hash;
93 iroute_hash_t tmp_hash;
94 iroute_t *iroute, *bestroute;
95 unsigned long hash_tmp;
96 u32_t tmp_mask;
98 hash= hash_iroute(port_nr, dest, hash_tmp);
99 iroute_hash= &iroute_hash_table[hash][0];
100 if (iroute_hash[0].irh_addr == dest)
101 iroute= iroute_hash[0].irh_route;
102 else if (iroute_hash[1].irh_addr == dest)
104 tmp_hash= iroute_hash[1];
105 iroute_hash[1]= iroute_hash[0];
106 iroute_hash[0]= tmp_hash;
107 iroute= tmp_hash.irh_route;
109 else if (iroute_hash[2].irh_addr == dest)
111 tmp_hash= iroute_hash[2];
112 iroute_hash[2]= iroute_hash[1];
113 iroute_hash[1]= iroute_hash[0];
114 iroute_hash[0]= tmp_hash;
115 iroute= tmp_hash.irh_route;
117 else if (iroute_hash[3].irh_addr == dest)
119 tmp_hash= iroute_hash[3];
120 iroute_hash[3]= iroute_hash[2];
121 iroute_hash[2]= iroute_hash[1];
122 iroute_hash[1]= iroute_hash[0];
123 iroute_hash[0]= tmp_hash;
124 iroute= tmp_hash.irh_route;
126 else
127 iroute= NULL;
128 if (iroute)
129 return iroute;
131 bestroute= NULL;
132 for (i= 0, iroute= iroute_table; i < IROUTE_NR; i++, iroute++)
134 if (!(iroute->irt_flags & IRTF_INUSE))
135 continue;
136 if (((dest ^ iroute->irt_dest) & iroute->irt_subnetmask) != 0)
137 continue;
138 if (!bestroute)
140 bestroute= iroute;
141 continue;
144 /* More specific netmasks are better */
145 if (iroute->irt_subnetmask != bestroute->irt_subnetmask)
147 /* Using two ntohl macros in one expression
148 * is not allowed (tmp_l is modified twice)
150 tmp_mask= ntohl(iroute->irt_subnetmask);
151 if (tmp_mask > ntohl(bestroute->irt_subnetmask))
152 bestroute= iroute;
153 continue;
156 /* Dynamic routes override static routes */
157 if ((iroute->irt_flags & IRTF_STATIC) !=
158 (bestroute->irt_flags & IRTF_STATIC))
160 if (bestroute->irt_flags & IRTF_STATIC)
161 bestroute= iroute;
162 continue;
165 /* A route to the local interface give an opportunity
166 * to send redirects.
168 if (iroute->irt_port != bestroute->irt_port)
170 if (iroute->irt_port == port_nr)
171 bestroute= iroute;
172 continue;
175 if (bestroute == NULL)
176 return NULL;
178 iroute_hash[3]= iroute_hash[2];
179 iroute_hash[2]= iroute_hash[1];
180 iroute_hash[1]= iroute_hash[0];
181 iroute_hash[0].irh_addr= dest;
182 iroute_hash[0].irh_route= bestroute;
184 return bestroute;
187 PUBLIC int oroute_frag(port_nr, dest, ttl, msgsize, nexthop)
188 int port_nr;
189 ipaddr_t dest;
190 int ttl;
191 size_t msgsize;
192 ipaddr_t *nexthop;
194 oroute_t *oroute;
196 oroute= oroute_find_ent(port_nr, dest);
197 if (!oroute || oroute->ort_dist > ttl)
198 return EDSTNOTRCH;
199 if (msgsize && oroute->ort_mtu &&
200 oroute->ort_mtu < msgsize)
202 return EPACKSIZE;
205 *nexthop= oroute->ort_gateway;
206 return NW_OK;
210 PUBLIC int ipr_add_oroute(port_nr, dest, subnetmask, gateway,
211 timeout, dist, mtu, static_route, preference, oroute_p)
212 int port_nr;
213 ipaddr_t dest;
214 ipaddr_t subnetmask;
215 ipaddr_t gateway;
216 time_t timeout;
217 int dist;
218 int mtu;
219 int static_route;
220 i32_t preference;
221 oroute_t **oroute_p;
223 int i;
224 ip_port_t *ip_port;
225 oroute_t *oroute, *oldest_route, *prev, *nw_route, *gw_route,
226 *prev_route;
227 time_t currtim, exp_tim, exp_tim_orig;
229 oldest_route= 0;
230 currtim= get_time();
231 if (timeout)
232 exp_tim= timeout+currtim;
233 else
234 exp_tim= 0;
236 DBLOCK(0x10,
237 printf("ip[%d]: adding oroute to ", port_nr);
238 writeIpAddr(dest);
239 printf("["); writeIpAddr(subnetmask); printf("] through ");
240 writeIpAddr(gateway);
241 printf(" timeout: %lds, distance %d, pref %ld, mtu %d\n",
242 (long)timeout/HZ, dist, (long)preference, mtu));
244 ip_port= &ip_port_table[port_nr];
246 /* Validate gateway */
247 if (((gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) != 0)
249 DBLOCK(1, printf("ip[%d]: (ipr_add_oroute) invalid gateway: ",
250 port_nr); writeIpAddr(gateway); printf("\n"));
251 return EINVAL;
254 if (static_route)
256 if (static_oroute_nr >= OROUTE_STATIC_NR)
257 return ENOMEM;
258 static_oroute_nr++;
260 else
262 /* Try to track down any old routes. */
263 for(oroute= oroute_head; oroute; oroute= oroute->ort_nextnw)
265 if (oroute->ort_port != port_nr)
266 continue;
267 if (oroute->ort_dest == dest &&
268 oroute->ort_subnetmask == subnetmask)
270 break;
273 for(; oroute; oroute= oroute->ort_nextgw)
275 if (oroute->ort_gateway == gateway)
276 break;
278 for(; oroute; oroute= oroute->ort_nextdist)
280 if ((oroute->ort_flags & ORTF_STATIC) != 0)
281 continue;
282 if (oroute->ort_dist > dist)
283 continue;
284 break;
286 if (oroute)
288 assert(oroute->ort_port == port_nr);
289 if (dest != 0)
291 /* The new expire should not be later
292 * than the old expire time. Except for
293 * default routes, where the expire time
294 * is simple set to the new value.
296 exp_tim_orig= oroute->ort_exp_tim;
297 if (!exp_tim)
298 exp_tim= exp_tim_orig;
299 else if (exp_tim_orig &&
300 exp_tim > exp_tim_orig)
302 exp_tim= exp_tim_orig;
305 oroute_del(oroute);
306 oroute->ort_flags= 0;
307 oldest_route= oroute;
311 if (oldest_route == NULL)
313 /* Look for an unused entry, or remove an existing one */
314 for (i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
316 if ((oroute->ort_flags & ORTF_INUSE) == 0)
317 break;
318 if (oroute->ort_exp_tim && oroute->ort_exp_tim <
319 currtim)
321 oroute_del(oroute);
322 oroute->ort_flags= 0;
323 break;
325 if (oroute->ort_flags & ORTF_STATIC)
326 continue;
327 if (oroute->ort_dest == 0)
329 /* Never remove default routes. */
330 continue;
332 if (oldest_route == NULL)
334 oldest_route= oroute;
335 continue;
337 if (oroute->ort_timestamp < oldest_route->ort_timestamp)
339 oldest_route= oroute;
342 if (i < OROUTE_NR)
343 oldest_route= oroute;
344 else
346 assert(oldest_route);
347 oroute_del(oldest_route);
348 oldest_route->ort_flags= 0;
352 oldest_route->ort_dest= dest;
353 oldest_route->ort_gateway= gateway;
354 oldest_route->ort_subnetmask= subnetmask;
355 oldest_route->ort_exp_tim= exp_tim;
356 oldest_route->ort_timestamp= currtim;
357 oldest_route->ort_dist= dist;
358 oldest_route->ort_mtu= mtu;
359 oldest_route->ort_port= port_nr;
360 oldest_route->ort_flags= ORTF_INUSE;
361 oldest_route->ort_pref= preference;
362 if (static_route)
363 oldest_route->ort_flags |= ORTF_STATIC;
365 /* Insert the route by tearing apart the routing table,
366 * and insert the entry during the reconstruction.
368 for (prev= 0, nw_route= oroute_head; nw_route;
369 prev= nw_route, nw_route= nw_route->ort_nextnw)
371 if (nw_route->ort_port != port_nr)
372 continue;
373 if (nw_route->ort_dest == dest &&
374 nw_route->ort_subnetmask == subnetmask)
376 if (prev)
377 prev->ort_nextnw= nw_route->ort_nextnw;
378 else
379 oroute_head= nw_route->ort_nextnw;
380 break;
383 prev_route= nw_route;
384 for(prev= NULL, gw_route= nw_route; gw_route;
385 prev= gw_route, gw_route= gw_route->ort_nextgw)
387 if (gw_route->ort_gateway == gateway)
389 if (prev)
390 prev->ort_nextgw= gw_route->ort_nextgw;
391 else
392 nw_route= gw_route->ort_nextgw;
393 break;
396 oldest_route->ort_nextdist= gw_route;
397 gw_route= oldest_route;
398 gw_route= sort_dists(gw_route);
399 gw_route->ort_nextgw= nw_route;
400 nw_route= gw_route;
401 nw_route= sort_gws(nw_route);
402 nw_route->ort_nextnw= oroute_head;
403 oroute_head= nw_route;
404 if (nw_route != prev_route)
405 oroute_uncache_nw(nw_route->ort_dest, nw_route->ort_subnetmask);
406 if (oroute_p != NULL)
407 *oroute_p= oldest_route;
408 return NW_OK;
411 PUBLIC int ipr_del_oroute(port_nr, dest, subnetmask, gateway, static_route)
412 int port_nr;
413 ipaddr_t dest;
414 ipaddr_t subnetmask;
415 ipaddr_t gateway;
416 int static_route;
418 int i;
419 oroute_t *oroute;
421 for(i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
423 if ((oroute->ort_flags & ORTF_INUSE) == 0)
424 continue;
425 if (oroute->ort_port != port_nr ||
426 oroute->ort_dest != dest ||
427 oroute->ort_subnetmask != subnetmask ||
428 oroute->ort_gateway != gateway)
430 continue;
432 if (!!(oroute->ort_flags & ORTF_STATIC) != static_route)
433 continue;
434 break;
437 if (i == OROUTE_NR)
438 return ESRCH;
440 if (static_route)
441 static_oroute_nr--;
443 oroute_del(oroute);
444 oroute->ort_flags &= ~ORTF_INUSE;
445 return NW_OK;
450 PUBLIC void ipr_chk_otab(port_nr, addr, mask)
451 int port_nr;
452 ipaddr_t addr;
453 ipaddr_t mask;
455 int i;
456 oroute_t *oroute;
458 DBLOCK(1,
459 printf("ip[%d] (ipr_chk_otab): addr ", port_nr);
460 writeIpAddr(addr);
461 printf(" mask ");
462 writeIpAddr(mask);
463 printf("\n");
466 if (addr == 0)
468 /* Special hack to flush entries for an interface that
469 * goes down.
471 addr= mask= HTONL(0xffffffff);
474 for(i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
476 if ((oroute->ort_flags & ORTF_INUSE) == 0)
477 continue;
478 if (oroute->ort_port != port_nr ||
479 ((oroute->ort_gateway ^ addr) & mask) == 0)
481 continue;
483 DBLOCK(1, printf("ip[%d] (ipr_chk_otab): deleting route to ",
484 port_nr);
485 writeIpAddr(oroute->ort_dest);
486 printf(" gw ");
487 writeIpAddr(oroute->ort_gateway);
488 printf("\n"));
490 if (oroute->ort_flags & ORTF_STATIC)
491 static_oroute_nr--;
492 oroute_del(oroute);
493 oroute->ort_flags &= ~ORTF_INUSE;
498 PUBLIC void ipr_gateway_down(port_nr, gateway, timeout)
499 int port_nr;
500 ipaddr_t gateway;
501 time_t timeout;
503 oroute_t *route_ind;
504 time_t currtim;
505 int i;
506 int result;
508 currtim= get_time();
509 for (i= 0, route_ind= oroute_table; i<OROUTE_NR; i++, route_ind++)
511 if (!(route_ind->ort_flags & ORTF_INUSE))
512 continue;
513 if (route_ind->ort_gateway != gateway)
514 continue;
515 if (route_ind->ort_exp_tim && route_ind->ort_exp_tim < currtim)
516 continue;
517 result= ipr_add_oroute(port_nr, route_ind->ort_dest,
518 route_ind->ort_subnetmask, gateway,
519 timeout, ORTD_UNREACHABLE, route_ind->ort_mtu,
520 FALSE, 0, NULL);
521 assert(result == NW_OK);
526 PUBLIC void ipr_destunrch(port_nr, dest, netmask, timeout)
527 int port_nr;
528 ipaddr_t dest;
529 ipaddr_t netmask;
530 time_t timeout;
532 oroute_t *oroute;
533 int result;
535 oroute= oroute_find_ent(port_nr, dest);
537 if (!oroute)
539 DBLOCK(1, printf("ip[%d]: got a dest unreachable for ",
540 port_nr);
541 writeIpAddr(dest); printf("but no route present\n"));
543 return;
545 result= ipr_add_oroute(port_nr, dest, netmask, oroute->ort_gateway,
546 timeout, ORTD_UNREACHABLE, oroute->ort_mtu, FALSE, 0, NULL);
547 assert(result == NW_OK);
551 PUBLIC void ipr_redirect(port_nr, dest, netmask, old_gateway, new_gateway,
552 timeout)
553 int port_nr;
554 ipaddr_t dest;
555 ipaddr_t netmask;
556 ipaddr_t old_gateway;
557 ipaddr_t new_gateway;
558 time_t timeout;
560 oroute_t *oroute;
561 ip_port_t *ip_port;
562 int result;
564 ip_port= &ip_port_table[port_nr];
565 oroute= oroute_find_ent(port_nr, dest);
567 if (!oroute)
569 DBLOCK(1, printf("ip[%d]: got a redirect for ", port_nr);
570 writeIpAddr(dest); printf("but no route present\n"));
571 return;
573 if (oroute->ort_gateway != old_gateway)
575 DBLOCK(1, printf("ip[%d]: got a redirect from ", port_nr);
576 writeIpAddr(old_gateway); printf(" for ");
577 writeIpAddr(dest); printf(" but curr gateway is ");
578 writeIpAddr(oroute->ort_gateway); printf("\n"));
579 return;
581 if ((new_gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask)
583 DBLOCK(1, printf("ip[%d]: redirect from ", port_nr);
584 writeIpAddr(old_gateway); printf(" for ");
585 writeIpAddr(dest); printf(" but new gateway ");
586 writeIpAddr(new_gateway);
587 printf(" is not on local subnet\n"));
588 return;
590 if (oroute->ort_flags & ORTF_STATIC)
592 if (oroute->ort_dest == dest)
594 DBLOCK(1, printf("ip[%d]: got a redirect for ",
595 port_nr);
596 writeIpAddr(dest);
597 printf("but route is fixed\n"));
598 return;
601 else
603 result= ipr_add_oroute(port_nr, dest, netmask,
604 oroute->ort_gateway, HZ, ORTD_UNREACHABLE,
605 oroute->ort_mtu, FALSE, 0, NULL);
606 assert(result == NW_OK);
608 result= ipr_add_oroute(port_nr, dest, netmask, new_gateway,
609 timeout, 1, oroute->ort_mtu, FALSE, 0, NULL);
610 assert(result == NW_OK);
614 PUBLIC void ipr_ttl_exc(port_nr, dest, netmask, timeout)
615 int port_nr;
616 ipaddr_t dest;
617 ipaddr_t netmask;
618 time_t timeout;
620 oroute_t *oroute;
621 int new_dist;
622 int result;
624 oroute= oroute_find_ent(port_nr, dest);
626 if (!oroute)
628 DBLOCK(1, printf("ip[%d]: got a ttl exceeded for ",
629 port_nr);
630 writeIpAddr(dest); printf("but no route present\n"));
631 return;
634 new_dist= oroute->ort_dist * 2;
635 if (new_dist > IP_DEF_TTL)
637 new_dist= oroute->ort_dist+1;
638 if (new_dist >= IP_DEF_TTL)
640 DBLOCK(1, printf("ip[%d]: got a ttl exceeded for ",
641 port_nr);
642 writeIpAddr(dest);
643 printf(" but dist is %d\n",
644 oroute->ort_dist));
645 return;
649 result= ipr_add_oroute(port_nr, dest, netmask, oroute->ort_gateway,
650 timeout, new_dist, oroute->ort_mtu, FALSE, 0, NULL);
651 assert(result == NW_OK);
654 PUBLIC void ipr_mtu(port_nr, dest, mtu, timeout)
655 int port_nr;
656 ipaddr_t dest;
657 u16_t mtu;
658 time_t timeout;
660 oroute_t *oroute;
661 int result;
663 oroute= oroute_find_ent(port_nr, dest);
665 if (!oroute)
667 DBLOCK(1, printf("ip[%d]: got a mtu exceeded for ",
668 port_nr);
669 writeIpAddr(dest); printf("but no route present\n"));
670 return;
673 if (mtu < IP_MIN_MTU)
674 return;
675 if (oroute->ort_mtu && mtu >= oroute->ort_mtu)
676 return; /* Only decrease mtu */
678 result= ipr_add_oroute(port_nr, dest, HTONL(0xffffffff),
679 oroute->ort_gateway, timeout, oroute->ort_dist, mtu,
680 FALSE, 0, NULL);
681 assert(result == NW_OK);
685 PUBLIC int ipr_get_oroute(ent_no, route_ent)
686 int ent_no;
687 nwio_route_t *route_ent;
689 oroute_t *oroute;
691 if (ent_no<0 || ent_no>= OROUTE_NR)
692 return ENOENT;
694 oroute= &oroute_table[ent_no];
695 if ((oroute->ort_flags & ORTF_INUSE) && oroute->ort_exp_tim &&
696 oroute->ort_exp_tim < get_time())
698 oroute_del(oroute);
699 oroute->ort_flags &= ~ORTF_INUSE;
702 route_ent->nwr_ent_no= ent_no;
703 route_ent->nwr_ent_count= OROUTE_NR;
704 route_ent->nwr_dest= oroute->ort_dest;
705 route_ent->nwr_netmask= oroute->ort_subnetmask;
706 route_ent->nwr_gateway= oroute->ort_gateway;
707 route_ent->nwr_dist= oroute->ort_dist;
708 route_ent->nwr_flags= NWRF_EMPTY;
709 if (oroute->ort_flags & ORTF_INUSE)
711 route_ent->nwr_flags |= NWRF_INUSE;
712 if (oroute->ort_flags & ORTF_STATIC)
713 route_ent->nwr_flags |= NWRF_STATIC;
715 route_ent->nwr_pref= oroute->ort_pref;
716 route_ent->nwr_mtu= oroute->ort_mtu;
717 route_ent->nwr_ifaddr= ip_get_ifaddr(oroute->ort_port);
718 return NW_OK;
722 PRIVATE oroute_t *oroute_find_ent(port_nr, dest)
723 int port_nr;
724 ipaddr_t dest;
726 int hash;
727 oroute_hash_t *oroute_hash;
728 oroute_hash_t tmp_hash;
729 oroute_t *oroute, *bestroute;
730 time_t currtim;
731 unsigned long hash_tmp;
732 u32_t tmp_mask;
734 currtim= get_time();
736 hash= hash_oroute(port_nr, dest, hash_tmp);
737 oroute_hash= &oroute_hash_table[hash][0];
738 if (oroute_hash[0].orh_addr == dest)
739 oroute= oroute_hash[0].orh_route;
740 else if (oroute_hash[1].orh_addr == dest)
742 tmp_hash= oroute_hash[1];
743 oroute_hash[1]= oroute_hash[0];
744 oroute_hash[0]= tmp_hash;
745 oroute= tmp_hash.orh_route;
747 else if (oroute_hash[2].orh_addr == dest)
749 tmp_hash= oroute_hash[2];
750 oroute_hash[2]= oroute_hash[1];
751 oroute_hash[1]= oroute_hash[0];
752 oroute_hash[0]= tmp_hash;
753 oroute= tmp_hash.orh_route;
755 else if (oroute_hash[3].orh_addr == dest)
757 tmp_hash= oroute_hash[3];
758 oroute_hash[3]= oroute_hash[2];
759 oroute_hash[2]= oroute_hash[1];
760 oroute_hash[1]= oroute_hash[0];
761 oroute_hash[0]= tmp_hash;
762 oroute= tmp_hash.orh_route;
764 else
765 oroute= NULL;
766 if (oroute)
768 assert(oroute->ort_port == port_nr);
769 if (oroute->ort_exp_tim && oroute->ort_exp_tim<currtim)
771 oroute_del(oroute);
772 oroute->ort_flags &= ~ORTF_INUSE;
774 else
775 return oroute;
778 bestroute= NULL;
779 for (oroute= oroute_head; oroute; oroute= oroute->ort_nextnw)
781 if (((dest ^ oroute->ort_dest) & oroute->ort_subnetmask) != 0)
782 continue;
783 if (oroute->ort_port != port_nr)
784 continue;
785 if (!bestroute)
787 bestroute= oroute;
788 continue;
790 assert(oroute->ort_dest != bestroute->ort_dest);
791 /* Using two ntohl macros in one expression
792 * is not allowed (tmp_l is modified twice)
794 tmp_mask= ntohl(oroute->ort_subnetmask);
795 if (tmp_mask > ntohl(bestroute->ort_subnetmask))
797 bestroute= oroute;
798 continue;
801 if (bestroute == NULL)
802 return NULL;
804 oroute_hash[3]= oroute_hash[2];
805 oroute_hash[2]= oroute_hash[1];
806 oroute_hash[1]= oroute_hash[0];
807 oroute_hash[0].orh_addr= dest;
808 oroute_hash[0].orh_route= bestroute;
810 return bestroute;
814 PRIVATE void oroute_del(oroute)
815 oroute_t *oroute;
817 oroute_t *prev, *nw_route, *gw_route, *dist_route, *prev_route;
819 DBLOCK(0x10,
820 printf("ip[%d]: deleting oroute to ", oroute->ort_port);
821 writeIpAddr(oroute->ort_dest);
822 printf("["); writeIpAddr(oroute->ort_subnetmask);
823 printf("] through ");
824 writeIpAddr(oroute->ort_gateway);
825 printf(
826 " timestamp %lds, timeout: %lds, distance %d pref %ld mtu %ld ",
827 (long)oroute->ort_timestamp/HZ,
828 (long)oroute->ort_exp_tim/HZ, oroute->ort_dist,
829 (long)oroute->ort_pref, (long)oroute->ort_mtu);
830 printf("flags 0x%x\n", oroute->ort_flags));
832 for (prev= NULL, nw_route= oroute_head; nw_route;
833 prev= nw_route, nw_route= nw_route->ort_nextnw)
835 if (oroute->ort_port == nw_route->ort_port &&
836 oroute->ort_dest == nw_route->ort_dest &&
837 oroute->ort_subnetmask == nw_route->ort_subnetmask)
839 break;
842 assert(nw_route);
843 if (prev)
844 prev->ort_nextnw= nw_route->ort_nextnw;
845 else
846 oroute_head= nw_route->ort_nextnw;
847 prev_route= nw_route;
848 for (prev= NULL, gw_route= nw_route; gw_route;
849 prev= gw_route, gw_route= gw_route->ort_nextgw)
851 if (oroute->ort_gateway == gw_route->ort_gateway)
852 break;
854 assert(gw_route);
855 if (prev)
856 prev->ort_nextgw= gw_route->ort_nextgw;
857 else
858 nw_route= gw_route->ort_nextgw;
859 for (prev= NULL, dist_route= gw_route; dist_route;
860 prev= dist_route, dist_route= dist_route->ort_nextdist)
862 if (oroute == dist_route)
863 break;
865 assert(dist_route);
866 if (prev)
867 prev->ort_nextdist= dist_route->ort_nextdist;
868 else
869 gw_route= dist_route->ort_nextdist;
870 gw_route= sort_dists(gw_route);
871 if (gw_route != NULL)
873 gw_route->ort_nextgw= nw_route;
874 nw_route= gw_route;
876 nw_route= sort_gws(nw_route);
877 if (nw_route != NULL)
879 nw_route->ort_nextnw= oroute_head;
880 oroute_head= nw_route;
882 if (nw_route != prev_route)
884 oroute_uncache_nw(prev_route->ort_dest,
885 prev_route->ort_subnetmask);
890 PRIVATE oroute_t *sort_dists(oroute)
891 oroute_t *oroute;
893 oroute_t *r, *prev, *best, *best_prev;
894 int best_dist, best_pref;
896 best= NULL;
897 best_dist= best_pref= 0;
898 best_prev= NULL;
899 for (prev= NULL, r= oroute; r; prev= r, r= r->ort_nextdist)
901 if (best == NULL)
902 ; /* Force assignment to best */
903 else if (r->ort_dist != best_dist)
905 if (r->ort_dist > best_dist)
906 continue;
908 else
910 if (r->ort_pref <= best_pref)
911 continue;
913 best= r;
914 best_prev= prev;
915 best_dist= r->ort_dist;
916 best_pref= r->ort_pref;
918 if (!best)
920 assert(oroute == NULL);
921 return oroute;
923 if (!best_prev)
925 assert(best == oroute);
926 return oroute;
928 best_prev->ort_nextdist= best->ort_nextdist;
929 best->ort_nextdist= oroute;
930 return best;
934 PRIVATE oroute_t *sort_gws(oroute)
935 oroute_t *oroute;
937 oroute_t *r, *prev, *best, *best_prev;
938 int best_dist, best_pref;
940 best= NULL;
941 best_dist= best_pref= 0;
942 best_prev= NULL;
943 for (prev= NULL, r= oroute; r; prev= r, r= r->ort_nextgw)
945 if (best == NULL)
946 ; /* Force assignment to best */
947 else if (r->ort_dist != best_dist)
949 if (r->ort_dist > best_dist)
950 continue;
952 else
954 if (r->ort_pref <= best_pref)
955 continue;
957 best= r;
958 best_prev= prev;
959 best_dist= r->ort_dist;
960 best_pref= r->ort_pref;
962 if (!best)
964 assert(oroute == NULL);
965 return oroute;
967 if (!best_prev)
969 assert(best == oroute);
970 return oroute;
972 best_prev->ort_nextgw= best->ort_nextgw;
973 best->ort_nextgw= oroute;
974 return best;
978 PRIVATE void oroute_uncache_nw(dest, netmask)
979 ipaddr_t dest;
980 ipaddr_t netmask;
982 int i, j;
983 oroute_hash_t *oroute_hash;
985 for (i= 0, oroute_hash= &oroute_hash_table[0][0];
986 i<OROUTE_HASH_NR; i++, oroute_hash += OROUTE_HASH_ASS_NR)
988 for (j= 0; j<OROUTE_HASH_ASS_NR; j++)
990 if (((oroute_hash[j].orh_addr ^ dest) & netmask) == 0)
992 oroute_hash[j].orh_addr= 0;
993 oroute_hash[j].orh_route= NULL;
1001 * Input routing
1004 PUBLIC int ipr_get_iroute(ent_no, route_ent)
1005 int ent_no;
1006 nwio_route_t *route_ent;
1008 iroute_t *iroute;
1010 if (ent_no<0 || ent_no>= IROUTE_NR)
1011 return ENOENT;
1013 iroute= &iroute_table[ent_no];
1015 route_ent->nwr_ent_no= ent_no;
1016 route_ent->nwr_ent_count= IROUTE_NR;
1017 route_ent->nwr_dest= iroute->irt_dest;
1018 route_ent->nwr_netmask= iroute->irt_subnetmask;
1019 route_ent->nwr_gateway= iroute->irt_gateway;
1020 route_ent->nwr_dist= iroute->irt_dist;
1021 route_ent->nwr_flags= NWRF_EMPTY;
1022 if (iroute->irt_flags & IRTF_INUSE)
1024 route_ent->nwr_flags |= NWRF_INUSE;
1025 if (iroute->irt_flags & IRTF_STATIC)
1026 route_ent->nwr_flags |= NWRF_STATIC;
1027 if (iroute->irt_dist == IRTD_UNREACHABLE)
1028 route_ent->nwr_flags |= NWRF_UNREACHABLE;
1030 route_ent->nwr_pref= 0;
1031 route_ent->nwr_mtu= iroute->irt_mtu;
1032 route_ent->nwr_ifaddr= ip_get_ifaddr(iroute->irt_port);
1033 return NW_OK;
1037 PUBLIC int ipr_add_iroute(port_nr, dest, subnetmask, gateway,
1038 dist, mtu, static_route, iroute_p)
1039 int port_nr;
1040 ipaddr_t dest;
1041 ipaddr_t subnetmask;
1042 ipaddr_t gateway;
1043 int dist;
1044 int mtu;
1045 int static_route;
1046 iroute_t **iroute_p;
1048 int i;
1049 iroute_t *iroute, *unused_route;
1050 ip_port_t *ip_port;
1052 ip_port= &ip_port_table[port_nr];
1054 /* Check gateway */
1055 if (((gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) != 0 &&
1056 gateway != 0)
1058 DBLOCK(1, printf("ip[%d] (ipr_add_iroute): invalid gateway: ",
1059 port_nr);
1060 writeIpAddr(gateway); printf("\n"));
1061 return EINVAL;
1064 unused_route= NULL;
1065 if (static_route)
1067 /* Static routes are not reused automatically, so we look
1068 * for an unused entry.
1070 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1072 if ((iroute->irt_flags & IRTF_INUSE) == 0)
1073 break;
1075 if (i != IROUTE_NR)
1076 unused_route= iroute;
1078 else
1080 /* Try to track down any old routes, and look for an
1081 * unused one.
1083 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1085 if ((iroute->irt_flags & IRTF_INUSE) == 0)
1087 unused_route= iroute;
1088 continue;
1090 if ((iroute->irt_flags & IRTF_STATIC) != 0)
1091 continue;
1092 if (iroute->irt_port != port_nr ||
1093 iroute->irt_dest != dest ||
1094 iroute->irt_subnetmask != subnetmask ||
1095 iroute->irt_gateway != gateway)
1097 continue;
1099 break;
1101 if (i != IROUTE_NR)
1102 unused_route= iroute;
1105 if (unused_route == NULL)
1106 return ENOMEM;
1107 iroute= unused_route;
1109 iroute->irt_port= port_nr;
1110 iroute->irt_dest= dest;
1111 iroute->irt_subnetmask= subnetmask;
1112 iroute->irt_gateway= gateway;
1113 iroute->irt_dist= dist;
1114 iroute->irt_mtu= mtu;
1115 iroute->irt_flags= IRTF_INUSE;
1116 if (static_route)
1117 iroute->irt_flags |= IRTF_STATIC;
1119 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
1120 if (iroute_p != NULL)
1121 *iroute_p= iroute;
1122 return NW_OK;
1126 PUBLIC int ipr_del_iroute(port_nr, dest, subnetmask, gateway, static_route)
1127 int port_nr;
1128 ipaddr_t dest;
1129 ipaddr_t subnetmask;
1130 ipaddr_t gateway;
1131 int static_route;
1133 int i;
1134 iroute_t *iroute;
1136 /* Try to track down any old routes, and look for an
1137 * unused one.
1139 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1141 if ((iroute->irt_flags & IRTF_INUSE) == 0)
1142 continue;
1143 if (iroute->irt_port != port_nr ||
1144 iroute->irt_dest != dest ||
1145 iroute->irt_subnetmask != subnetmask ||
1146 iroute->irt_gateway != gateway)
1148 continue;
1150 if (!!(iroute->irt_flags & IRTF_STATIC) != static_route)
1151 continue;
1152 break;
1155 if (i == IROUTE_NR)
1156 return ESRCH;
1158 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
1159 iroute->irt_flags= IRTF_EMPTY;
1160 return NW_OK;
1164 PUBLIC void ipr_chk_itab(port_nr, addr, mask)
1165 int port_nr;
1166 ipaddr_t addr;
1167 ipaddr_t mask;
1169 int i;
1170 iroute_t *iroute;
1172 DBLOCK(1,
1173 printf("ip[%d] (ipr_chk_itab): addr ", port_nr);
1174 writeIpAddr(addr);
1175 printf(" mask ");
1176 writeIpAddr(mask);
1177 printf("\n");
1180 if (addr == 0)
1182 /* Special hack to flush entries for an interface that
1183 * goes down.
1185 addr= mask= HTONL(0xffffffff);
1188 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1190 if ((iroute->irt_flags & IRTF_INUSE) == 0)
1191 continue;
1192 if (iroute->irt_port != port_nr)
1193 continue;
1194 if (iroute->irt_gateway == 0)
1196 /* Special case: attached network. */
1197 if (iroute->irt_subnetmask == mask &&
1198 iroute->irt_dest == (addr & mask))
1200 /* Nothing changed. */
1201 continue;
1204 if (((iroute->irt_gateway ^ addr) & mask) == 0)
1205 continue;
1207 DBLOCK(1, printf("ip[%d] (ipr_chk_itab): deleting route to ",
1208 port_nr);
1209 writeIpAddr(iroute->irt_dest);
1210 printf(" gw ");
1211 writeIpAddr(iroute->irt_gateway);
1212 printf("\n"));
1214 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
1215 iroute->irt_flags &= ~IRTF_INUSE;
1220 PRIVATE void iroute_uncache_nw(dest, netmask)
1221 ipaddr_t dest;
1222 ipaddr_t netmask;
1224 int i, j;
1225 iroute_hash_t *iroute_hash;
1227 for (i= 0, iroute_hash= &iroute_hash_table[0][0];
1228 i<IROUTE_HASH_NR; i++, iroute_hash += IROUTE_HASH_ASS_NR)
1230 for (j= 0; j<IROUTE_HASH_ASS_NR; j++)
1232 if (((iroute_hash[j].irh_addr ^ dest) &
1233 netmask) == 0)
1235 iroute_hash[j].irh_addr= 0;
1236 iroute_hash[j].irh_route= NULL;
1245 * $PchId: ipr.c,v 1.23 2003/01/22 11:49:58 philip Exp $