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

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