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  * Fixes:
  14  *              Alan Cox        :       Verify area fixes.
  15  *              Alan Cox        :       cli() protects routing changes
  16  *              Rui Oliveira    :       ICMP routing table updates
  17  *              (rco@di.uminho.pt)      Routing table insertion and update
  18  *
  19  *              This program is free software; you can redistribute it and/or
  20  *              modify it under the terms of the GNU General Public License
  21  *              as published by the Free Software Foundation; either version
  22  *              2 of the License, or (at your option) any later version.
  23  */
  24 #include <asm/segment.h>
  25 #include <asm/system.h>
  26 #include <linux/types.h>
  27 #include <linux/kernel.h>
  28 #include <linux/sched.h>
  29 #include <linux/string.h>
  30 #include <linux/socket.h>
  31 #include <linux/sockios.h>
  32 #include <linux/errno.h>
  33 #include <linux/in.h>
  34 #include "inet.h"
  35 #include "dev.h"
  36 #include "ip.h"
  37 #include "protocol.h"
  38 #include "route.h"
  39 #include "tcp.h"
  40 #include "skbuff.h"
  41 #include "sock.h"
  42 #include "arp.h"
  43 #include "icmp.h"
  44 
  45 
  46 static struct rtable *rt_base = NULL;
  47 
  48 
  49 /* Dump the contents of a routing table entry. */
  50 static void
  51 rt_print(struct rtable *rt)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53   if (rt == NULL || inet_debug != DBG_RT) return;
  54 
  55   printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
  56                 (long) rt, (long) rt->rt_next, rt->rt_flags);
  57   printk("    TARGET=%s ", in_ntoa(rt->rt_dst));
  58   printk("GW=%s ", in_ntoa(rt->rt_gateway));
  59   printk("    DEV=%s USE=%ld REF=%d\n",
  60         (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
  61         rt->rt_use, rt->rt_refcnt);
  62 }
  63 
  64 
  65 /* Remove a routing table entry. */
  66 static void
  67 rt_del(unsigned long dst)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69   struct rtable *r, *x, *p;
  70   unsigned long flags;
  71   
  72   DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
  73   if ((r = rt_base) == NULL) 
  74         return;
  75 
  76   save_flags(flags);
  77   cli();
  78   p = NULL;
  79   while(r != NULL) 
  80   {
  81         if (r->rt_dst == dst) 
  82         {
  83                 if (p == NULL)
  84                         rt_base = r->rt_next;
  85                 else 
  86                         p->rt_next = r->rt_next;
  87                 x = r->rt_next;
  88                 kfree_s(r, sizeof(struct rtable));
  89                 r = x;
  90         } 
  91         else 
  92         {
  93                 p = r;
  94                 r = r->rt_next;
  95         }
  96   }
  97   restore_flags(flags);
  98 }
  99 
 100 
 101 /* Remove all routing table entries for a device. */
 102 void
 103 rt_flush(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105   struct rtable *r, *x, *p;
 106   unsigned long flags;
 107   
 108   DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
 109   if ((r = rt_base) == NULL) return;
 110   
 111   cli();
 112   save_flags(flags);
 113   
 114   p = NULL;
 115   while(r != NULL) 
 116   {
 117         if (r->rt_dev == dev)
 118         {
 119                 if (p == NULL) 
 120                         rt_base = r->rt_next;
 121                 else 
 122                         p->rt_next = r->rt_next;
 123                 x = r->rt_next;
 124                 kfree_s(r, sizeof(struct rtable));
 125                 r = x;
 126         } 
 127         else 
 128         {
 129                 p = r;
 130                 r = r->rt_next;
 131         }
 132   }
 133   restore_flags(flags);
 134 }
 135 
 136 
 137 void
 138 rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140   struct rtable *r, *r1;
 141   struct rtable *rt;
 142   int mask=0;
 143   unsigned long cpuflags;
 144 
 145   /* Allocate an entry. */
 146   rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
 147   if (rt == NULL) {
 148         DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
 149         return;
 150   }
 151 
 152   /* Fill in the fields. */
 153   memset(rt, 0, sizeof(struct rtable));
 154   rt->rt_flags = (flags | RTF_UP);
 155   
 156   /*
 157    *    Gateway to our own interface is really direct
 158    */
 159   if (gw==dev->pa_addr || gw==dst)
 160   {
 161         gw=0;
 162         rt->rt_flags&=~RTF_GATEWAY;
 163   }
 164   
 165   if (gw != 0) 
 166         rt->rt_flags |= RTF_GATEWAY;
 167   rt->rt_dev = dev;
 168   rt->rt_gateway = gw;
 169 
 170   /*
 171    * If this is coming from an ICMP redirect message, truncate
 172    * the TARGET if we are creating an entry for a NETWORK. Use
 173    * an Internet class C network mask.  Yuck :-(
 174    */
 175   if (flags & RTF_DYNAMIC) 
 176   {
 177         if (flags & RTF_HOST)
 178                 rt->rt_dst = dst;
 179         else
 180         {
 181                 /* Cut down to the route at interface mask level */
 182                 rt->rt_dst = (dst & dev->pa_mask);
 183                 mask=dev->pa_mask;
 184                 /* We don't want new routes to our own net*/
 185                 if(rt->rt_dst == (dev->pa_addr & dev->pa_mask))
 186                 {
 187                         kfree_s(rt, sizeof(struct rtable));
 188                         /*printk("Dynamic route to my own net rejected\n");*/
 189                         return;
 190                 }
 191         }
 192   } 
 193   else 
 194         rt->rt_dst = dst;
 195 
 196   rt_print(rt);
 197 
 198   if (rt_base == NULL) 
 199   {
 200         rt->rt_next = NULL;
 201         rt_base = rt;
 202         return;
 203   }
 204 
 205   /*
 206    * What we have to do is loop though this until we have
 207    * found the first address which has the same generality
 208    * as the one in rt.  Then we can put rt in after it.
 209    */
 210    
 211   if(mask==0)   /* Dont figure out masks for DYNAMIC routes. The mask is (our should be!)
 212                    the device mask (obtained above) */
 213   {
 214           for (mask = 0xff000000L; mask != 0xffffffffL; mask = (mask >> 8) | mask) 
 215           {
 216                 if (mask & dst) 
 217                 {
 218                         mask = mask << 8;
 219                         break;
 220                 }
 221           }
 222           DPRINTF((DBG_RT, "RT: mask = %X\n", mask));
 223   }
 224     
 225   save_flags(cpuflags);
 226   cli();
 227   
 228   r1 = rt_base;
 229 
 230   /* See if we are getting a duplicate. */
 231   for (r = rt_base; r != NULL; r = r->rt_next) 
 232   {
 233         if (r->rt_dst == dst) 
 234         {
 235                 if (r == rt_base) 
 236                 {
 237                         rt->rt_next = r->rt_next;
 238                         rt_base = rt;
 239                 } 
 240                 else 
 241                 {
 242                         rt->rt_next = r->rt_next;
 243                         r1->rt_next = rt;
 244                 }
 245                 kfree_s(r, sizeof(struct rtable));
 246                 restore_flags(cpuflags);
 247                 return;
 248         }
 249         r1 = r;
 250   }
 251 
 252   r1 = rt_base;
 253   for (r = rt_base; r != NULL; r = r->rt_next) 
 254   {
 255         /* When we find a route more general than ourselves, and we are not a gateway or it is a gateway then use it 
 256            This puts gateways after direct links in the table and sorts (most) of the bit aligned subnetting out */
 257         if (! (r->rt_dst & mask) && (gw==0 || r->rt_flags&RTF_GATEWAY)) 
 258         {
 259                 DPRINTF((DBG_RT, "RT: adding before r=%X\n", r));
 260                 rt_print(r);
 261                 if (r == rt_base) 
 262                 {
 263                         rt->rt_next = rt_base;
 264                         rt_base = rt;
 265                         restore_flags(cpuflags);
 266                         return;
 267                 }
 268                 rt->rt_next = r;
 269                 r1->rt_next = rt;
 270                 restore_flags(cpuflags);
 271                 return;
 272         }
 273         r1 = r;
 274   }
 275   DPRINTF((DBG_RT, "RT: adding after r1=%X\n", r1));
 276   rt_print(r1);
 277 
 278   /* Goes at the end. */
 279   rt->rt_next = NULL;
 280   r1->rt_next = rt;
 281 }
 282 
 283 
 284 static int
 285 rt_new(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 286 {
 287   struct device *dev;
 288   struct rtable *rt;
 289 
 290   if ((r->rt_dst.sa_family != AF_INET) ||
 291       (r->rt_gateway.sa_family != AF_INET)) {
 292         DPRINTF((DBG_RT, "RT: We only know about AF_INET !\n"));
 293         return(-EAFNOSUPPORT);
 294   }
 295 
 296   /*
 297    * I admit that the following bits of code were "inspired" by
 298    * the Berkeley UNIX system source code.  I could think of no
 299    * other way to find out how to make it compatible with it (I
 300    * want this to be compatible to get "routed" up and running).
 301    * -FvK
 302    */
 303 
 304   /* If we have a 'gateway' route here, check the correct address. */
 305   if (!(r->rt_flags & RTF_GATEWAY))
 306         dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
 307   else
 308         if ((rt = rt_route(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.
 309                            s_addr,NULL)))
 310             dev = rt->rt_dev;
 311         else
 312             dev = NULL;
 313 
 314   DPRINTF((DBG_RT, "RT: dev for %s gw ",
 315         in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
 316   DPRINTF((DBG_RT, "%s (0x%04X) is 0x%X (%s)\n",
 317         in_ntoa((*(struct sockaddr_in *)&r->rt_gateway).sin_addr.s_addr),
 318         r->rt_flags, dev, (dev == NULL) ? "NONE" : dev->name));
 319 
 320   if (dev == NULL) return(-ENETUNREACH);
 321 
 322   rt_add(r->rt_flags, (*(struct sockaddr_in *) &r->rt_dst).sin_addr.s_addr,
 323          (*(struct sockaddr_in *) &r->rt_gateway).sin_addr.s_addr, dev);
 324 
 325   return(0);
 326 }
 327 
 328 
 329 static int
 330 rt_kill(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332   struct sockaddr_in *trg;
 333 
 334   trg = (struct sockaddr_in *) &r->rt_dst;
 335   rt_del(trg->sin_addr.s_addr);
 336 
 337   return(0);
 338 }
 339 
 340 
 341 /* Called from the PROCfs module. */
 342 int
 343 rt_get_info(char *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 344 {
 345   struct rtable *r;
 346   char *pos;
 347 
 348   pos = buffer;
 349 
 350   pos += sprintf(pos,
 351                  "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\n");
 352   
 353   /* This isn't quite right -- r->rt_dst is a struct! */
 354   for (r = rt_base; r != NULL; r = r->rt_next) {
 355         pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\n",
 356                 r->rt_dev->name, r->rt_dst, r->rt_gateway,
 357                 r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric);
 358   }
 359   return(pos - buffer);
 360 }
 361 
 362 
 363 struct rtable *
 364 rt_route(unsigned long daddr, struct options *opt)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366   struct rtable *rt;
 367   int type;
 368 
 369   /*
 370    * This is a hack, I think. -FvK
 371    */
 372   if ((type=chk_addr(daddr)) == IS_MYADDR) daddr = my_addr();
 373 
 374   /*
 375    * Loop over the IP routing table to find a route suitable
 376    * for this packet.  Note that we really should have a look
 377    * at the IP options to see if we have been given a hint as
 378    * to what kind of path we should use... -FvK
 379    */
 380   for (rt = rt_base; rt != NULL; rt = rt->rt_next)
 381         if ((rt->rt_flags & RTF_HOST) && rt->rt_dst == daddr) {
 382                 DPRINTF((DBG_RT, "%s (%s)\n",
 383                         rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
 384                 rt->rt_use++;
 385                 return(rt);
 386         }
 387   for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
 388         DPRINTF((DBG_RT, "RT: %s via ", in_ntoa(daddr)));
 389         if (!(rt->rt_flags & RTF_HOST) && ip_addr_match(rt->rt_dst, daddr)) {
 390                 DPRINTF((DBG_RT, "%s (%s)\n",
 391                         rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
 392                 rt->rt_use++;
 393                 return(rt);
 394         }
 395         if (type==IS_BROADCAST && (rt->rt_dev->flags & IFF_BROADCAST) &&
 396             ip_addr_match(rt->rt_dev->pa_brdaddr, daddr)) {
 397                 DPRINTF((DBG_RT, "%s (BCAST %s)\n",
 398                         rt->rt_dev->name, in_ntoa(rt->rt_dev->pa_brdaddr)));
 399                 rt->rt_use++;
 400                 return(rt);
 401         }
 402   }
 403 
 404   DPRINTF((DBG_RT, "NONE\n"));
 405   return(NULL);
 406 };
 407 
 408 
 409 int
 410 rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412   struct device *dev;
 413   struct rtentry rt;
 414   char namebuf[32];
 415   int ret;
 416   int err;
 417 
 418   switch(cmd) {
 419         case DDIOCSDBG:
 420                 ret = dbg_ioctl(arg, DBG_RT);
 421                 break;
 422         case SIOCADDRT:
 423         case SIOCDELRT:
 424                 if (!suser()) return(-EPERM);
 425                 err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
 426                 if(err)
 427                         return err;
 428                 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
 429                 if (rt.rt_dev) {
 430                     err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
 431                     if(err)
 432                         return err;
 433                     memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
 434                     dev = dev_get(namebuf);
 435                     rt.rt_dev = dev;
 436                 }
 437                 ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
 438                 break;
 439         default:
 440                 ret = -EINVAL;
 441   }
 442 
 443   return(ret);
 444 }

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