root/net/inet/route.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rt_print
  2. rt_del
  3. rt_flush
  4. rt_add
  5. rt_new
  6. rt_kill
  7. rt_get_info
  8. rt_route
  9. rt_ioctl

   1 /*
   2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3  *              operating system.  INET is implemented using the  BSD Socket
   4  *              interface as the means of communication with the user level.
   5  *
   6  *              ROUTE - implementation of the IP router.
   7  *
   8  * Version:     @(#)route.c     1.0.14  05/31/93
   9  *
  10  * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
  11  *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  12  *
  13  *              This program is free software; you can redistribute it and/or
  14  *              modify it under the terms of the GNU General Public License
  15  *              as published by the Free Software Foundation; either version
  16  *              2 of the License, or (at your option) any later version.
  17  */
  18 #include <asm/segment.h>
  19 #include <asm/system.h>
  20 #include <linux/types.h>
  21 #include <linux/kernel.h>
  22 #include <linux/sched.h>
  23 #include <linux/string.h>
  24 #include <linux/socket.h>
  25 #include <linux/sockios.h>
  26 #include <linux/errno.h>
  27 #include <linux/in.h>
  28 #include "inet.h"
  29 #include "timer.h"
  30 #include "dev.h"
  31 #include "ip.h"
  32 #include "protocol.h"
  33 #include "route.h"
  34 #include "tcp.h"
  35 #include "skbuff.h"
  36 #include "sock.h"
  37 #include "arp.h"
  38 #include "icmp.h"
  39 
  40 
  41 static struct rtable *rt_base = NULL;
  42 
  43 
  44 /* Dump the contents of a routing table entry. */
  45 static void
  46 rt_print(struct rtable *rt)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48   if (rt == NULL || inet_debug != DBG_RT) return;
  49 
  50   printk("RT: %06lx NXT=%06lx FLAGS=0x%02lx\n",
  51                 (long) rt, (long) rt->rt_next, rt->rt_flags);
  52   printk("    TARGET=%s ", in_ntoa(rt->rt_dst));
  53   printk("GW=%s ", in_ntoa(rt->rt_gateway));
  54   printk("    DEV=%s USE=%ld REF=%ld\n",
  55         (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
  56         rt->rt_use, rt->rt_refcnt);
  57 }
  58 
  59 
  60 /* Remove a routing table entry. */
  61 static void
  62 rt_del(unsigned long dst)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64   struct rtable *r, *x, *p;
  65 
  66   DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
  67   if ((r = rt_base) == NULL) return;
  68   p = NULL;
  69   while(r != NULL) {
  70         if (r->rt_dst == dst) {
  71                 if (p == NULL) rt_base = r->rt_next;
  72                   else p->rt_next = r->rt_next;
  73                 x = r->rt_next;
  74                 kfree_s(r, sizeof(struct rtable));
  75                 r = x;
  76         } else {
  77                 p = r;
  78                 r = r->rt_next;
  79         }
  80   }
  81 }
  82 
  83 
  84 /* Remove all routing table entries for a device. */
  85 void
  86 rt_flush(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88   struct rtable *r, *x, *p;
  89 
  90   DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
  91   if ((r = rt_base) == NULL) return;
  92   p = NULL;
  93   while(r != NULL) {
  94         if (r->rt_dev == dev) {
  95                 if (p == NULL) rt_base = r->rt_next;
  96                   else p->rt_next = r->rt_next;
  97                 x = r->rt_next;
  98                 kfree_s(r, sizeof(struct rtable));
  99                 r = x;
 100         } else {
 101                 p = r;
 102                 r = r->rt_next;
 103         }
 104   }
 105 }
 106 
 107 
 108 void
 109 rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111   struct rtable *r, *r1;
 112   struct rtable *rt;
 113   int mask;
 114 
 115   /* Allocate an entry. */
 116   rt = kmalloc(sizeof(struct rtable), GFP_ATOMIC);
 117   if (rt == NULL) {
 118         DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
 119         return;
 120   }
 121 
 122   /* Fill in the fields. */
 123   memset(rt, 0, sizeof(struct rtable));
 124   rt->rt_flags = (flags | RTF_UP);
 125   if (gw != 0) rt->rt_flags |= RTF_GATEWAY;
 126   rt->rt_dev = dev;
 127   rt->rt_gateway = gw;
 128 
 129   /*
 130    * If this is coming from an ICMP redirect message, truncate
 131    * the TARGET if we are creating an entry for a NETWORK. Use
 132    * an Internet class C network mask.  Yuck :-(
 133    */
 134   if (flags & RTF_DYNAMIC) {
 135         if (flags & RTF_HOST) rt->rt_dst = dst;
 136           else rt->rt_dst = (dst & htonl(IN_CLASSC_NET));
 137   } else rt->rt_dst = dst;
 138 
 139   rt_print(rt);
 140 
 141   if (rt_base == NULL) {
 142         rt->rt_next = NULL;
 143         rt_base = rt;
 144         return;
 145   }
 146 
 147   /*
 148    * What we have to do is loop though this until we have
 149    * found the first address which has the same generality
 150    * as the one in rt.  Then we can put rt in after it.
 151    */
 152   for (mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) {
 153         if (mask & dst) {
 154                 mask = mask << 8;
 155                 break;
 156         }
 157   }
 158   DPRINTF((DBG_RT, "RT: mask = %X\n", mask));
 159   r1 = rt_base;
 160 
 161   /* See if we are getting a duplicate. */
 162   for (r = rt_base; r != NULL; r = r->rt_next) {
 163         if (r->rt_dst == dst) {
 164                 if (r == rt_base) {
 165                         rt->rt_next = r->rt_next;
 166                         rt_base = rt;
 167                 } else {
 168                         rt->rt_next = r->rt_next;
 169                         r1->rt_next = rt;
 170                 }
 171                 kfree_s(r, sizeof(struct rtable));
 172                 return;
 173         }
 174 
 175         if (! (r->rt_dst & mask)) {
 176                 DPRINTF((DBG_RT, "RT: adding before r=%X\n", r));
 177                 rt_print(r);
 178                 if (r == rt_base) {
 179                         rt->rt_next = rt_base;
 180                         rt_base = rt;
 181                         return;
 182                 }
 183                 rt->rt_next = r;
 184                 r1->rt_next = rt;
 185                 return;
 186         }
 187         r1 = r;
 188   }
 189   DPRINTF((DBG_RT, "RT: adding after r1=%X\n", r1));
 190   rt_print(r1);
 191 
 192   /* Goes at the end. */
 193   rt->rt_next = NULL;
 194   r1->rt_next = rt;
 195 }
 196 
 197 
 198 static int
 199 rt_new(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201   struct device *dev;
 202   struct rtable *rt;
 203 
 204   if ((r->rt_dst.sa_family != AF_INET) ||
 205       (r->rt_gateway.sa_family != AF_INET)) {
 206         DPRINTF((DBG_RT, "RT: We only know about AF_INET !\n"));
 207         return(-EAFNOSUPPORT);
 208   }
 209 
 210   /*
 211    * I admit that the following bits of code were "inspired" by
 212    * the Berkeley UNIX system source code.  I could think of no
 213    * other way to find out how to make it compatible with it (I
 214    * want this to be compatible to get "routed" up and running).
 215    * -FvK
 216    */
 217 
 218   /* If we have a 'gateway' route here, check the correct address. */
 219   if (r->rt_flags & RTF_GATEWAY) {
 220         dev = dev_check(0,
 221                 ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr);
 222         if (dev == NULL) {
 223                 dev = dev_check(1,
 224                     ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr);
 225         }
 226 
 227         /*
 228          * Aii.  We are using an indirect route.  Check the already
 229          * existing routing table for an entry.
 230          */
 231         if (dev == NULL) {
 232                 for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
 233                         if ((rt->rt_dev->flags & IFF_UP) == 0) continue;
 234                         if (ip_addr_match(rt->rt_dst, 
 235                                           ((struct sockaddr_in *)
 236                                             &r->rt_gateway)->sin_addr.s_addr)) {
 237                                 dev = rt->rt_dev;
 238                                 break;
 239                         }
 240                         if (ip_addr_match(rt->rt_dev->pa_brdaddr,
 241                                           ((struct sockaddr_in *)
 242                                             &r->rt_gateway)->sin_addr.s_addr)) {
 243                                 dev = rt->rt_dev;
 244                                 break;
 245                         }
 246                 }
 247         }
 248   } else {
 249         dev = dev_check(0,
 250                 ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
 251         if (dev == NULL) {
 252                 dev = dev_check(1,
 253                     ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
 254         }
 255 
 256         /*
 257          * Aii.  We are using an indirect route.  Check the already
 258          * existing routing table for an entry.
 259          */
 260         if (dev == NULL) {
 261                 for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
 262                         if ((rt->rt_dev->flags & IFF_UP) == 0) continue;
 263                         if (ip_addr_match(rt->rt_dst,
 264                                           ((struct sockaddr_in *)
 265                                             &r->rt_dst)->sin_addr.s_addr)) {
 266                                 dev = rt->rt_dev;
 267                                 break;
 268                         }
 269                         if (ip_addr_match(rt->rt_dev->pa_brdaddr,
 270                                           ((struct sockaddr_in *)
 271                                             &r->rt_dst)->sin_addr.s_addr)) {
 272                                 dev = rt->rt_dev;
 273                                 break;
 274                         }
 275                 }
 276         }
 277   }
 278 
 279   DPRINTF((DBG_RT, "RT: dev for %s gw ",
 280         in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
 281   DPRINTF((DBG_RT, "%s (0x%04X) is 0x%X (%s)\n",
 282         in_ntoa((*(struct sockaddr_in *)&r->rt_gateway).sin_addr.s_addr),
 283         r->rt_flags, dev, (dev == NULL) ? "NONE" : dev->name));
 284 
 285   if (dev == NULL) return(-ENETUNREACH);
 286 
 287   rt_add(r->rt_flags, (*(struct sockaddr_in *) &r->rt_dst).sin_addr.s_addr,
 288          (*(struct sockaddr_in *) &r->rt_gateway).sin_addr.s_addr, dev);
 289 
 290   return(0);
 291 }
 292 
 293 
 294 static int
 295 rt_kill(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 296 {
 297   struct sockaddr_in *trg;
 298 
 299   trg = (struct sockaddr_in *) &r->rt_dst;
 300   rt_del(trg->sin_addr.s_addr);
 301 
 302   return(0);
 303 }
 304 
 305 
 306 /* Called from the PROCfs module. */
 307 int
 308 rt_get_info(char *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310   struct rtable *r;
 311   char *pos;
 312 
 313   pos = buffer;
 314 
 315   pos += sprintf(pos, "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\n");
 316   
 317   for (r = rt_base; r != NULL; r = r->rt_next) {
 318         pos += sprintf(pos, "%s\t%08X\t%08X\t%02X\t%d\t%d\n",
 319                 r->rt_dev->name, r->rt_dst, r->rt_gateway,
 320                 r->rt_flags, r->rt_refcnt, r->rt_use);
 321   }
 322   return(pos - buffer);
 323 }
 324 
 325 
 326 struct rtable *
 327 rt_route(unsigned long daddr, struct options *opt)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329   struct rtable *rt;
 330 
 331   /*
 332    * This is a hack, I think. -FvK
 333    */
 334   if (chk_addr(daddr) == IS_MYADDR) daddr = my_addr();
 335 
 336   /*
 337    * Loop over the IP routing table to find a route suitable
 338    * for this packet.  Note that we really should have a look
 339    * at the IP options to see if we have been given a hint as
 340    * to what kind of path we should use... -FvK
 341    */
 342   for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
 343         DPRINTF((DBG_RT, "RT: %s via ", in_ntoa(daddr)));
 344         if (ip_addr_match(rt->rt_dst, daddr)) {
 345                 DPRINTF((DBG_RT, "%s (%s)\n",
 346                         rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
 347                 rt->rt_use++;
 348                 return(rt);
 349         }
 350         if (ip_addr_match(rt->rt_dev->pa_brdaddr, daddr)) {
 351                 DPRINTF((DBG_RT, "%s (BCAST %s)\n",
 352                         rt->rt_dev->name, in_ntoa(rt->rt_dev->pa_brdaddr)));
 353                 rt->rt_use++;
 354                 return(rt);
 355         }
 356   }
 357 
 358   DPRINTF((DBG_RT, "NONE\n"));
 359   return(NULL);
 360 };
 361 
 362 
 363 int
 364 rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366   struct rtentry rt;
 367   int ret;
 368 
 369   switch(cmd) {
 370         case DDIOCSDBG:
 371                 ret = dbg_ioctl(arg, DBG_RT);
 372                 break;
 373         case SIOCADDRT:
 374                 if (!suser()) return(-EPERM);
 375                 verify_area(VERIFY_WRITE, arg, sizeof(struct rtentry));
 376                 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
 377                 ret = rt_new(&rt);
 378                 break;
 379         case SIOCDELRT:
 380                 if (!suser()) return(-EPERM);
 381                 verify_area(VERIFY_WRITE, arg, sizeof(struct rtentry));
 382                 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
 383                 ret = rt_kill(&rt);
 384                 break;
 385         default:
 386                 ret = -EINVAL;
 387   }
 388 
 389   return(ret);
 390 }

/* [previous][next][first][last][top][bottom][index][help] */