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

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