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

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