00001
00002
00003
00004
00005
00006
00007 #include "inet.h"
00008 #include "clock.h"
00009
00010 #include "type.h"
00011 #include "assert.h"
00012 #include "buf.h"
00013 #include "event.h"
00014 #include "io.h"
00015 #include "ip_int.h"
00016 #include "ipr.h"
00017
00018 THIS_FILE
00019
00020 #define OROUTE_NR 128
00021 #define OROUTE_STATIC_NR 16
00022 #define OROUTE_HASH_ASS_NR 4
00023 #define OROUTE_HASH_NR 32
00024 #define OROUTE_HASH_MASK (OROUTE_HASH_NR-1)
00025
00026 #define hash_oroute(port_nr, ipaddr, hash_tmp) (hash_tmp= (ipaddr), \
00027 hash_tmp= (hash_tmp >> 20) ^ hash_tmp, \
00028 hash_tmp= (hash_tmp >> 10) ^ hash_tmp, \
00029 hash_tmp= (hash_tmp >> 5) ^ hash_tmp, \
00030 (hash_tmp + (port_nr)) & OROUTE_HASH_MASK)
00031
00032 typedef struct oroute_hash
00033 {
00034 ipaddr_t orh_addr;
00035 oroute_t *orh_route;
00036 } oroute_hash_t;
00037
00038 PRIVATE oroute_t oroute_table[OROUTE_NR];
00039 PRIVATE oroute_t *oroute_head;
00040 PRIVATE int static_oroute_nr;
00041 PRIVATE oroute_hash_t oroute_hash_table[OROUTE_HASH_NR][OROUTE_HASH_ASS_NR];
00042
00043 #define IROUTE_NR 512
00044 #define IROUTE_HASH_ASS_NR 4
00045 #define IROUTE_HASH_NR 32
00046 #define IROUTE_HASH_MASK (IROUTE_HASH_NR-1)
00047
00048 #define hash_iroute(port_nr, ipaddr, hash_tmp) (hash_tmp= (ipaddr), \
00049 hash_tmp= (hash_tmp >> 20) ^ hash_tmp, \
00050 hash_tmp= (hash_tmp >> 10) ^ hash_tmp, \
00051 hash_tmp= (hash_tmp >> 5) ^ hash_tmp, \
00052 (hash_tmp + (port_nr)) & IROUTE_HASH_MASK)
00053
00054 typedef struct iroute_hash
00055 {
00056 ipaddr_t irh_addr;
00057 iroute_t *irh_route;
00058 } iroute_hash_t;
00059
00060 PRIVATE iroute_t iroute_table[IROUTE_NR];
00061 PRIVATE iroute_hash_t iroute_hash_table[IROUTE_HASH_NR][IROUTE_HASH_ASS_NR];
00062
00063 FORWARD oroute_t *oroute_find_ent ARGS(( int port_nr, ipaddr_t dest ));
00064 FORWARD void oroute_del ARGS(( oroute_t *oroute ));
00065 FORWARD oroute_t *sort_dists ARGS(( oroute_t *oroute ));
00066 FORWARD oroute_t *sort_gws ARGS(( oroute_t *oroute ));
00067 FORWARD void oroute_uncache_nw ARGS(( ipaddr_t dest, ipaddr_t netmask ));
00068 FORWARD void iroute_uncache_nw ARGS(( ipaddr_t dest, ipaddr_t netmask ));
00069
00070 PUBLIC void ipr_init()
00071 {
00072 int i;
00073 oroute_t *oroute;
00074 iroute_t *iroute;
00075
00076 for (i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
00077 oroute->ort_flags= ORTF_EMPTY;
00078 static_oroute_nr= 0;
00079 assert(OROUTE_HASH_ASS_NR == 4);
00080
00081 for (i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
00082 iroute->irt_flags= IRTF_EMPTY;
00083 assert(IROUTE_HASH_ASS_NR == 4);
00084 }
00085
00086
00087 PUBLIC iroute_t *iroute_frag(port_nr, dest)
00088 int port_nr;
00089 ipaddr_t dest;
00090 {
00091 int hash, i;
00092 iroute_hash_t *iroute_hash;
00093 iroute_hash_t tmp_hash;
00094 iroute_t *iroute, *bestroute;
00095 unsigned long hash_tmp;
00096 u32_t tmp_mask;
00097
00098 hash= hash_iroute(port_nr, dest, hash_tmp);
00099 iroute_hash= &iroute_hash_table[hash][0];
00100 if (iroute_hash[0].irh_addr == dest)
00101 iroute= iroute_hash[0].irh_route;
00102 else if (iroute_hash[1].irh_addr == dest)
00103 {
00104 tmp_hash= iroute_hash[1];
00105 iroute_hash[1]= iroute_hash[0];
00106 iroute_hash[0]= tmp_hash;
00107 iroute= tmp_hash.irh_route;
00108 }
00109 else if (iroute_hash[2].irh_addr == dest)
00110 {
00111 tmp_hash= iroute_hash[2];
00112 iroute_hash[2]= iroute_hash[1];
00113 iroute_hash[1]= iroute_hash[0];
00114 iroute_hash[0]= tmp_hash;
00115 iroute= tmp_hash.irh_route;
00116 }
00117 else if (iroute_hash[3].irh_addr == dest)
00118 {
00119 tmp_hash= iroute_hash[3];
00120 iroute_hash[3]= iroute_hash[2];
00121 iroute_hash[2]= iroute_hash[1];
00122 iroute_hash[1]= iroute_hash[0];
00123 iroute_hash[0]= tmp_hash;
00124 iroute= tmp_hash.irh_route;
00125 }
00126 else
00127 iroute= NULL;
00128 if (iroute)
00129 return iroute;
00130
00131 bestroute= NULL;
00132 for (i= 0, iroute= iroute_table; i < IROUTE_NR; i++, iroute++)
00133 {
00134 if (!(iroute->irt_flags & IRTF_INUSE))
00135 continue;
00136 if (((dest ^ iroute->irt_dest) & iroute->irt_subnetmask) != 0)
00137 continue;
00138 if (!bestroute)
00139 {
00140 bestroute= iroute;
00141 continue;
00142 }
00143
00144
00145 if (iroute->irt_subnetmask != bestroute->irt_subnetmask)
00146 {
00147
00148
00149
00150 tmp_mask= ntohl(iroute->irt_subnetmask);
00151 if (tmp_mask > ntohl(bestroute->irt_subnetmask))
00152 bestroute= iroute;
00153 continue;
00154 }
00155
00156
00157 if ((iroute->irt_flags & IRTF_STATIC) !=
00158 (bestroute->irt_flags & IRTF_STATIC))
00159 {
00160 if (bestroute->irt_flags & IRTF_STATIC)
00161 bestroute= iroute;
00162 continue;
00163 }
00164
00165
00166
00167
00168 if (iroute->irt_port != bestroute->irt_port)
00169 {
00170 if (iroute->irt_port == port_nr)
00171 bestroute= iroute;
00172 continue;
00173 }
00174 }
00175 if (bestroute == NULL)
00176 return NULL;
00177
00178 iroute_hash[3]= iroute_hash[2];
00179 iroute_hash[2]= iroute_hash[1];
00180 iroute_hash[1]= iroute_hash[0];
00181 iroute_hash[0].irh_addr= dest;
00182 iroute_hash[0].irh_route= bestroute;
00183
00184 return bestroute;
00185 }
00186
00187 PUBLIC int oroute_frag(port_nr, dest, ttl, msgsize, nexthop)
00188 int port_nr;
00189 ipaddr_t dest;
00190 int ttl;
00191 size_t msgsize;
00192 ipaddr_t *nexthop;
00193 {
00194 oroute_t *oroute;
00195
00196 oroute= oroute_find_ent(port_nr, dest);
00197 if (!oroute || oroute->ort_dist > ttl)
00198 return EDSTNOTRCH;
00199 if (msgsize && oroute->ort_mtu &&
00200 oroute->ort_mtu < msgsize)
00201 {
00202 return EPACKSIZE;
00203 }
00204
00205 *nexthop= oroute->ort_gateway;
00206 return NW_OK;
00207 }
00208
00209
00210 PUBLIC int ipr_add_oroute(port_nr, dest, subnetmask, gateway,
00211 timeout, dist, mtu, static_route, preference, oroute_p)
00212 int port_nr;
00213 ipaddr_t dest;
00214 ipaddr_t subnetmask;
00215 ipaddr_t gateway;
00216 time_t timeout;
00217 int dist;
00218 int mtu;
00219 int static_route;
00220 i32_t preference;
00221 oroute_t **oroute_p;
00222 {
00223 int i;
00224 ip_port_t *ip_port;
00225 oroute_t *oroute, *oldest_route, *prev, *nw_route, *gw_route,
00226 *prev_route;
00227 time_t currtim, exp_tim, exp_tim_orig;
00228
00229 oldest_route= 0;
00230 currtim= get_time();
00231 if (timeout)
00232 exp_tim= timeout+currtim;
00233 else
00234 exp_tim= 0;
00235
00236 DBLOCK(0x10,
00237 printf("ip[%d]: adding oroute to ", port_nr);
00238 writeIpAddr(dest);
00239 printf("["); writeIpAddr(subnetmask); printf("] through ");
00240 writeIpAddr(gateway);
00241 printf(" timeout: %lds, distance %d, pref %ld, mtu %d\n",
00242 (long)timeout/HZ, dist, (long)preference, mtu));
00243
00244 ip_port= &ip_port_table[port_nr];
00245
00246
00247 if (((gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) != 0)
00248 {
00249 DBLOCK(1, printf("ip[%d]: (ipr_add_oroute) invalid gateway: ",
00250 port_nr); writeIpAddr(gateway); printf("\n"));
00251 return EINVAL;
00252 }
00253
00254 if (static_route)
00255 {
00256 if (static_oroute_nr >= OROUTE_STATIC_NR)
00257 return ENOMEM;
00258 static_oroute_nr++;
00259 }
00260 else
00261 {
00262
00263 for(oroute= oroute_head; oroute; oroute= oroute->ort_nextnw)
00264 {
00265 if (oroute->ort_port != port_nr)
00266 continue;
00267 if (oroute->ort_dest == dest &&
00268 oroute->ort_subnetmask == subnetmask)
00269 {
00270 break;
00271 }
00272 }
00273 for(; oroute; oroute= oroute->ort_nextgw)
00274 {
00275 if (oroute->ort_gateway == gateway)
00276 break;
00277 }
00278 for(; oroute; oroute= oroute->ort_nextdist)
00279 {
00280 if ((oroute->ort_flags & ORTF_STATIC) != 0)
00281 continue;
00282 if (oroute->ort_dist > dist)
00283 continue;
00284 break;
00285 }
00286 if (oroute)
00287 {
00288 assert(oroute->ort_port == port_nr);
00289 if (dest != 0)
00290 {
00291
00292
00293
00294
00295
00296 exp_tim_orig= oroute->ort_exp_tim;
00297 if (!exp_tim)
00298 exp_tim= exp_tim_orig;
00299 else if (exp_tim_orig &&
00300 exp_tim > exp_tim_orig)
00301 {
00302 exp_tim= exp_tim_orig;
00303 }
00304 }
00305 oroute_del(oroute);
00306 oroute->ort_flags= 0;
00307 oldest_route= oroute;
00308 }
00309 }
00310
00311 if (oldest_route == NULL)
00312 {
00313
00314 for (i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
00315 {
00316 if ((oroute->ort_flags & ORTF_INUSE) == 0)
00317 break;
00318 if (oroute->ort_exp_tim && oroute->ort_exp_tim <
00319 currtim)
00320 {
00321 oroute_del(oroute);
00322 oroute->ort_flags= 0;
00323 break;
00324 }
00325 if (oroute->ort_flags & ORTF_STATIC)
00326 continue;
00327 if (oroute->ort_dest == 0)
00328 {
00329
00330 continue;
00331 }
00332 if (oldest_route == NULL)
00333 {
00334 oldest_route= oroute;
00335 continue;
00336 }
00337 if (oroute->ort_timestamp < oldest_route->ort_timestamp)
00338 {
00339 oldest_route= oroute;
00340 }
00341 }
00342 if (i < OROUTE_NR)
00343 oldest_route= oroute;
00344 else
00345 {
00346 assert(oldest_route);
00347 oroute_del(oldest_route);
00348 oldest_route->ort_flags= 0;
00349 }
00350 }
00351
00352 oldest_route->ort_dest= dest;
00353 oldest_route->ort_gateway= gateway;
00354 oldest_route->ort_subnetmask= subnetmask;
00355 oldest_route->ort_exp_tim= exp_tim;
00356 oldest_route->ort_timestamp= currtim;
00357 oldest_route->ort_dist= dist;
00358 oldest_route->ort_mtu= mtu;
00359 oldest_route->ort_port= port_nr;
00360 oldest_route->ort_flags= ORTF_INUSE;
00361 oldest_route->ort_pref= preference;
00362 if (static_route)
00363 oldest_route->ort_flags |= ORTF_STATIC;
00364
00365
00366
00367
00368 for (prev= 0, nw_route= oroute_head; nw_route;
00369 prev= nw_route, nw_route= nw_route->ort_nextnw)
00370 {
00371 if (nw_route->ort_port != port_nr)
00372 continue;
00373 if (nw_route->ort_dest == dest &&
00374 nw_route->ort_subnetmask == subnetmask)
00375 {
00376 if (prev)
00377 prev->ort_nextnw= nw_route->ort_nextnw;
00378 else
00379 oroute_head= nw_route->ort_nextnw;
00380 break;
00381 }
00382 }
00383 prev_route= nw_route;
00384 for(prev= NULL, gw_route= nw_route; gw_route;
00385 prev= gw_route, gw_route= gw_route->ort_nextgw)
00386 {
00387 if (gw_route->ort_gateway == gateway)
00388 {
00389 if (prev)
00390 prev->ort_nextgw= gw_route->ort_nextgw;
00391 else
00392 nw_route= gw_route->ort_nextgw;
00393 break;
00394 }
00395 }
00396 oldest_route->ort_nextdist= gw_route;
00397 gw_route= oldest_route;
00398 gw_route= sort_dists(gw_route);
00399 gw_route->ort_nextgw= nw_route;
00400 nw_route= gw_route;
00401 nw_route= sort_gws(nw_route);
00402 nw_route->ort_nextnw= oroute_head;
00403 oroute_head= nw_route;
00404 if (nw_route != prev_route)
00405 oroute_uncache_nw(nw_route->ort_dest, nw_route->ort_subnetmask);
00406 if (oroute_p != NULL)
00407 *oroute_p= oldest_route;
00408 return NW_OK;
00409 }
00410
00411 PUBLIC int ipr_del_oroute(port_nr, dest, subnetmask, gateway, static_route)
00412 int port_nr;
00413 ipaddr_t dest;
00414 ipaddr_t subnetmask;
00415 ipaddr_t gateway;
00416 int static_route;
00417 {
00418 int i;
00419 oroute_t *oroute;
00420
00421 for(i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
00422 {
00423 if ((oroute->ort_flags & ORTF_INUSE) == 0)
00424 continue;
00425 if (oroute->ort_port != port_nr ||
00426 oroute->ort_dest != dest ||
00427 oroute->ort_subnetmask != subnetmask ||
00428 oroute->ort_gateway != gateway)
00429 {
00430 continue;
00431 }
00432 if (!!(oroute->ort_flags & ORTF_STATIC) != static_route)
00433 continue;
00434 break;
00435 }
00436
00437 if (i == OROUTE_NR)
00438 return ESRCH;
00439
00440 if (static_route)
00441 static_oroute_nr--;
00442
00443 oroute_del(oroute);
00444 oroute->ort_flags &= ~ORTF_INUSE;
00445 return NW_OK;
00446 }
00447
00448
00449
00450 PUBLIC void ipr_chk_otab(port_nr, addr, mask)
00451 int port_nr;
00452 ipaddr_t addr;
00453 ipaddr_t mask;
00454 {
00455 int i;
00456 oroute_t *oroute;
00457
00458 DBLOCK(1,
00459 printf("ip[%d] (ipr_chk_otab): addr ", port_nr);
00460 writeIpAddr(addr);
00461 printf(" mask ");
00462 writeIpAddr(mask);
00463 printf("\n");
00464 );
00465
00466 if (addr == 0)
00467 {
00468
00469
00470
00471 addr= mask= HTONL(0xffffffff);
00472 }
00473
00474 for(i= 0, oroute= oroute_table; i<OROUTE_NR; i++, oroute++)
00475 {
00476 if ((oroute->ort_flags & ORTF_INUSE) == 0)
00477 continue;
00478 if (oroute->ort_port != port_nr ||
00479 ((oroute->ort_gateway ^ addr) & mask) == 0)
00480 {
00481 continue;
00482 }
00483 DBLOCK(1, printf("ip[%d] (ipr_chk_otab): deleting route to ",
00484 port_nr);
00485 writeIpAddr(oroute->ort_dest);
00486 printf(" gw ");
00487 writeIpAddr(oroute->ort_gateway);
00488 printf("\n"));
00489
00490 if (oroute->ort_flags & ORTF_STATIC)
00491 static_oroute_nr--;
00492 oroute_del(oroute);
00493 oroute->ort_flags &= ~ORTF_INUSE;
00494 }
00495 }
00496
00497
00498 PUBLIC void ipr_gateway_down(port_nr, gateway, timeout)
00499 int port_nr;
00500 ipaddr_t gateway;
00501 time_t timeout;
00502 {
00503 oroute_t *route_ind;
00504 time_t currtim;
00505 int i;
00506 int result;
00507
00508 currtim= get_time();
00509 for (i= 0, route_ind= oroute_table; i<OROUTE_NR; i++, route_ind++)
00510 {
00511 if (!(route_ind->ort_flags & ORTF_INUSE))
00512 continue;
00513 if (route_ind->ort_gateway != gateway)
00514 continue;
00515 if (route_ind->ort_exp_tim && route_ind->ort_exp_tim < currtim)
00516 continue;
00517 result= ipr_add_oroute(port_nr, route_ind->ort_dest,
00518 route_ind->ort_subnetmask, gateway,
00519 timeout, ORTD_UNREACHABLE, route_ind->ort_mtu,
00520 FALSE, 0, NULL);
00521 assert(result == NW_OK);
00522 }
00523 }
00524
00525
00526 PUBLIC void ipr_destunrch(port_nr, dest, netmask, timeout)
00527 int port_nr;
00528 ipaddr_t dest;
00529 ipaddr_t netmask;
00530 time_t timeout;
00531 {
00532 oroute_t *oroute;
00533 int result;
00534
00535 oroute= oroute_find_ent(port_nr, dest);
00536
00537 if (!oroute)
00538 {
00539 DBLOCK(1, printf("ip[%d]: got a dest unreachable for ",
00540 port_nr);
00541 writeIpAddr(dest); printf("but no route present\n"));
00542
00543 return;
00544 }
00545 result= ipr_add_oroute(port_nr, dest, netmask, oroute->ort_gateway,
00546 timeout, ORTD_UNREACHABLE, oroute->ort_mtu, FALSE, 0, NULL);
00547 assert(result == NW_OK);
00548 }
00549
00550
00551 PUBLIC void ipr_redirect(port_nr, dest, netmask, old_gateway, new_gateway,
00552 timeout)
00553 int port_nr;
00554 ipaddr_t dest;
00555 ipaddr_t netmask;
00556 ipaddr_t old_gateway;
00557 ipaddr_t new_gateway;
00558 time_t timeout;
00559 {
00560 oroute_t *oroute;
00561 ip_port_t *ip_port;
00562 int result;
00563
00564 ip_port= &ip_port_table[port_nr];
00565 oroute= oroute_find_ent(port_nr, dest);
00566
00567 if (!oroute)
00568 {
00569 DBLOCK(1, printf("ip[%d]: got a redirect for ", port_nr);
00570 writeIpAddr(dest); printf("but no route present\n"));
00571 return;
00572 }
00573 if (oroute->ort_gateway != old_gateway)
00574 {
00575 DBLOCK(1, printf("ip[%d]: got a redirect from ", port_nr);
00576 writeIpAddr(old_gateway); printf(" for ");
00577 writeIpAddr(dest); printf(" but curr gateway is ");
00578 writeIpAddr(oroute->ort_gateway); printf("\n"));
00579 return;
00580 }
00581 if ((new_gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask)
00582 {
00583 DBLOCK(1, printf("ip[%d]: redirect from ", port_nr);
00584 writeIpAddr(old_gateway); printf(" for ");
00585 writeIpAddr(dest); printf(" but new gateway ");
00586 writeIpAddr(new_gateway);
00587 printf(" is not on local subnet\n"));
00588 return;
00589 }
00590 if (oroute->ort_flags & ORTF_STATIC)
00591 {
00592 if (oroute->ort_dest == dest)
00593 {
00594 DBLOCK(1, printf("ip[%d]: got a redirect for ",
00595 port_nr);
00596 writeIpAddr(dest);
00597 printf("but route is fixed\n"));
00598 return;
00599 }
00600 }
00601 else
00602 {
00603 result= ipr_add_oroute(port_nr, dest, netmask,
00604 oroute->ort_gateway, HZ, ORTD_UNREACHABLE,
00605 oroute->ort_mtu, FALSE, 0, NULL);
00606 assert(result == NW_OK);
00607 }
00608 result= ipr_add_oroute(port_nr, dest, netmask, new_gateway,
00609 timeout, 1, oroute->ort_mtu, FALSE, 0, NULL);
00610 assert(result == NW_OK);
00611 }
00612
00613
00614 PUBLIC void ipr_ttl_exc(port_nr, dest, netmask, timeout)
00615 int port_nr;
00616 ipaddr_t dest;
00617 ipaddr_t netmask;
00618 time_t timeout;
00619 {
00620 oroute_t *oroute;
00621 int new_dist;
00622 int result;
00623
00624 oroute= oroute_find_ent(port_nr, dest);
00625
00626 if (!oroute)
00627 {
00628 DBLOCK(1, printf("ip[%d]: got a ttl exceeded for ",
00629 port_nr);
00630 writeIpAddr(dest); printf("but no route present\n"));
00631 return;
00632 }
00633
00634 new_dist= oroute->ort_dist * 2;
00635 if (new_dist > IP_DEF_TTL)
00636 {
00637 new_dist= oroute->ort_dist+1;
00638 if (new_dist >= IP_DEF_TTL)
00639 {
00640 DBLOCK(1, printf("ip[%d]: got a ttl exceeded for ",
00641 port_nr);
00642 writeIpAddr(dest);
00643 printf(" but dist is %d\n",
00644 oroute->ort_dist));
00645 return;
00646 }
00647 }
00648
00649 result= ipr_add_oroute(port_nr, dest, netmask, oroute->ort_gateway,
00650 timeout, new_dist, oroute->ort_mtu, FALSE, 0, NULL);
00651 assert(result == NW_OK);
00652 }
00653
00654 PUBLIC void ipr_mtu(port_nr, dest, mtu, timeout)
00655 int port_nr;
00656 ipaddr_t dest;
00657 u16_t mtu;
00658 time_t timeout;
00659 {
00660 oroute_t *oroute;
00661 int result;
00662
00663 oroute= oroute_find_ent(port_nr, dest);
00664
00665 if (!oroute)
00666 {
00667 DBLOCK(1, printf("ip[%d]: got a mtu exceeded for ",
00668 port_nr);
00669 writeIpAddr(dest); printf("but no route present\n"));
00670 return;
00671 }
00672
00673 if (mtu < IP_MIN_MTU)
00674 return;
00675 if (oroute->ort_mtu && mtu >= oroute->ort_mtu)
00676 return;
00677
00678 result= ipr_add_oroute(port_nr, dest, HTONL(0xffffffff),
00679 oroute->ort_gateway, timeout, oroute->ort_dist, mtu,
00680 FALSE, 0, NULL);
00681 assert(result == NW_OK);
00682 }
00683
00684
00685 PUBLIC int ipr_get_oroute(ent_no, route_ent)
00686 int ent_no;
00687 nwio_route_t *route_ent;
00688 {
00689 oroute_t *oroute;
00690
00691 if (ent_no<0 || ent_no>= OROUTE_NR)
00692 return ENOENT;
00693
00694 oroute= &oroute_table[ent_no];
00695 if ((oroute->ort_flags & ORTF_INUSE) && oroute->ort_exp_tim &&
00696 oroute->ort_exp_tim < get_time())
00697 {
00698 oroute_del(oroute);
00699 oroute->ort_flags &= ~ORTF_INUSE;
00700 }
00701
00702 route_ent->nwr_ent_no= ent_no;
00703 route_ent->nwr_ent_count= OROUTE_NR;
00704 route_ent->nwr_dest= oroute->ort_dest;
00705 route_ent->nwr_netmask= oroute->ort_subnetmask;
00706 route_ent->nwr_gateway= oroute->ort_gateway;
00707 route_ent->nwr_dist= oroute->ort_dist;
00708 route_ent->nwr_flags= NWRF_EMPTY;
00709 if (oroute->ort_flags & ORTF_INUSE)
00710 {
00711 route_ent->nwr_flags |= NWRF_INUSE;
00712 if (oroute->ort_flags & ORTF_STATIC)
00713 route_ent->nwr_flags |= NWRF_STATIC;
00714 }
00715 route_ent->nwr_pref= oroute->ort_pref;
00716 route_ent->nwr_mtu= oroute->ort_mtu;
00717 route_ent->nwr_ifaddr= ip_get_ifaddr(oroute->ort_port);
00718 return NW_OK;
00719 }
00720
00721
00722 PRIVATE oroute_t *oroute_find_ent(port_nr, dest)
00723 int port_nr;
00724 ipaddr_t dest;
00725 {
00726 int hash;
00727 oroute_hash_t *oroute_hash;
00728 oroute_hash_t tmp_hash;
00729 oroute_t *oroute, *bestroute;
00730 time_t currtim;
00731 unsigned long hash_tmp;
00732 u32_t tmp_mask;
00733
00734 currtim= get_time();
00735
00736 hash= hash_oroute(port_nr, dest, hash_tmp);
00737 oroute_hash= &oroute_hash_table[hash][0];
00738 if (oroute_hash[0].orh_addr == dest)
00739 oroute= oroute_hash[0].orh_route;
00740 else if (oroute_hash[1].orh_addr == dest)
00741 {
00742 tmp_hash= oroute_hash[1];
00743 oroute_hash[1]= oroute_hash[0];
00744 oroute_hash[0]= tmp_hash;
00745 oroute= tmp_hash.orh_route;
00746 }
00747 else if (oroute_hash[2].orh_addr == dest)
00748 {
00749 tmp_hash= oroute_hash[2];
00750 oroute_hash[2]= oroute_hash[1];
00751 oroute_hash[1]= oroute_hash[0];
00752 oroute_hash[0]= tmp_hash;
00753 oroute= tmp_hash.orh_route;
00754 }
00755 else if (oroute_hash[3].orh_addr == dest)
00756 {
00757 tmp_hash= oroute_hash[3];
00758 oroute_hash[3]= oroute_hash[2];
00759 oroute_hash[2]= oroute_hash[1];
00760 oroute_hash[1]= oroute_hash[0];
00761 oroute_hash[0]= tmp_hash;
00762 oroute= tmp_hash.orh_route;
00763 }
00764 else
00765 oroute= NULL;
00766 if (oroute)
00767 {
00768 assert(oroute->ort_port == port_nr);
00769 if (oroute->ort_exp_tim && oroute->ort_exp_tim<currtim)
00770 {
00771 oroute_del(oroute);
00772 oroute->ort_flags &= ~ORTF_INUSE;
00773 }
00774 else
00775 return oroute;
00776 }
00777
00778 bestroute= NULL;
00779 for (oroute= oroute_head; oroute; oroute= oroute->ort_nextnw)
00780 {
00781 if (((dest ^ oroute->ort_dest) & oroute->ort_subnetmask) != 0)
00782 continue;
00783 if (oroute->ort_port != port_nr)
00784 continue;
00785 if (!bestroute)
00786 {
00787 bestroute= oroute;
00788 continue;
00789 }
00790 assert(oroute->ort_dest != bestroute->ort_dest);
00791
00792
00793
00794 tmp_mask= ntohl(oroute->ort_subnetmask);
00795 if (tmp_mask > ntohl(bestroute->ort_subnetmask))
00796 {
00797 bestroute= oroute;
00798 continue;
00799 }
00800 }
00801 if (bestroute == NULL)
00802 return NULL;
00803
00804 oroute_hash[3]= oroute_hash[2];
00805 oroute_hash[2]= oroute_hash[1];
00806 oroute_hash[1]= oroute_hash[0];
00807 oroute_hash[0].orh_addr= dest;
00808 oroute_hash[0].orh_route= bestroute;
00809
00810 return bestroute;
00811 }
00812
00813
00814 PRIVATE void oroute_del(oroute)
00815 oroute_t *oroute;
00816 {
00817 oroute_t *prev, *nw_route, *gw_route, *dist_route, *prev_route;
00818
00819 DBLOCK(0x10,
00820 printf("ip[%d]: deleting oroute to ", oroute->ort_port);
00821 writeIpAddr(oroute->ort_dest);
00822 printf("["); writeIpAddr(oroute->ort_subnetmask);
00823 printf("] through ");
00824 writeIpAddr(oroute->ort_gateway);
00825 printf(
00826 " timestamp %lds, timeout: %lds, distance %d pref %ld mtu %ld ",
00827 (long)oroute->ort_timestamp/HZ,
00828 (long)oroute->ort_exp_tim/HZ, oroute->ort_dist,
00829 (long)oroute->ort_pref, (long)oroute->ort_mtu);
00830 printf("flags 0x%x\n", oroute->ort_flags));
00831
00832 for (prev= NULL, nw_route= oroute_head; nw_route;
00833 prev= nw_route, nw_route= nw_route->ort_nextnw)
00834 {
00835 if (oroute->ort_port == nw_route->ort_port &&
00836 oroute->ort_dest == nw_route->ort_dest &&
00837 oroute->ort_subnetmask == nw_route->ort_subnetmask)
00838 {
00839 break;
00840 }
00841 }
00842 assert(nw_route);
00843 if (prev)
00844 prev->ort_nextnw= nw_route->ort_nextnw;
00845 else
00846 oroute_head= nw_route->ort_nextnw;
00847 prev_route= nw_route;
00848 for (prev= NULL, gw_route= nw_route; gw_route;
00849 prev= gw_route, gw_route= gw_route->ort_nextgw)
00850 {
00851 if (oroute->ort_gateway == gw_route->ort_gateway)
00852 break;
00853 }
00854 assert(gw_route);
00855 if (prev)
00856 prev->ort_nextgw= gw_route->ort_nextgw;
00857 else
00858 nw_route= gw_route->ort_nextgw;
00859 for (prev= NULL, dist_route= gw_route; dist_route;
00860 prev= dist_route, dist_route= dist_route->ort_nextdist)
00861 {
00862 if (oroute == dist_route)
00863 break;
00864 }
00865 assert(dist_route);
00866 if (prev)
00867 prev->ort_nextdist= dist_route->ort_nextdist;
00868 else
00869 gw_route= dist_route->ort_nextdist;
00870 gw_route= sort_dists(gw_route);
00871 if (gw_route != NULL)
00872 {
00873 gw_route->ort_nextgw= nw_route;
00874 nw_route= gw_route;
00875 }
00876 nw_route= sort_gws(nw_route);
00877 if (nw_route != NULL)
00878 {
00879 nw_route->ort_nextnw= oroute_head;
00880 oroute_head= nw_route;
00881 }
00882 if (nw_route != prev_route)
00883 {
00884 oroute_uncache_nw(prev_route->ort_dest,
00885 prev_route->ort_subnetmask);
00886 }
00887 }
00888
00889
00890 PRIVATE oroute_t *sort_dists(oroute)
00891 oroute_t *oroute;
00892 {
00893 oroute_t *r, *prev, *best, *best_prev;
00894 int best_dist, best_pref;
00895
00896 best= NULL;
00897 best_dist= best_pref= 0;
00898 best_prev= NULL;
00899 for (prev= NULL, r= oroute; r; prev= r, r= r->ort_nextdist)
00900 {
00901 if (best == NULL)
00902 ;
00903 else if (r->ort_dist != best_dist)
00904 {
00905 if (r->ort_dist > best_dist)
00906 continue;
00907 }
00908 else
00909 {
00910 if (r->ort_pref <= best_pref)
00911 continue;
00912 }
00913 best= r;
00914 best_prev= prev;
00915 best_dist= r->ort_dist;
00916 best_pref= r->ort_pref;
00917 }
00918 if (!best)
00919 {
00920 assert(oroute == NULL);
00921 return oroute;
00922 }
00923 if (!best_prev)
00924 {
00925 assert(best == oroute);
00926 return oroute;
00927 }
00928 best_prev->ort_nextdist= best->ort_nextdist;
00929 best->ort_nextdist= oroute;
00930 return best;
00931 }
00932
00933
00934 PRIVATE oroute_t *sort_gws(oroute)
00935 oroute_t *oroute;
00936 {
00937 oroute_t *r, *prev, *best, *best_prev;
00938 int best_dist, best_pref;
00939
00940 best= NULL;
00941 best_dist= best_pref= 0;
00942 best_prev= NULL;
00943 for (prev= NULL, r= oroute; r; prev= r, r= r->ort_nextgw)
00944 {
00945 if (best == NULL)
00946 ;
00947 else if (r->ort_dist != best_dist)
00948 {
00949 if (r->ort_dist > best_dist)
00950 continue;
00951 }
00952 else
00953 {
00954 if (r->ort_pref <= best_pref)
00955 continue;
00956 }
00957 best= r;
00958 best_prev= prev;
00959 best_dist= r->ort_dist;
00960 best_pref= r->ort_pref;
00961 }
00962 if (!best)
00963 {
00964 assert(oroute == NULL);
00965 return oroute;
00966 }
00967 if (!best_prev)
00968 {
00969 assert(best == oroute);
00970 return oroute;
00971 }
00972 best_prev->ort_nextgw= best->ort_nextgw;
00973 best->ort_nextgw= oroute;
00974 return best;
00975 }
00976
00977
00978 PRIVATE void oroute_uncache_nw(dest, netmask)
00979 ipaddr_t dest;
00980 ipaddr_t netmask;
00981 {
00982 int i, j;
00983 oroute_hash_t *oroute_hash;
00984
00985 for (i= 0, oroute_hash= &oroute_hash_table[0][0];
00986 i<OROUTE_HASH_NR; i++, oroute_hash += OROUTE_HASH_ASS_NR)
00987 {
00988 for (j= 0; j<OROUTE_HASH_ASS_NR; j++)
00989 {
00990 if (((oroute_hash[j].orh_addr ^ dest) & netmask) == 0)
00991 {
00992 oroute_hash[j].orh_addr= 0;
00993 oroute_hash[j].orh_route= NULL;
00994 }
00995 }
00996 }
00997 }
00998
00999
01000
01001
01002
01003
01004 PUBLIC int ipr_get_iroute(ent_no, route_ent)
01005 int ent_no;
01006 nwio_route_t *route_ent;
01007 {
01008 iroute_t *iroute;
01009
01010 if (ent_no<0 || ent_no>= IROUTE_NR)
01011 return ENOENT;
01012
01013 iroute= &iroute_table[ent_no];
01014
01015 route_ent->nwr_ent_no= ent_no;
01016 route_ent->nwr_ent_count= IROUTE_NR;
01017 route_ent->nwr_dest= iroute->irt_dest;
01018 route_ent->nwr_netmask= iroute->irt_subnetmask;
01019 route_ent->nwr_gateway= iroute->irt_gateway;
01020 route_ent->nwr_dist= iroute->irt_dist;
01021 route_ent->nwr_flags= NWRF_EMPTY;
01022 if (iroute->irt_flags & IRTF_INUSE)
01023 {
01024 route_ent->nwr_flags |= NWRF_INUSE;
01025 if (iroute->irt_flags & IRTF_STATIC)
01026 route_ent->nwr_flags |= NWRF_STATIC;
01027 if (iroute->irt_dist == IRTD_UNREACHABLE)
01028 route_ent->nwr_flags |= NWRF_UNREACHABLE;
01029 }
01030 route_ent->nwr_pref= 0;
01031 route_ent->nwr_mtu= iroute->irt_mtu;
01032 route_ent->nwr_ifaddr= ip_get_ifaddr(iroute->irt_port);
01033 return NW_OK;
01034 }
01035
01036
01037 PUBLIC int ipr_add_iroute(port_nr, dest, subnetmask, gateway,
01038 dist, mtu, static_route, iroute_p)
01039 int port_nr;
01040 ipaddr_t dest;
01041 ipaddr_t subnetmask;
01042 ipaddr_t gateway;
01043 int dist;
01044 int mtu;
01045 int static_route;
01046 iroute_t **iroute_p;
01047 {
01048 int i;
01049 iroute_t *iroute, *unused_route;
01050 ip_port_t *ip_port;
01051
01052 ip_port= &ip_port_table[port_nr];
01053
01054
01055 if (((gateway ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) != 0 &&
01056 gateway != 0)
01057 {
01058 DBLOCK(1, printf("ip[%d] (ipr_add_iroute): invalid gateway: ",
01059 port_nr);
01060 writeIpAddr(gateway); printf("\n"));
01061 return EINVAL;
01062 }
01063
01064 unused_route= NULL;
01065 if (static_route)
01066 {
01067
01068
01069
01070 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
01071 {
01072 if ((iroute->irt_flags & IRTF_INUSE) == 0)
01073 break;
01074 }
01075 if (i != IROUTE_NR)
01076 unused_route= iroute;
01077 }
01078 else
01079 {
01080
01081
01082
01083 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
01084 {
01085 if ((iroute->irt_flags & IRTF_INUSE) == 0)
01086 {
01087 unused_route= iroute;
01088 continue;
01089 }
01090 if ((iroute->irt_flags & IRTF_STATIC) != 0)
01091 continue;
01092 if (iroute->irt_port != port_nr ||
01093 iroute->irt_dest != dest ||
01094 iroute->irt_subnetmask != subnetmask ||
01095 iroute->irt_gateway != gateway)
01096 {
01097 continue;
01098 }
01099 break;
01100 }
01101 if (i != IROUTE_NR)
01102 unused_route= iroute;
01103 }
01104
01105 if (unused_route == NULL)
01106 return ENOMEM;
01107 iroute= unused_route;
01108
01109 iroute->irt_port= port_nr;
01110 iroute->irt_dest= dest;
01111 iroute->irt_subnetmask= subnetmask;
01112 iroute->irt_gateway= gateway;
01113 iroute->irt_dist= dist;
01114 iroute->irt_mtu= mtu;
01115 iroute->irt_flags= IRTF_INUSE;
01116 if (static_route)
01117 iroute->irt_flags |= IRTF_STATIC;
01118
01119 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
01120 if (iroute_p != NULL)
01121 *iroute_p= iroute;
01122 return NW_OK;
01123 }
01124
01125
01126 PUBLIC int ipr_del_iroute(port_nr, dest, subnetmask, gateway, static_route)
01127 int port_nr;
01128 ipaddr_t dest;
01129 ipaddr_t subnetmask;
01130 ipaddr_t gateway;
01131 int static_route;
01132 {
01133 int i;
01134 iroute_t *iroute;
01135
01136
01137
01138
01139 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
01140 {
01141 if ((iroute->irt_flags & IRTF_INUSE) == 0)
01142 continue;
01143 if (iroute->irt_port != port_nr ||
01144 iroute->irt_dest != dest ||
01145 iroute->irt_subnetmask != subnetmask ||
01146 iroute->irt_gateway != gateway)
01147 {
01148 continue;
01149 }
01150 if (!!(iroute->irt_flags & IRTF_STATIC) != static_route)
01151 continue;
01152 break;
01153 }
01154
01155 if (i == IROUTE_NR)
01156 return ESRCH;
01157
01158 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
01159 iroute->irt_flags= IRTF_EMPTY;
01160 return NW_OK;
01161 }
01162
01163
01164 PUBLIC void ipr_chk_itab(port_nr, addr, mask)
01165 int port_nr;
01166 ipaddr_t addr;
01167 ipaddr_t mask;
01168 {
01169 int i;
01170 iroute_t *iroute;
01171
01172 DBLOCK(1,
01173 printf("ip[%d] (ipr_chk_itab): addr ", port_nr);
01174 writeIpAddr(addr);
01175 printf(" mask ");
01176 writeIpAddr(mask);
01177 printf("\n");
01178 );
01179
01180 if (addr == 0)
01181 {
01182
01183
01184
01185 addr= mask= HTONL(0xffffffff);
01186 }
01187
01188 for(i= 0, iroute= iroute_table; i<IROUTE_NR; i++, iroute++)
01189 {
01190 if ((iroute->irt_flags & IRTF_INUSE) == 0)
01191 continue;
01192 if (iroute->irt_port != port_nr)
01193 continue;
01194 if (iroute->irt_gateway == 0)
01195 {
01196
01197 if (iroute->irt_subnetmask == mask &&
01198 iroute->irt_dest == (addr & mask))
01199 {
01200
01201 continue;
01202 }
01203 }
01204 if (((iroute->irt_gateway ^ addr) & mask) == 0)
01205 continue;
01206
01207 DBLOCK(1, printf("ip[%d] (ipr_chk_itab): deleting route to ",
01208 port_nr);
01209 writeIpAddr(iroute->irt_dest);
01210 printf(" gw ");
01211 writeIpAddr(iroute->irt_gateway);
01212 printf("\n"));
01213
01214 iroute_uncache_nw(iroute->irt_dest, iroute->irt_subnetmask);
01215 iroute->irt_flags &= ~IRTF_INUSE;
01216 }
01217 }
01218
01219
01220 PRIVATE void iroute_uncache_nw(dest, netmask)
01221 ipaddr_t dest;
01222 ipaddr_t netmask;
01223 {
01224 int i, j;
01225 iroute_hash_t *iroute_hash;
01226
01227 for (i= 0, iroute_hash= &iroute_hash_table[0][0];
01228 i<IROUTE_HASH_NR; i++, iroute_hash += IROUTE_HASH_ASS_NR)
01229 {
01230 for (j= 0; j<IROUTE_HASH_ASS_NR; j++)
01231 {
01232 if (((iroute_hash[j].irh_addr ^ dest) &
01233 netmask) == 0)
01234 {
01235 iroute_hash[j].irh_addr= 0;
01236 iroute_hash[j].irh_route= NULL;
01237 }
01238 }
01239 }
01240 }
01241
01242
01243
01244
01245
01246