root/net/inet/route.c

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

DEFINITIONS

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

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