source: trunk/minix/servers/inet/generic/ipr.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 26.9 KB
Line 
1/*
2ipr.c
3
4Copyright 1995 Philip Homburg
5*/
6
7#include "inet.h"
8#include "clock.h"
9
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"
17
18THIS_FILE
19
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)
25
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)
31
32typedef struct oroute_hash
33{
34 ipaddr_t orh_addr;
35 oroute_t *orh_route;
36} oroute_hash_t;
37
38PRIVATE oroute_t oroute_table[OROUTE_NR];
39PRIVATE oroute_t *oroute_head;
40PRIVATE int static_oroute_nr;
41PRIVATE oroute_hash_t oroute_hash_table[OROUTE_HASH_NR][OROUTE_HASH_ASS_NR];
42
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)
47
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)
53
54typedef struct iroute_hash
55{
56 ipaddr_t irh_addr;
57 iroute_t *irh_route;
58} iroute_hash_t;
59
60PRIVATE iroute_t iroute_table[IROUTE_NR];
61PRIVATE iroute_hash_t iroute_hash_table[IROUTE_HASH_NR][IROUTE_HASH_ASS_NR];
62
63FORWARD oroute_t *oroute_find_ent ARGS(( int port_nr, ipaddr_t dest ));
64FORWARD void oroute_del ARGS(( oroute_t *oroute ));
65FORWARD oroute_t *sort_dists ARGS(( oroute_t *oroute ));
66FORWARD oroute_t *sort_gws ARGS(( oroute_t *oroute ));
67FORWARD void oroute_uncache_nw ARGS(( ipaddr_t dest, ipaddr_t netmask ));
68FORWARD void iroute_uncache_nw ARGS(( ipaddr_t dest, ipaddr_t netmask ));
69
70PUBLIC void ipr_init()
71{
72 int i;
73 oroute_t *oroute;
74 iroute_t *iroute;
75
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);
80
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);
84}
85
86
87PUBLIC iroute_t *iroute_frag(port_nr, dest)
88int port_nr;
89ipaddr_t dest;
90{
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;
97
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)
103 {
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;
108 }
109 else if (iroute_hash[2].irh_addr == dest)
110 {
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;
116 }
117 else if (iroute_hash[3].irh_addr == dest)
118 {
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;
125 }
126 else
127 iroute= NULL;
128 if (iroute)
129 return iroute;
130
131 bestroute= NULL;
132 for (i= 0, iroute= iroute_table; i < IROUTE_NR; i++, iroute++)
133 {
134 if (!(iroute->irt_flags & IRTF_INUSE))
135 continue;
136 if (((dest ^ iroute->irt_dest) & iroute->irt_subnetmask) != 0)
137 continue;
138 if (!bestroute)
139 {
140 bestroute= iroute;
141 continue;
142 }
143
144 /* More specific netmasks are better */
145 if (iroute->irt_subnetmask != bestroute->irt_subnetmask)
146 {
147 /* Using two ntohl macros in one expression
148 * is not allowed (tmp_l is modified twice)
149 */
150 tmp_mask= ntohl(iroute->irt_subnetmask);
151 if (tmp_mask > ntohl(bestroute->irt_subnetmask))
152 bestroute= iroute;
153 continue;
154 }
155
156 /* Dynamic routes override static routes */
157 if ((iroute->irt_flags & IRTF_STATIC) !=
158 (bestroute->irt_flags & IRTF_STATIC))
159 {
160 if (bestroute->irt_flags & IRTF_STATIC)
161 bestroute= iroute;
162 continue;
163 }
164
165 /* A route to the local interface give an opportunity
166 * to send redirects.
167 */
168 if (iroute->irt_port != bestroute->irt_port)
169 {
170 if (iroute->irt_port == port_nr)
171 bestroute= iroute;
172 continue;
173 }
174 }
175 if (bestroute == NULL)
176 return NULL;
177
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;
183
184 return bestroute;
185}
186
187PUBLIC int oroute_frag(port_nr, dest, ttl, msgsize, nexthop)
188int port_nr;
189ipaddr_t dest;
190int ttl;
191size_t msgsize;
192ipaddr_t *nexthop;
193{
194 oroute_t *oroute;
195
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)
201 {
202 return EPACKSIZE;
203 }
204
205 *nexthop= oroute->ort_gateway;
206 return NW_OK;
207}
208
209
210PUBLIC int ipr_add_oroute(port_nr, dest, subnetmask, gateway,
211 timeout, dist, mtu, static_route, preference, oroute_p)
212int port_nr;
213ipaddr_t dest;
214ipaddr_t subnetmask;
215ipaddr_t gateway;
216time_t timeout;
217int dist;
218int mtu;
219int static_route;
220i32_t preference;
221oroute_t **oroute_p;
222{
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;
228
229 oldest_route= 0;
230 currtim= get_time();
231 if (timeout)
232 exp_tim= timeout+currtim;
233 else
234 exp_tim= 0;
235
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));
243
244 ip_port= &ip_port_table[port_nr];
245
246 /* Validate gateway */
247 if (((gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) != 0)
248 {
249 DBLOCK(1, printf("ip[%d]: (ipr_add_oroute) invalid gateway: ",
250 port_nr); writeIpAddr(gateway); printf("\n"));
251 return EINVAL;
252 }
253
254 if (static_route)
255 {
256 if (static_oroute_nr >= OROUTE_STATIC_NR)
257 return ENOMEM;
258 static_oroute_nr++;
259 }
260 else
261 {
262 /* Try to track down any old routes. */
263 for(oroute= oroute_head; oroute; oroute= oroute->ort_nextnw)
264 {
265 if (oroute->ort_port != port_nr)
266 continue;
267 if (oroute->ort_dest == dest &&
268 oroute->ort_subnetmask == subnetmask)
269 {
270 break;
271 }
272 }
273 for(; oroute; oroute= oroute->ort_nextgw)
274 {
275 if (oroute->ort_gateway == gateway)
276 break;
277 }
278 for(; oroute; oroute= oroute->ort_nextdist)
279 {
280 if ((oroute->ort_flags & ORTF_STATIC) != 0)
281 continue;
282 if (oroute->ort_dist > dist)
283 continue;
284 break;
285 }
286 if (oroute)
287 {
288 assert(oroute->ort_port == port_nr);
289 if (dest != 0)
290 {
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.
295 */
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)
301 {
302 exp_tim= exp_tim_orig;
303 }
304 }
305 oroute_del(oroute);
306 oroute->ort_flags= 0;
307 oldest_route= oroute;
308 }
309 }
310
311 if (oldest_route == NULL)
312 {
313 /* Look for an unused entry, or remove an existing one */
314 for (i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
315 {
316 if ((oroute->ort_flags & ORTF_INUSE) == 0)
317 break;
318 if (oroute->ort_exp_tim && oroute->ort_exp_tim <
319 currtim)
320 {
321 oroute_del(oroute);
322 oroute->ort_flags= 0;
323 break;
324 }
325 if (oroute->ort_flags & ORTF_STATIC)
326 continue;
327 if (oroute->ort_dest == 0)
328 {
329 /* Never remove default routes. */
330 continue;
331 }
332 if (oldest_route == NULL)
333 {
334 oldest_route= oroute;
335 continue;
336 }
337 if (oroute->ort_timestamp < oldest_route->ort_timestamp)
338 {
339 oldest_route= oroute;
340 }
341 }
342 if (i < OROUTE_NR)
343 oldest_route= oroute;
344 else
345 {
346 assert(oldest_route);
347 oroute_del(oldest_route);
348 oldest_route->ort_flags= 0;
349 }
350 }
351
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;
364
365 /* Insert the route by tearing apart the routing table,
366 * and insert the entry during the reconstruction.
367 */
368 for (prev= 0, nw_route= oroute_head; nw_route;
369 prev= nw_route, nw_route= nw_route->ort_nextnw)
370 {
371 if (nw_route->ort_port != port_nr)
372 continue;
373 if (nw_route->ort_dest == dest &&
374 nw_route->ort_subnetmask == subnetmask)
375 {
376 if (prev)
377 prev->ort_nextnw= nw_route->ort_nextnw;
378 else
379 oroute_head= nw_route->ort_nextnw;
380 break;
381 }
382 }
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)
386 {
387 if (gw_route->ort_gateway == gateway)
388 {
389 if (prev)
390 prev->ort_nextgw= gw_route->ort_nextgw;
391 else
392 nw_route= gw_route->ort_nextgw;
393 break;
394 }
395 }
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;
409}
410
411PUBLIC int ipr_del_oroute(port_nr, dest, subnetmask, gateway, static_route)
412int port_nr;
413ipaddr_t dest;
414ipaddr_t subnetmask;
415ipaddr_t gateway;
416int static_route;
417{
418 int i;
419 oroute_t *oroute;
420
421 for(i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
422 {
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)
429 {
430 continue;
431 }
432 if (!!(oroute->ort_flags & ORTF_STATIC) != static_route)
433 continue;
434 break;
435 }
436
437 if (i == OROUTE_NR)
438 return ESRCH;
439
440 if (static_route)
441 static_oroute_nr--;
442
443 oroute_del(oroute);
444 oroute->ort_flags &= ~ORTF_INUSE;
445 return NW_OK;
446}
447
448
449
450PUBLIC void ipr_chk_otab(port_nr, addr, mask)
451int port_nr;
452ipaddr_t addr;
453ipaddr_t mask;
454{
455 int i;
456 oroute_t *oroute;
457
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");
464 );
465
466 if (addr == 0)
467 {
468 /* Special hack to flush entries for an interface that
469 * goes down.
470 */
471 addr= mask= HTONL(0xffffffff);
472 }
473
474 for(i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
475 {
476 if ((oroute->ort_flags & ORTF_INUSE) == 0)
477 continue;
478 if (oroute->ort_port != port_nr ||
479 ((oroute->ort_gateway ^ addr) & mask) == 0)
480 {
481 continue;
482 }
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"));
489
490 if (oroute->ort_flags & ORTF_STATIC)
491 static_oroute_nr--;
492 oroute_del(oroute);
493 oroute->ort_flags &= ~ORTF_INUSE;
494 }
495}
496
497
498PUBLIC void ipr_gateway_down(port_nr, gateway, timeout)
499int port_nr;
500ipaddr_t gateway;
501time_t timeout;
502{
503 oroute_t *route_ind;
504 time_t currtim;
505 int i;
506 int result;
507
508 currtim= get_time();
509 for (i= 0, route_ind= oroute_table; i<OROUTE_NR; i++, route_ind++)
510 {
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);
522 }
523}
524
525
526PUBLIC void ipr_destunrch(port_nr, dest, netmask, timeout)
527int port_nr;
528ipaddr_t dest;
529ipaddr_t netmask;
530time_t timeout;
531{
532 oroute_t *oroute;
533 int result;
534
535 oroute= oroute_find_ent(port_nr, dest);
536
537 if (!oroute)
538 {
539 DBLOCK(1, printf("ip[%d]: got a dest unreachable for ",
540 port_nr);
541 writeIpAddr(dest); printf("but no route present\n"));
542
543 return;
544 }
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);
548}
549
550
551PUBLIC void ipr_redirect(port_nr, dest, netmask, old_gateway, new_gateway,
552 timeout)
553int port_nr;
554ipaddr_t dest;
555ipaddr_t netmask;
556ipaddr_t old_gateway;
557ipaddr_t new_gateway;
558time_t timeout;
559{
560 oroute_t *oroute;
561 ip_port_t *ip_port;
562 int result;
563
564 ip_port= &ip_port_table[port_nr];
565 oroute= oroute_find_ent(port_nr, dest);
566
567 if (!oroute)
568 {
569 DBLOCK(1, printf("ip[%d]: got a redirect for ", port_nr);
570 writeIpAddr(dest); printf("but no route present\n"));
571 return;
572 }
573 if (oroute->ort_gateway != old_gateway)
574 {
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;
580 }
581 if ((new_gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask)
582 {
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;
589 }
590 if (oroute->ort_flags & ORTF_STATIC)
591 {
592 if (oroute->ort_dest == dest)
593 {
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;
599 }
600 }
601 else
602 {
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);
607 }
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);
611}
612
613
614PUBLIC void ipr_ttl_exc(port_nr, dest, netmask, timeout)
615int port_nr;
616ipaddr_t dest;
617ipaddr_t netmask;
618time_t timeout;
619{
620 oroute_t *oroute;
621 int new_dist;
622 int result;
623
624 oroute= oroute_find_ent(port_nr, dest);
625
626 if (!oroute)
627 {
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;
632 }
633
634 new_dist= oroute->ort_dist * 2;
635 if (new_dist > IP_DEF_TTL)
636 {
637 new_dist= oroute->ort_dist+1;
638 if (new_dist >= IP_DEF_TTL)
639 {
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;
646 }
647 }
648
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);
652}
653
654PUBLIC void ipr_mtu(port_nr, dest, mtu, timeout)
655int port_nr;
656ipaddr_t dest;
657u16_t mtu;
658time_t timeout;
659{
660 oroute_t *oroute;
661 int result;
662
663 oroute= oroute_find_ent(port_nr, dest);
664
665 if (!oroute)
666 {
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;
671 }
672
673 if (mtu < IP_MIN_MTU)
674 return;
675 if (oroute->ort_mtu && mtu >= oroute->ort_mtu)
676 return; /* Only decrease mtu */
677
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);
682}
683
684
685PUBLIC int ipr_get_oroute(ent_no, route_ent)
686int ent_no;
687nwio_route_t *route_ent;
688{
689 oroute_t *oroute;
690
691 if (ent_no<0 || ent_no>= OROUTE_NR)
692 return ENOENT;
693
694 oroute= &oroute_table[ent_no];
695 if ((oroute->ort_flags & ORTF_INUSE) && oroute->ort_exp_tim &&
696 oroute->ort_exp_tim < get_time())
697 {
698 oroute_del(oroute);
699 oroute->ort_flags &= ~ORTF_INUSE;
700 }
701
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)
710 {
711 route_ent->nwr_flags |= NWRF_INUSE;
712 if (oroute->ort_flags & ORTF_STATIC)
713 route_ent->nwr_flags |= NWRF_STATIC;
714 }
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;
719}
720
721
722PRIVATE oroute_t *oroute_find_ent(port_nr, dest)
723int port_nr;
724ipaddr_t dest;
725{
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;
733
734 currtim= get_time();
735
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)
741 {
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;
746 }
747 else if (oroute_hash[2].orh_addr == dest)
748 {
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;
754 }
755 else if (oroute_hash[3].orh_addr == dest)
756 {
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;
763 }
764 else
765 oroute= NULL;
766 if (oroute)
767 {
768 assert(oroute->ort_port == port_nr);
769 if (oroute->ort_exp_tim && oroute->ort_exp_tim<currtim)
770 {
771 oroute_del(oroute);
772 oroute->ort_flags &= ~ORTF_INUSE;
773 }
774 else
775 return oroute;
776 }
777
778 bestroute= NULL;
779 for (oroute= oroute_head; oroute; oroute= oroute->ort_nextnw)
780 {
781 if (((dest ^ oroute->ort_dest) & oroute->ort_subnetmask) != 0)
782 continue;
783 if (oroute->ort_port != port_nr)
784 continue;
785 if (!bestroute)
786 {
787 bestroute= oroute;
788 continue;
789 }
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)
793 */
794 tmp_mask= ntohl(oroute->ort_subnetmask);
795 if (tmp_mask > ntohl(bestroute->ort_subnetmask))
796 {
797 bestroute= oroute;
798 continue;
799 }
800 }
801 if (bestroute == NULL)
802 return NULL;
803
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;
809
810 return bestroute;
811}
812
813
814PRIVATE void oroute_del(oroute)
815oroute_t *oroute;
816{
817 oroute_t *prev, *nw_route, *gw_route, *dist_route, *prev_route;
818
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));
831
832 for (prev= NULL, nw_route= oroute_head; nw_route;
833 prev= nw_route, nw_route= nw_route->ort_nextnw)
834 {
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)
838 {
839 break;
840 }
841 }
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)
850 {
851 if (oroute->ort_gateway == gw_route->ort_gateway)
852 break;
853 }
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)
861 {
862 if (oroute == dist_route)
863 break;
864 }
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)
872 {
873 gw_route->ort_nextgw= nw_route;
874 nw_route= gw_route;
875 }
876 nw_route= sort_gws(nw_route);
877 if (nw_route != NULL)
878 {
879 nw_route->ort_nextnw= oroute_head;
880 oroute_head= nw_route;
881 }
882 if (nw_route != prev_route)
883 {
884 oroute_uncache_nw(prev_route->ort_dest,
885 prev_route->ort_subnetmask);
886 }
887}
888
889
890PRIVATE oroute_t *sort_dists(oroute)
891oroute_t *oroute;
892{
893 oroute_t *r, *prev, *best, *best_prev;
894 int best_dist, best_pref;
895
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)
900 {
901 if (best == NULL)
902 ; /* Force assignment to best */
903 else if (r->ort_dist != best_dist)
904 {
905 if (r->ort_dist > best_dist)
906 continue;
907 }
908 else
909 {
910 if (r->ort_pref <= best_pref)
911 continue;
912 }
913 best= r;
914 best_prev= prev;
915 best_dist= r->ort_dist;
916 best_pref= r->ort_pref;
917 }
918 if (!best)
919 {
920 assert(oroute == NULL);
921 return oroute;
922 }
923 if (!best_prev)
924 {
925 assert(best == oroute);
926 return oroute;
927 }
928 best_prev->ort_nextdist= best->ort_nextdist;
929 best->ort_nextdist= oroute;
930 return best;
931}
932
933
934PRIVATE oroute_t *sort_gws(oroute)
935oroute_t *oroute;
936{
937 oroute_t *r, *prev, *best, *best_prev;
938 int best_dist, best_pref;
939
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)
944 {
945 if (best == NULL)
946 ; /* Force assignment to best */
947 else if (r->ort_dist != best_dist)
948 {
949 if (r->ort_dist > best_dist)
950 continue;
951 }
952 else
953 {
954 if (r->ort_pref <= best_pref)
955 continue;
956 }
957 best= r;
958 best_prev= prev;
959 best_dist= r->ort_dist;
960 best_pref= r->ort_pref;
961 }
962 if (!best)
963 {
964 assert(oroute == NULL);
965 return oroute;
966 }
967 if (!best_prev)
968 {
969 assert(best == oroute);
970 return oroute;
971 }
972 best_prev->ort_nextgw= best->ort_nextgw;
973 best->ort_nextgw= oroute;
974 return best;
975}
976
977
978PRIVATE void oroute_uncache_nw(dest, netmask)
979ipaddr_t dest;
980ipaddr_t netmask;
981{
982 int i, j;
983 oroute_hash_t *oroute_hash;
984
985 for (i= 0, oroute_hash= &oroute_hash_table[0][0];
986 i<OROUTE_HASH_NR; i++, oroute_hash += OROUTE_HASH_ASS_NR)
987 {
988 for (j= 0; j<OROUTE_HASH_ASS_NR; j++)
989 {
990 if (((oroute_hash[j].orh_addr ^ dest) & netmask) == 0)
991 {
992 oroute_hash[j].orh_addr= 0;
993 oroute_hash[j].orh_route= NULL;
994 }
995 }
996 }
997}
998
999
1000/*
1001 * Input routing
1002 */
1003
1004PUBLIC int ipr_get_iroute(ent_no, route_ent)
1005int ent_no;
1006nwio_route_t *route_ent;
1007{
1008 iroute_t *iroute;
1009
1010 if (ent_no<0 || ent_no>= IROUTE_NR)
1011 return ENOENT;
1012
1013 iroute= &iroute_table[ent_no];
1014
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)
1023 {
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;
1029 }
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;
1034}
1035
1036
1037PUBLIC int ipr_add_iroute(port_nr, dest, subnetmask, gateway,
1038 dist, mtu, static_route, iroute_p)
1039int port_nr;
1040ipaddr_t dest;
1041ipaddr_t subnetmask;
1042ipaddr_t gateway;
1043int dist;
1044int mtu;
1045int static_route;
1046iroute_t **iroute_p;
1047{
1048 int i;
1049 iroute_t *iroute, *unused_route;
1050 ip_port_t *ip_port;
1051
1052 ip_port= &ip_port_table[port_nr];
1053
1054 /* Check gateway */
1055 if (((gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) != 0 &&
1056 gateway != 0)
1057 {
1058 DBLOCK(1, printf("ip[%d] (ipr_add_iroute): invalid gateway: ",
1059 port_nr);
1060 writeIpAddr(gateway); printf("\n"));
1061 return EINVAL;
1062 }
1063
1064 unused_route= NULL;
1065 if (static_route)
1066 {
1067 /* Static routes are not reused automatically, so we look
1068 * for an unused entry.
1069 */
1070 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1071 {
1072 if ((iroute->irt_flags & IRTF_INUSE) == 0)
1073 break;
1074 }
1075 if (i != IROUTE_NR)
1076 unused_route= iroute;
1077 }
1078 else
1079 {
1080 /* Try to track down any old routes, and look for an
1081 * unused one.
1082 */
1083 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1084 {
1085 if ((iroute->irt_flags & IRTF_INUSE) == 0)
1086 {
1087 unused_route= iroute;
1088 continue;
1089 }
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)
1096 {
1097 continue;
1098 }
1099 break;
1100 }
1101 if (i != IROUTE_NR)
1102 unused_route= iroute;
1103 }
1104
1105 if (unused_route == NULL)
1106 return ENOMEM;
1107 iroute= unused_route;
1108
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;
1118
1119 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
1120 if (iroute_p != NULL)
1121 *iroute_p= iroute;
1122 return NW_OK;
1123}
1124
1125
1126PUBLIC int ipr_del_iroute(port_nr, dest, subnetmask, gateway, static_route)
1127int port_nr;
1128ipaddr_t dest;
1129ipaddr_t subnetmask;
1130ipaddr_t gateway;
1131int static_route;
1132{
1133 int i;
1134 iroute_t *iroute;
1135
1136 /* Try to track down any old routes, and look for an
1137 * unused one.
1138 */
1139 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1140 {
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)
1147 {
1148 continue;
1149 }
1150 if (!!(iroute->irt_flags & IRTF_STATIC) != static_route)
1151 continue;
1152 break;
1153 }
1154
1155 if (i == IROUTE_NR)
1156 return ESRCH;
1157
1158 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
1159 iroute->irt_flags= IRTF_EMPTY;
1160 return NW_OK;
1161}
1162
1163
1164PUBLIC void ipr_chk_itab(port_nr, addr, mask)
1165int port_nr;
1166ipaddr_t addr;
1167ipaddr_t mask;
1168{
1169 int i;
1170 iroute_t *iroute;
1171
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");
1178 );
1179
1180 if (addr == 0)
1181 {
1182 /* Special hack to flush entries for an interface that
1183 * goes down.
1184 */
1185 addr= mask= HTONL(0xffffffff);
1186 }
1187
1188 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
1189 {
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)
1195 {
1196 /* Special case: attached network. */
1197 if (iroute->irt_subnetmask == mask &&
1198 iroute->irt_dest == (addr & mask))
1199 {
1200 /* Nothing changed. */
1201 continue;
1202 }
1203 }
1204 if (((iroute->irt_gateway ^ addr) & mask) == 0)
1205 continue;
1206
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"));
1213
1214 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
1215 iroute->irt_flags &= ~IRTF_INUSE;
1216 }
1217}
1218
1219
1220PRIVATE void iroute_uncache_nw(dest, netmask)
1221ipaddr_t dest;
1222ipaddr_t netmask;
1223{
1224 int i, j;
1225 iroute_hash_t *iroute_hash;
1226
1227 for (i= 0, iroute_hash= &iroute_hash_table[0][0];
1228 i<IROUTE_HASH_NR; i++, iroute_hash += IROUTE_HASH_ASS_NR)
1229 {
1230 for (j= 0; j<IROUTE_HASH_ASS_NR; j++)
1231 {
1232 if (((iroute_hash[j].irh_addr ^ dest) &
1233 netmask) == 0)
1234 {
1235 iroute_hash[j].irh_addr= 0;
1236 iroute_hash[j].irh_route= NULL;
1237 }
1238 }
1239 }
1240}
1241
1242
1243
1244/*
1245 * $PchId: ipr.c,v 1.23 2003/01/22 11:49:58 philip Exp $
1246 */
Note: See TracBrowser for help on using the repository browser.