ipr.c

Go to the documentation of this file.
00001 /*
00002 ipr.c
00003 
00004 Copyright 1995 Philip Homburg
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                 /* More specific netmasks are better */
00145                 if (iroute->irt_subnetmask != bestroute->irt_subnetmask)
00146                 {
00147                         /* Using two ntohl macros in one expression
00148                          * is not allowed (tmp_l is modified twice)
00149                          */
00150                         tmp_mask= ntohl(iroute->irt_subnetmask);
00151                         if (tmp_mask > ntohl(bestroute->irt_subnetmask))
00152                                 bestroute= iroute;
00153                         continue;
00154                 }
00155                         
00156                 /* Dynamic routes override static routes */
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                 /* A route to the local interface give an opportunity
00166                  * to send redirects.
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         /* Validate gateway */
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                 /* Try to track down any old routes. */
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                                 /* The new expire should not be later
00292                                  * than the old expire time. Except for
00293                                  * default routes, where the expire time
00294                                  * is simple set to the new value.
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                 /* Look for an unused entry, or remove an existing one */
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                                 /* Never remove default routes. */
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         /* Insert the route by tearing apart the routing table, 
00366          * and insert the entry during the reconstruction.
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                 /* Special hack to flush entries for an interface that
00469                  * goes down.
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;         /* Only decrease mtu */
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                 /* Using two ntohl macros in one expression
00792                  * is not allowed (tmp_l is modified twice)
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                         ;       /* Force assignment to best */
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                         ;       /* Force assignment to best */
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  * Input routing
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         /* Check gateway */
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                 /* Static routes are not reused automatically, so we look 
01068                  * for an unused entry.
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                 /* Try to track down any old routes, and look for an
01081                  * unused one.
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         /* Try to track down any old routes, and look for an
01137          * unused one.
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                 /* Special hack to flush entries for an interface that
01183                  * goes down.
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                         /* Special case: attached network. */
01197                         if (iroute->irt_subnetmask == mask &&
01198                                 iroute->irt_dest == (addr & mask))
01199                         {
01200                                 /* Nothing changed. */
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  * $PchId: ipr.c,v 1.23 2003/01/22 11:49:58 philip Exp $
01246  */

Generated on Fri Apr 14 22:57:30 2006 for minix by  doxygen 1.4.6