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) return;
  74 
  75   save_flags(flags);
  76   cli();
  77   p = NULL;
  78   while(r != NULL) {
  79         if (r->rt_dst == dst) {
  80                 if (p == NULL) rt_base = r->rt_next;
  81                   else p->rt_next = r->rt_next;
  82                 x = r->rt_next;
  83                 kfree_s(r, sizeof(struct rtable));
  84                 r = x;
  85         } else {
  86                 p = r;
  87                 r = r->rt_next;
  88         }
  89   }
  90   restore_flags(flags);
  91 }
  92 
  93 
  94 /* Remove all routing table entries for a device. */
  95 void
  96 rt_flush(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98   struct rtable *r, *x, *p;
  99   unsigned long flags;
 100   
 101   DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
 102   if ((r = rt_base) == NULL) return;
 103   
 104   cli();
 105   save_flags(flags);
 106   
 107   p = NULL;
 108   while(r != NULL) {
 109         if (r->rt_dev == dev) {
 110                 if (p == NULL) rt_base = r->rt_next;
 111                   else p->rt_next = r->rt_next;
 112                 x = r->rt_next;
 113                 kfree_s(r, sizeof(struct rtable));
 114                 r = x;
 115         } else {
 116                 p = r;
 117                 r = r->rt_next;
 118         }
 119   }
 120   restore_flags(flags);
 121 }
 122 
 123 
 124 void
 125 rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127   struct rtable *r, *r1;
 128   struct rtable *rt;
 129   int mask;
 130   unsigned long cpuflags;
 131 
 132   /* Allocate an entry. */
 133   rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
 134   if (rt == NULL) {
 135         DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
 136         return;
 137   }
 138 
 139   /* Fill in the fields. */
 140   memset(rt, 0, sizeof(struct rtable));
 141   rt->rt_flags = (flags | RTF_UP);
 142   if (gw != 0) rt->rt_flags |= RTF_GATEWAY;
 143   rt->rt_dev = dev;
 144   rt->rt_gateway = gw;
 145 
 146   /*
 147    * If this is coming from an ICMP redirect message, truncate
 148    * the TARGET if we are creating an entry for a NETWORK. Use
 149    * an Internet class C network mask.  Yuck :-(
 150    */
 151   if (flags & RTF_DYNAMIC) {
 152         if (flags & RTF_HOST)
 153                 rt->rt_dst = dst;
 154         else{
 155                 rt->rt_dst = (dst & dev->pa_mask);
 156                 /* We don't want new routes to our own net*/
 157                 if(rt->rt_dst == (dev->pa_addr & dev->pa_mask)){
 158                         kfree_s(rt, sizeof(struct rtable));
 159                         /*printk("Dynamic route to my own net rejected\n");*/
 160                         return;
 161                 }
 162         }
 163   } else rt->rt_dst = dst;
 164 
 165   rt_print(rt);
 166 
 167   if (rt_base == NULL) {
 168         rt->rt_next = NULL;
 169         rt_base = rt;
 170         return;
 171   }
 172 
 173   /*
 174    * What we have to do is loop though this until we have
 175    * found the first address which has the same generality
 176    * as the one in rt.  Then we can put rt in after it.
 177    */
 178   for (mask = 0xff000000L; mask != 0xffffffffL; mask = (mask >> 8) | mask) {
 179         if (mask & dst) {
 180                 mask = mask << 8;
 181                 break;
 182         }
 183   }
 184   DPRINTF((DBG_RT, "RT: mask = %X\n", mask));
 185   
 186   save_flags(cpuflags);
 187   cli();
 188   
 189   r1 = rt_base;
 190 
 191   /* See if we are getting a duplicate. */
 192   for (r = rt_base; r != NULL; r = r->rt_next) {
 193         if (r->rt_dst == dst) {
 194                 if (r == rt_base) {
 195                         rt->rt_next = r->rt_next;
 196                         rt_base = rt;
 197                 } else {
 198                         rt->rt_next = r->rt_next;
 199                         r1->rt_next = rt;
 200                 }
 201                 kfree_s(r, sizeof(struct rtable));
 202                 restore_flags(cpuflags);
 203                 return;
 204         }
 205         r1 = r;
 206   }
 207 
 208   r1 = rt_base;
 209   for (r = rt_base; r != NULL; r = r->rt_next) {
 210         if (! (r->rt_dst & mask)) {
 211                 DPRINTF((DBG_RT, "RT: adding before r=%X\n", r));
 212                 rt_print(r);
 213                 if (r == rt_base) {
 214                         rt->rt_next = rt_base;
 215                         rt_base = rt;
 216                         restore_flags(cpuflags);
 217                         return;
 218                 }
 219                 rt->rt_next = r;
 220                 r1->rt_next = rt;
 221                 restore_flags(cpuflags);
 222                 return;
 223         }
 224         r1 = r;
 225   }
 226   DPRINTF((DBG_RT, "RT: adding after r1=%X\n", r1));
 227   rt_print(r1);
 228 
 229   /* Goes at the end. */
 230   rt->rt_next = NULL;
 231   r1->rt_next = rt;
 232 }
 233 
 234 
 235 static int
 236 rt_new(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238   struct device *dev;
 239   struct rtable *rt;
 240 
 241   if ((r->rt_dst.sa_family != AF_INET) ||
 242       (r->rt_gateway.sa_family != AF_INET)) {
 243         DPRINTF((DBG_RT, "RT: We only know about AF_INET !\n"));
 244         return(-EAFNOSUPPORT);
 245   }
 246 
 247   /*
 248    * I admit that the following bits of code were "inspired" by
 249    * the Berkeley UNIX system source code.  I could think of no
 250    * other way to find out how to make it compatible with it (I
 251    * want this to be compatible to get "routed" up and running).
 252    * -FvK
 253    */
 254 
 255   /* If we have a 'gateway' route here, check the correct address. */
 256   if (!(r->rt_flags & RTF_GATEWAY))
 257         dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
 258   else
 259         if ((rt = rt_route(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.
 260                            s_addr,NULL)))
 261             dev = rt->rt_dev;
 262         else
 263             dev = NULL;
 264 
 265   DPRINTF((DBG_RT, "RT: dev for %s gw ",
 266         in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
 267   DPRINTF((DBG_RT, "%s (0x%04X) is 0x%X (%s)\n",
 268         in_ntoa((*(struct sockaddr_in *)&r->rt_gateway).sin_addr.s_addr),
 269         r->rt_flags, dev, (dev == NULL) ? "NONE" : dev->name));
 270 
 271   if (dev == NULL) return(-ENETUNREACH);
 272 
 273   rt_add(r->rt_flags, (*(struct sockaddr_in *) &r->rt_dst).sin_addr.s_addr,
 274          (*(struct sockaddr_in *) &r->rt_gateway).sin_addr.s_addr, dev);
 275 
 276   return(0);
 277 }
 278 
 279 
 280 static int
 281 rt_kill(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283   struct sockaddr_in *trg;
 284 
 285   trg = (struct sockaddr_in *) &r->rt_dst;
 286   rt_del(trg->sin_addr.s_addr);
 287 
 288   return(0);
 289 }
 290 
 291 
 292 /* Called from the PROCfs module. */
 293 int
 294 rt_get_info(char *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296   struct rtable *r;
 297   char *pos;
 298 
 299   pos = buffer;
 300 
 301   pos += sprintf(pos,
 302                  "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\n");
 303   
 304   /* This isn't quite right -- r->rt_dst is a struct! */
 305   for (r = rt_base; r != NULL; r = r->rt_next) {
 306         pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\n",
 307                 r->rt_dev->name, r->rt_dst, r->rt_gateway,
 308                 r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric);
 309   }
 310   return(pos - buffer);
 311 }
 312 
 313 
 314 struct rtable *
 315 rt_route(unsigned long daddr, struct options *opt)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317   struct rtable *rt;
 318 
 319   /*
 320    * This is a hack, I think. -FvK
 321    */
 322   if (chk_addr(daddr) == IS_MYADDR) daddr = my_addr();
 323 
 324   /*
 325    * Loop over the IP routing table to find a route suitable
 326    * for this packet.  Note that we really should have a look
 327    * at the IP options to see if we have been given a hint as
 328    * to what kind of path we should use... -FvK
 329    */
 330   for (rt = rt_base; rt != NULL; rt = rt->rt_next)
 331         if ((rt->rt_flags & RTF_HOST) && rt->rt_dst == daddr) {
 332                 DPRINTF((DBG_RT, "%s (%s)\n",
 333                         rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
 334                 rt->rt_use++;
 335                 return(rt);
 336         }
 337   for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
 338         DPRINTF((DBG_RT, "RT: %s via ", in_ntoa(daddr)));
 339         if (!(rt->rt_flags & RTF_HOST) && ip_addr_match(rt->rt_dst, daddr)) {
 340                 DPRINTF((DBG_RT, "%s (%s)\n",
 341                         rt->rt_dev->name, in_ntoa(rt->rt_gateway)));
 342                 rt->rt_use++;
 343                 return(rt);
 344         }
 345         if ((rt->rt_dev->flags & IFF_BROADCAST) &&
 346             ip_addr_match(rt->rt_dev->pa_brdaddr, daddr)) {
 347                 DPRINTF((DBG_RT, "%s (BCAST %s)\n",
 348                         rt->rt_dev->name, in_ntoa(rt->rt_dev->pa_brdaddr)));
 349                 rt->rt_use++;
 350                 return(rt);
 351         }
 352   }
 353 
 354   DPRINTF((DBG_RT, "NONE\n"));
 355   return(NULL);
 356 };
 357 
 358 
 359 int
 360 rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 361 {
 362   struct device *dev;
 363   struct rtentry rt;
 364   char namebuf[32];
 365   int ret;
 366   int err;
 367 
 368   switch(cmd) {
 369         case DDIOCSDBG:
 370                 ret = dbg_ioctl(arg, DBG_RT);
 371                 break;
 372         case SIOCADDRT:
 373         case SIOCDELRT:
 374                 if (!suser()) return(-EPERM);
 375                 err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
 376                 if(err)
 377                         return err;
 378                 memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
 379                 if (rt.rt_dev) {
 380                     err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
 381                     if(err)
 382                         return err;
 383                     memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
 384                     dev = dev_get(namebuf);
 385                     rt.rt_dev = dev;
 386                 }
 387                 ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
 388                 break;
 389         default:
 390                 ret = -EINVAL;
 391   }
 392 
 393   return(ret);
 394 }

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