home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / net / inet / route.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-13  |  9.7 KB  |  424 lines

  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.  *
  13.  * Fixes:
  14.  *        Alan Cox    :    Verify area fixes.
  15.  *        Alan Cox    :    cli() protects routing changes
  16.  *        Rui Oliveira    :    ICMP routing table updates
  17.  *        (rco@di.uminho.pt)    Routing table insertion and update
  18.  *        Linus Torvalds    :    Rewrote bits to be sensible
  19.  *
  20.  *        This program is free software; you can redistribute it and/or
  21.  *        modify it under the terms of the GNU General Public License
  22.  *        as published by the Free Software Foundation; either version
  23.  *        2 of the License, or (at your option) any later version.
  24.  */
  25. #include <asm/segment.h>
  26. #include <asm/system.h>
  27. #include <linux/types.h>
  28. #include <linux/kernel.h>
  29. #include <linux/sched.h>
  30. #include <linux/string.h>
  31. #include <linux/socket.h>
  32. #include <linux/sockios.h>
  33. #include <linux/errno.h>
  34. #include <linux/in.h>
  35. #include "inet.h"
  36. #include "dev.h"
  37. #include "ip.h"
  38. #include "protocol.h"
  39. #include "route.h"
  40. #include "tcp.h"
  41. #include "skbuff.h"
  42. #include "sock.h"
  43. #include "arp.h"
  44. #include "icmp.h"
  45.  
  46.  
  47. static struct rtable *rt_base = NULL;
  48. static struct rtable *rt_loopback = NULL;
  49.  
  50. /* Dump the contents of a routing table entry. */
  51. static void
  52. rt_print(struct rtable *rt)
  53. {
  54.   if (rt == NULL || inet_debug != DBG_RT) return;
  55.  
  56.   printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
  57.         (long) rt, (long) rt->rt_next, rt->rt_flags);
  58.   printk("    TARGET=%s ", in_ntoa(rt->rt_dst));
  59.   printk("GW=%s ", in_ntoa(rt->rt_gateway));
  60.   printk("    DEV=%s USE=%ld REF=%d\n",
  61.     (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
  62.     rt->rt_use, rt->rt_refcnt);
  63. }
  64.  
  65.  
  66. /*
  67.  * Remove a routing table entry.
  68.  */
  69. static void rt_del(unsigned long dst)
  70. {
  71.     struct rtable *r, **rp;
  72.     unsigned long flags;
  73.  
  74.     DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
  75.     rp = &rt_base;
  76.     save_flags(flags);
  77.     cli();
  78.     while((r = *rp) != NULL) {
  79.         if (r->rt_dst != dst) {
  80.             rp = &r->rt_next;
  81.             continue;
  82.         }
  83.         *rp = r->rt_next;
  84.         if (rt_loopback == r)
  85.             rt_loopback = NULL;
  86.         kfree_s(r, sizeof(struct rtable));
  87.     } 
  88.     restore_flags(flags);
  89. }
  90.  
  91.  
  92. /*
  93.  * Remove all routing table entries for a device.
  94.  */
  95. void rt_flush(struct device *dev)
  96. {
  97.     struct rtable *r;
  98.     struct rtable **rp;
  99.     unsigned long flags;
  100.  
  101.     DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
  102.     rp = &rt_base;
  103.     cli();
  104.     save_flags(flags);
  105.     while ((r = *rp) != NULL) {
  106.         if (r->rt_dev != dev) {
  107.             rp = &r->rt_next;
  108.             continue;
  109.         }
  110.         *rp = r->rt_next;
  111.         if (rt_loopback == r)
  112.             rt_loopback = NULL;
  113.         kfree_s(r, sizeof(struct rtable));
  114.     } 
  115.     restore_flags(flags);
  116. }
  117.  
  118. /*
  119.  * Used by 'rt_add()' when we can't get the netmask any other way..
  120.  *
  121.  * If the lower byte or two are zero, we guess the mask based on the
  122.  * number of zero 8-bit net numbers, otherwise we use the "default"
  123.  * masks judging by the destination address and our device netmask.
  124.  */
  125. static inline unsigned long default_mask(unsigned long dst)
  126. {
  127.     dst = ntohl(dst);
  128.     if (IN_CLASSA(dst))
  129.         return htonl(IN_CLASSA_NET);
  130.     if (IN_CLASSB(dst))
  131.         return htonl(IN_CLASSB_NET);
  132.     return htonl(IN_CLASSC_NET);
  133. }
  134.  
  135. static unsigned long guess_mask(unsigned long dst, struct device * dev)
  136. {
  137.     unsigned long mask;
  138.  
  139.     if (!dst)
  140.         return 0;
  141.     mask = default_mask(dst);
  142.     if ((dst ^ dev->pa_addr) & mask)
  143.         return mask;
  144.     return dev->pa_mask;
  145. }
  146.  
  147. static inline struct device * get_gw_dev(unsigned long gw)
  148. {
  149.     struct rtable * rt;
  150.  
  151.     for (rt = rt_base ; ; rt = rt->rt_next) {
  152.         if (!rt)
  153.             return NULL;
  154.         if ((gw ^ rt->rt_dst) & rt->rt_mask)
  155.             continue;
  156.         /* gateways behind gateways are a no-no */
  157.         if (rt->rt_flags & RTF_GATEWAY)
  158.             return NULL;
  159.         return rt->rt_dev;
  160.     }
  161. }
  162.  
  163. /*
  164.  * rewrote rt_add(), as the old one was weird. Linus
  165.  */
  166. void rt_add(short flags, unsigned long dst, unsigned long mask,
  167.     unsigned long gw, struct device *dev)
  168. {
  169.     struct rtable *r, *rt;
  170.     struct rtable **rp;
  171.     unsigned long cpuflags;
  172.  
  173.     if (flags & RTF_HOST) {
  174.         mask = 0xffffffff;
  175.     } else if (!mask) {
  176.         if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {
  177.             mask = dev->pa_mask;
  178.             flags &= ~RTF_GATEWAY;
  179.             if (flags & RTF_DYNAMIC) {
  180.                 /*printk("Dynamic route to my own net rejected\n");*/
  181.                 return;
  182.             }
  183.         } else
  184.             mask = guess_mask(dst, dev);
  185.         dst &= mask;
  186.     }
  187.     if (gw == dev->pa_addr)
  188.         flags &= ~RTF_GATEWAY;
  189.     if (flags & RTF_GATEWAY) {
  190.         /* don't try to add a gateway we can't reach.. */
  191.         if (dev != get_gw_dev(gw))
  192.             return;
  193.         flags |= RTF_GATEWAY;
  194.     } else
  195.         gw = 0;
  196.     /* Allocate an entry. */
  197.     rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
  198.     if (rt == NULL) {
  199.         DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
  200.         return;
  201.     }
  202.     memset(rt, 0, sizeof(struct rtable));
  203.     rt->rt_flags = flags | RTF_UP;
  204.     rt->rt_dst = dst;
  205.     rt->rt_dev = dev;
  206.     rt->rt_gateway = gw;
  207.     rt->rt_mask = mask;
  208.     rt->rt_mtu = dev->mtu;
  209.     rt_print(rt);
  210.     /*
  211.      * What we have to do is loop though this until we have
  212.      * found the first address which has a higher generality than
  213.      * the one in rt.  Then we can put rt in right before it.
  214.      */
  215.     save_flags(cpuflags);
  216.     cli();
  217.     /* remove old route if we are getting a duplicate. */
  218.     rp = &rt_base;
  219.     while ((r = *rp) != NULL) {
  220.         if (r->rt_dst != dst) {
  221.             rp = &r->rt_next;
  222.             continue;
  223.         }
  224.         *rp = r->rt_next;
  225.         if (rt_loopback == r)
  226.             rt_loopback = NULL;
  227.         kfree_s(r, sizeof(struct rtable));
  228.     }
  229.     /* add the new route */
  230.     rp = &rt_base;
  231.     while ((r = *rp) != NULL) {
  232.         if ((r->rt_mask & mask) != mask)
  233.             break;
  234.         rp = &r->rt_next;
  235.     }
  236.     rt->rt_next = r;
  237.     *rp = rt;
  238.     if (rt->rt_dev->flags & IFF_LOOPBACK)
  239.         rt_loopback = rt;
  240.     restore_flags(cpuflags);
  241.     return;
  242. }
  243.  
  244. static inline int bad_mask(unsigned long mask, unsigned long addr)
  245. {
  246.     if (addr & (mask = ~mask))
  247.         return 1;
  248.     mask = ntohl(mask);
  249.     if (mask & (mask+1))
  250.         return 1;
  251.     return 0;
  252. }
  253.  
  254. static int rt_new(struct rtentry *r)
  255. {
  256.     int err;
  257.     char * devname;
  258.     struct device * dev = NULL;
  259.     unsigned long flags, daddr, mask, gw;
  260.  
  261.     if ((devname = r->rt_dev) != NULL) {
  262.         err = getname(devname, &devname);
  263.         if (err)
  264.             return err;
  265.         dev = dev_get(devname);
  266.         putname(devname);
  267.         if (!dev)
  268.             return -EINVAL;
  269.     }
  270.  
  271.     if (r->rt_dst.sa_family != AF_INET)
  272.         return -EAFNOSUPPORT;
  273.  
  274.     flags = r->rt_flags;
  275.     daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
  276.     mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
  277.     gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
  278.  
  279. /* BSD emulation: Permits route add someroute gw one-of-my-addresses
  280.    to indicate which iface. Not as clean as the nice Linux dev technique
  281.    but people keep using it... */
  282.     if (!dev && (flags & RTF_GATEWAY)) {
  283.         struct device *dev2;
  284.         for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) {
  285.             if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) {
  286.                 flags &= ~RTF_GATEWAY;
  287.                 dev = dev2;
  288.                 break;
  289.             }
  290.         }
  291.     }
  292.  
  293.     if (bad_mask(mask, daddr))
  294.         mask = 0;
  295.  
  296.     if (flags & RTF_HOST)
  297.         mask = 0xffffffff;
  298.     else if (mask && r->rt_genmask.sa_family != AF_INET)
  299.         return -EAFNOSUPPORT;
  300.  
  301.     if (flags & RTF_GATEWAY) {
  302.         if (r->rt_gateway.sa_family != AF_INET)
  303.             return -EAFNOSUPPORT;
  304.         if (!dev)
  305.             dev = get_gw_dev(gw);
  306.     } else if (!dev)
  307.         dev = dev_check(daddr);
  308.  
  309.     if (dev == NULL)
  310.         return -ENETUNREACH;
  311.  
  312.     rt_add(flags, daddr, mask, gw, dev);
  313.     return 0;
  314. }
  315.  
  316.  
  317. static int rt_kill(struct rtentry *r)
  318. {
  319.     struct sockaddr_in *trg;
  320.  
  321.     trg = (struct sockaddr_in *) &r->rt_dst;
  322.     rt_del(trg->sin_addr.s_addr);
  323.     return 0;
  324. }
  325.  
  326.  
  327. /* Called from the PROCfs module. */
  328. int
  329. rt_get_info(char *buffer)
  330. {
  331.   struct rtable *r;
  332.   char *pos;
  333.  
  334.   pos = buffer;
  335.  
  336.   pos += sprintf(pos,
  337.          "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
  338.   
  339.   /* This isn't quite right -- r->rt_dst is a struct! */
  340.   for (r = rt_base; r != NULL; r = r->rt_next) {
  341.         pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
  342.         r->rt_dev->name, r->rt_dst, r->rt_gateway,
  343.         r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
  344.         r->rt_mask);
  345.   }
  346.   return(pos - buffer);
  347. }
  348.  
  349. /*
  350.  * This is hackish, but results in better code. Use "-S" to see why.
  351.  */
  352. #define early_out ({ goto no_route; 1; })
  353.  
  354. struct rtable * rt_route(unsigned long daddr, struct options *opt)
  355. {
  356.     struct rtable *rt;
  357.  
  358.     for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) {
  359.         if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
  360.             break;
  361.         /* broadcast addresses can be special cases.. */
  362.         if ((rt->rt_dev->flags & IFF_BROADCAST) &&
  363.              rt->rt_dev->pa_brdaddr == daddr)
  364.             break;
  365.     }
  366.     if (daddr == rt->rt_dev->pa_addr) {
  367.         if ((rt = rt_loopback) == NULL)
  368.             goto no_route;
  369.     }
  370.     rt->rt_use++;
  371.     return rt;
  372. no_route:
  373.     return NULL;
  374. }
  375.  
  376. static int get_old_rtent(struct old_rtentry * src, struct rtentry * rt)
  377. {
  378.     int err;
  379.     struct old_rtentry tmp;
  380.  
  381.     err=verify_area(VERIFY_READ, src, sizeof(*src));
  382.     if (err)
  383.         return err;
  384.     memcpy_fromfs(&tmp, src, sizeof(*src));
  385.     memset(rt, 0, sizeof(*rt));
  386.     rt->rt_dst = tmp.rt_dst;
  387.     rt->rt_gateway = tmp.rt_gateway;
  388.     rt->rt_genmask.sa_family = AF_INET;
  389.     ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;
  390.     rt->rt_flags = tmp.rt_flags;
  391.     rt->rt_dev = tmp.rt_dev;
  392.     return 0;
  393. }
  394.  
  395. int rt_ioctl(unsigned int cmd, void *arg)
  396. {
  397.     int err;
  398.     struct rtentry rt;
  399.  
  400.     switch(cmd) {
  401.     case DDIOCSDBG:
  402.         return dbg_ioctl(arg, DBG_RT);
  403.     case SIOCADDRTOLD:
  404.     case SIOCDELRTOLD:
  405.         if (!suser())
  406.             return -EPERM;
  407.         err = get_old_rtent((struct old_rtentry *) arg, &rt);
  408.         if (err)
  409.             return err;
  410.         return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);
  411.     case SIOCADDRT:
  412.     case SIOCDELRT:
  413.         if (!suser())
  414.             return -EPERM;
  415.         err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
  416.         if (err)
  417.             return err;
  418.         memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
  419.         return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
  420.     }
  421.  
  422.     return -EINVAL;
  423. }
  424.