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

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