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

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