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. ip_rt_flush
  4. default_mask
  5. guess_mask
  6. get_gw_dev
  7. ip_rt_add
  8. bad_mask
  9. rt_new
  10. rt_kill
  11. rt_get_info
  12. ip_rt_route
  13. ip_get_old_rtent
  14. ip_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  *              Alan Cox, <gw4pts@gw4pts.ampr.org>
  13  *              Linus Torvalds, <Linus.Torvalds@helsinki.fi>
  14  *
  15  * Fixes:
  16  *              Alan Cox        :       Verify area fixes.
  17  *              Alan Cox        :       cli() protects routing changes
  18  *              Rui Oliveira    :       ICMP routing table updates
  19  *              (rco@di.uminho.pt)      Routing table insertion and update
  20  *              Linus Torvalds  :       Rewrote bits to be sensible
  21  *              Alan Cox        :       Added BSD route gw semantics
  22  *              Alan Cox        :       Super /proc >4K 
  23  *
  24  *              This program is free software; you can redistribute it and/or
  25  *              modify it under the terms of the GNU General Public License
  26  *              as published by the Free Software Foundation; either version
  27  *              2 of the License, or (at your option) any later version.
  28  */
  29 
  30 #include <asm/segment.h>
  31 #include <asm/system.h>
  32 #include <linux/types.h>
  33 #include <linux/kernel.h>
  34 #include <linux/sched.h>
  35 #include <linux/string.h>
  36 #include <linux/socket.h>
  37 #include <linux/sockios.h>
  38 #include <linux/errno.h>
  39 #include <linux/in.h>
  40 #include <linux/inet.h>
  41 #include <linux/netdevice.h>
  42 #include "ip.h"
  43 #include "protocol.h"
  44 #include "route.h"
  45 #include "tcp.h"
  46 #include <linux/skbuff.h>
  47 #include "sock.h"
  48 #include "icmp.h"
  49 
  50 /*
  51  *      The routing table list
  52  */
  53 
  54 static struct rtable *rt_base = NULL;
  55 
  56 /*
  57  *      Pointer to the loopback route
  58  */
  59  
  60 static struct rtable *rt_loopback = NULL;
  61 
  62 /*
  63  *      Dump the contents of a routing table entry. 
  64  */
  65  
  66 static void rt_print(struct rtable *rt)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68 
  69         if (rt == NULL || inet_debug != DBG_RT) 
  70                 return;
  71 
  72         printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
  73                 (long) rt, (long) rt->rt_next, rt->rt_flags);
  74         printk("    TARGET=%s ", in_ntoa(rt->rt_dst));
  75         printk("GW=%s ", in_ntoa(rt->rt_gateway));
  76         printk("    DEV=%s USE=%ld REF=%d\n",
  77                 (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
  78                 rt->rt_use, rt->rt_refcnt);
  79 }
  80 
  81 
  82 /*
  83  *      Remove a routing table entry.
  84  */
  85 
  86 static void rt_del(unsigned long dst)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         struct rtable *r, **rp;
  89         unsigned long flags;
  90 
  91         DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
  92         rp = &rt_base;
  93         
  94         /*
  95          *      This must be done with interrupts off because we could take
  96          *      an ICMP_REDIRECT.
  97          */
  98          
  99         save_flags(flags);
 100         cli();
 101         while((r = *rp) != NULL) 
 102         {
 103                 if (r->rt_dst != dst) 
 104                 {
 105                         rp = &r->rt_next;
 106                         continue;
 107                 }
 108                 *rp = r->rt_next;
 109                 
 110                 /*
 111                  *      If we delete the loopback route update its pointer.
 112                  */
 113                  
 114                 if (rt_loopback == r)
 115                         rt_loopback = NULL;
 116                 kfree_s(r, sizeof(struct rtable));
 117         } 
 118         restore_flags(flags);
 119 }
 120 
 121 
 122 /*
 123  *      Remove all routing table entries for a device. This is called when
 124  *      a device is downed.
 125  */
 126  
 127 void ip_rt_flush(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129         struct rtable *r;
 130         struct rtable **rp;
 131         unsigned long flags;
 132 
 133         DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
 134         rp = &rt_base;
 135         cli();
 136         save_flags(flags);
 137         while ((r = *rp) != NULL) {
 138                 if (r->rt_dev != dev) {
 139                         rp = &r->rt_next;
 140                         continue;
 141                 }
 142                 *rp = r->rt_next;
 143                 if (rt_loopback == r)
 144                         rt_loopback = NULL;
 145                 kfree_s(r, sizeof(struct rtable));
 146         } 
 147         restore_flags(flags);
 148 }
 149 
 150 /*
 151  *      Used by 'rt_add()' when we can't get the netmask any other way..
 152  *
 153  *      If the lower byte or two are zero, we guess the mask based on the
 154  *      number of zero 8-bit net numbers, otherwise we use the "default"
 155  *      masks judging by the destination address and our device netmask.
 156  */
 157  
 158 static inline unsigned long default_mask(unsigned long dst)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160         dst = ntohl(dst);
 161         if (IN_CLASSA(dst))
 162                 return htonl(IN_CLASSA_NET);
 163         if (IN_CLASSB(dst))
 164                 return htonl(IN_CLASSB_NET);
 165         return htonl(IN_CLASSC_NET);
 166 }
 167 
 168 
 169 /*
 170  *      If no mask is specified then generate a default entry.
 171  */
 172 
 173 static unsigned long guess_mask(unsigned long dst, struct device * dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175         unsigned long mask;
 176 
 177         if (!dst)
 178                 return 0;
 179         mask = default_mask(dst);
 180         if ((dst ^ dev->pa_addr) & mask)
 181                 return mask;
 182         return dev->pa_mask;
 183 }
 184 
 185 
 186 /*
 187  *      Find the route entry through which our gateway will be reached
 188  */
 189  
 190 static inline struct device * get_gw_dev(unsigned long gw)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         struct rtable * rt;
 193 
 194         for (rt = rt_base ; ; rt = rt->rt_next) 
 195         {
 196                 if (!rt)
 197                         return NULL;
 198                 if ((gw ^ rt->rt_dst) & rt->rt_mask)
 199                         continue;
 200                 /* 
 201                  *      Gateways behind gateways are a no-no 
 202                  */
 203                  
 204                 if (rt->rt_flags & RTF_GATEWAY)
 205                         return NULL;
 206                 return rt->rt_dev;
 207         }
 208 }
 209 
 210 /*
 211  *      Rewrote rt_add(), as the old one was weird - Linus
 212  *
 213  *      This routine is used to update the IP routing table, either
 214  *      from the kernel (ICMP_REDIRECT) or via an ioctl call issued
 215  *      by the superuser.
 216  */
 217  
 218 void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
     /* [previous][next][first][last][top][bottom][index][help] */
 219         unsigned long gw, struct device *dev)
 220 {
 221         struct rtable *r, *rt;
 222         struct rtable **rp;
 223         unsigned long cpuflags;
 224 
 225         /*
 226          *      A host is a unique machine and has no network bits.
 227          */
 228          
 229         if (flags & RTF_HOST) 
 230         {
 231                 mask = 0xffffffff;
 232         } 
 233         
 234         /*
 235          *      Calculate the network mask
 236          */
 237          
 238         else if (!mask) 
 239         {
 240                 if (!((dst ^ dev->pa_addr) & dev->pa_mask)) 
 241                 {
 242                         mask = dev->pa_mask;
 243                         flags &= ~RTF_GATEWAY;
 244                         if (flags & RTF_DYNAMIC) 
 245                         {
 246                                 /*printk("Dynamic route to my own net rejected\n");*/
 247                                 return;
 248                         }
 249                 } 
 250                 else
 251                         mask = guess_mask(dst, dev);
 252                 dst &= mask;
 253         }
 254         
 255         /*
 256          *      A gateway must be reachable and not a local address
 257          */
 258          
 259         if (gw == dev->pa_addr)
 260                 flags &= ~RTF_GATEWAY;
 261                 
 262         if (flags & RTF_GATEWAY) 
 263         {
 264                 /*
 265                  *      Don't try to add a gateway we can't reach.. 
 266                  */
 267                  
 268                 if (dev != get_gw_dev(gw))
 269                         return;
 270                         
 271                 flags |= RTF_GATEWAY;
 272         } 
 273         else
 274                 gw = 0;
 275                 
 276         /*
 277          *      Allocate an entry and fill it in.
 278          */
 279          
 280         rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
 281         if (rt == NULL) 
 282         {
 283                 DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
 284                 return;
 285         }
 286         memset(rt, 0, sizeof(struct rtable));
 287         rt->rt_flags = flags | RTF_UP;
 288         rt->rt_dst = dst;
 289         rt->rt_dev = dev;
 290         rt->rt_gateway = gw;
 291         rt->rt_mask = mask;
 292         rt->rt_mtu = dev->mtu;
 293         rt_print(rt);
 294 
 295         /*
 296          *      What we have to do is loop though this until we have
 297          *      found the first address which has a higher generality than
 298          *      the one in rt.  Then we can put rt in right before it.
 299          *      The interrupts must be off for this process.
 300          */
 301 
 302         save_flags(cpuflags);
 303         cli();
 304 
 305         /*
 306          *      Remove old route if we are getting a duplicate. 
 307          */
 308          
 309         rp = &rt_base;
 310         while ((r = *rp) != NULL) 
 311         {
 312                 if (r->rt_dst != dst) 
 313                 {
 314                         rp = &r->rt_next;
 315                         continue;
 316                 }
 317                 *rp = r->rt_next;
 318                 if (rt_loopback == r)
 319                         rt_loopback = NULL;
 320                 kfree_s(r, sizeof(struct rtable));
 321         }
 322         
 323         /*
 324          *      Add the new route 
 325          */
 326          
 327         rp = &rt_base;
 328         while ((r = *rp) != NULL) {
 329                 if ((r->rt_mask & mask) != mask)
 330                         break;
 331                 rp = &r->rt_next;
 332         }
 333         rt->rt_next = r;
 334         *rp = rt;
 335         
 336         /*
 337          *      Update the loopback route
 338          */
 339          
 340         if (rt->rt_dev->flags & IFF_LOOPBACK)
 341                 rt_loopback = rt;
 342                 
 343         /*
 344          *      Restore the interrupts and return
 345          */
 346          
 347         restore_flags(cpuflags);
 348         return;
 349 }
 350 
 351 
 352 /*
 353  *      Check if a mask is acceptable.
 354  */
 355  
 356 static inline int bad_mask(unsigned long mask, unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358         if (addr & (mask = ~mask))
 359                 return 1;
 360         mask = ntohl(mask);
 361         if (mask & (mask+1))
 362                 return 1;
 363         return 0;
 364 }
 365 
 366 /*
 367  *      Process a route add request from the user
 368  */
 369  
 370 static int rt_new(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 371 {
 372         int err;
 373         char * devname;
 374         struct device * dev = NULL;
 375         unsigned long flags, daddr, mask, gw;
 376 
 377         /*
 378          *      If a device is specified find it.
 379          */
 380          
 381         if ((devname = r->rt_dev) != NULL) 
 382         {
 383                 err = getname(devname, &devname);
 384                 if (err)
 385                         return err;
 386                 dev = dev_get(devname);
 387                 putname(devname);
 388                 if (!dev)
 389                         return -EINVAL;
 390         }
 391         
 392         /*
 393          *      If the device isn't INET, don't allow it
 394          */
 395 
 396         if (r->rt_dst.sa_family != AF_INET)
 397                 return -EAFNOSUPPORT;
 398 
 399         /*
 400          *      Make local copies of the important bits
 401          */
 402          
 403         flags = r->rt_flags;
 404         daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
 405         mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
 406         gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
 407 
 408 
 409         /*
 410          *      BSD emulation: Permits route add someroute gw one-of-my-addresses
 411          *      to indicate which iface. Not as clean as the nice Linux dev technique
 412          *      but people keep using it... 
 413          */
 414          
 415         if (!dev && (flags & RTF_GATEWAY)) 
 416         {
 417                 struct device *dev2;
 418                 for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) 
 419                 {
 420                         if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) 
 421                         {
 422                                 flags &= ~RTF_GATEWAY;
 423                                 dev = dev2;
 424                                 break;
 425                         }
 426                 }
 427         }
 428 
 429         /*
 430          *      Ignore faulty masks
 431          */
 432          
 433         if (bad_mask(mask, daddr))
 434                 mask = 0;
 435 
 436         /*
 437          *      Set the mask to nothing for host routes.
 438          */
 439          
 440         if (flags & RTF_HOST)
 441                 mask = 0xffffffff;
 442         else if (mask && r->rt_genmask.sa_family != AF_INET)
 443                 return -EAFNOSUPPORT;
 444 
 445         /*
 446          *      You can only gateway IP via IP..
 447          */
 448          
 449         if (flags & RTF_GATEWAY) 
 450         {
 451                 if (r->rt_gateway.sa_family != AF_INET)
 452                         return -EAFNOSUPPORT;
 453                 if (!dev)
 454                         dev = get_gw_dev(gw);
 455         } 
 456         else if (!dev)
 457                 dev = ip_dev_check(daddr);
 458 
 459         /*
 460          *      Unknown device.
 461          */
 462          
 463         if (dev == NULL)
 464                 return -ENETUNREACH;
 465 
 466         /*
 467          *      Add the route
 468          */
 469          
 470         ip_rt_add(flags, daddr, mask, gw, dev);
 471         return 0;
 472 }
 473 
 474 
 475 /*
 476  *      Remove a route, as requested by the user.
 477  */
 478 
 479 static int rt_kill(struct rtentry *r)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481         struct sockaddr_in *trg;
 482 
 483         trg = (struct sockaddr_in *) &r->rt_dst;
 484         rt_del(trg->sin_addr.s_addr);
 485         return 0;
 486 }
 487 
 488 
 489 /* 
 490  *      Called from the PROCfs module. This outputs /proc/net/route.
 491  */
 492  
 493 int rt_get_info(char *buffer, char **start, off_t offset, int length)
     /* [previous][next][first][last][top][bottom][index][help] */
 494 {
 495         struct rtable *r;
 496         int len=0;
 497         off_t pos=0;
 498         off_t begin=0;
 499         int size;
 500 
 501         len += sprintf(buffer,
 502                  "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
 503         pos=len;
 504   
 505         /*
 506          *      This isn't quite right -- r->rt_dst is a struct! 
 507          */
 508          
 509         for (r = rt_base; r != NULL; r = r->rt_next) 
 510         {
 511                 size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
 512                         r->rt_dev->name, r->rt_dst, r->rt_gateway,
 513                         r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
 514                         r->rt_mask);
 515                 len+=size;
 516                 pos+=size;
 517                 if(pos<offset)
 518                 {
 519                         len=0;
 520                         begin=pos;
 521                 }
 522                 if(pos>offset+length)
 523                         break;
 524         }
 525         
 526         *start=buffer+(offset-begin);
 527         len-=(offset-begin);
 528         if(len>length)
 529                 len=length;
 530         return len;
 531 }
 532 
 533 /*
 534  *      This is hackish, but results in better code. Use "-S" to see why.
 535  */
 536  
 537 #define early_out ({ goto no_route; 1; })
 538 
 539 /*
 540  *      Route a packet. This needs to be fairly quick. Florian & Co. 
 541  *      suggested a unified ARP and IP routing cache. Done right its
 542  *      probably a brilliant idea. I'd actually suggest a unified
 543  *      ARP/IP routing/Socket pointer cache. Volunteers welcome
 544  */
 545  
 546 struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548         struct rtable *rt;
 549 
 550         for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) 
 551         {
 552                 if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
 553                         break;
 554                 /*
 555                  *      broadcast addresses can be special cases.. 
 556                  */
 557                  
 558                 if ((rt->rt_dev->flags & IFF_BROADCAST) &&
 559                      rt->rt_dev->pa_brdaddr == daddr)
 560                         break;
 561         }
 562         
 563         if(src_addr!=NULL)
 564                 *src_addr= rt->rt_dev->pa_addr;
 565                 
 566         if (daddr == rt->rt_dev->pa_addr) {
 567                 if ((rt = rt_loopback) == NULL)
 568                         goto no_route;
 569         }
 570         rt->rt_use++;
 571         return rt;
 572 no_route:
 573         return NULL;
 574 }
 575 
 576 /*
 577  *      Backwards compatibility
 578  */
 579  
 580 static int ip_get_old_rtent(struct old_rtentry * src, struct rtentry * rt)
     /* [previous][next][first][last][top][bottom][index][help] */
 581 {
 582         int err;
 583         struct old_rtentry tmp;
 584 
 585         err=verify_area(VERIFY_READ, src, sizeof(*src));
 586         if (err)
 587                 return err;
 588         memcpy_fromfs(&tmp, src, sizeof(*src));
 589         memset(rt, 0, sizeof(*rt));
 590         rt->rt_dst = tmp.rt_dst;
 591         rt->rt_gateway = tmp.rt_gateway;
 592         rt->rt_genmask.sa_family = AF_INET;
 593         ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;
 594         rt->rt_flags = tmp.rt_flags;
 595         rt->rt_dev = tmp.rt_dev;
 596         printk("Warning: obsolete routing request made.\n");
 597         return 0;
 598 }
 599 
 600 /*
 601  *      Handle IP routing ioctl calls. These are used to manipulate the routing tables
 602  */
 603  
 604 int ip_rt_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 605 {
 606         int err;
 607         struct rtentry rt;
 608 
 609         switch(cmd) 
 610         {
 611                 case DDIOCSDBG:         /* Control debugging */
 612                         return dbg_ioctl(arg, DBG_RT);
 613         
 614                 case SIOCADDRTOLD:      /* Old style add route */
 615                 case SIOCDELRTOLD:      /* Old style delete route */
 616                         if (!suser())
 617                                 return -EPERM;
 618                         err = ip_get_old_rtent((struct old_rtentry *) arg, &rt);
 619                         if (err)
 620                                 return err;
 621                         return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);
 622 
 623                 case SIOCADDRT:         /* Add a route */
 624                 case SIOCDELRT:         /* Delete a route */
 625                         if (!suser())
 626                                 return -EPERM;
 627                         err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
 628                         if (err)
 629                                 return err;
 630                         memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
 631                         return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
 632         }
 633 
 634         return -EINVAL;
 635 }

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