ipddp.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
  3.  *  Appletalk-IP to IP Decapsulation driver for Linux
  4.  *
  5.  * Authors:
  6.  *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
  7.  * - DDP-IP Decap by: Jay Schulist <jschlst@samba.org>
  8.  *
  9.  * Derived from:
  10.  * - Almost all code already existed in net/appletalk/ddp.c I just
  11.  *   moved/reorginized it into a driver file. Original IP-over-DDP code
  12.  *   was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
  13.  *      - skeleton.c: A network driver outline for linux.
  14.  *        Written 1993-94 by Donald Becker.
  15.  * - dummy.c: A dummy net driver. By Nick Holloway.
  16.  * - MacGate: A user space Daemon for Appletalk-IP Decap for
  17.  *   Linux by Jay Schulist <jschlst@samba.org>
  18.  *
  19.  *      Copyright 1993 United States Government as represented by the
  20.  *      Director, National Security Agency.
  21.  *
  22.  *      This software may be used and distributed according to the terms
  23.  *      of the GNU General Public License, incorporated herein by reference.
  24.  */
  25. #include <linux/config.h>
  26. #include <linux/module.h>
  27. #include <linux/kernel.h>
  28. #include <linux/init.h>
  29. #include <linux/netdevice.h>
  30. #include <linux/ip.h>
  31. #include <linux/atalk.h>
  32. #include <linux/if_arp.h>
  33. #include <net/route.h>
  34. #include <asm/uaccess.h>
  35. #include "ipddp.h" /* Our stuff */
  36. static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>n";
  37. static struct ipddp_route *ipddp_route_list;
  38. #ifdef CONFIG_IPDDP_ENCAP
  39. static int ipddp_mode = IPDDP_ENCAP;
  40. #else
  41. static int ipddp_mode = IPDDP_DECAP;
  42. #endif
  43. /* Index to functions, as function prototypes. */
  44. static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
  45. static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
  46. static int ipddp_create(struct ipddp_route *new_rt);
  47. static int ipddp_delete(struct ipddp_route *rt);
  48. static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
  49. static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
  50. static int __init ipddp_init(struct net_device *dev)
  51. {
  52. static unsigned version_printed;
  53. SET_MODULE_OWNER(dev);
  54. if (version_printed++ == 0)
  55.                 printk(version);
  56. /* Let the user now what mode we are in */
  57. if(ipddp_mode == IPDDP_ENCAP)
  58. printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>n", 
  59. dev->name);
  60. if(ipddp_mode == IPDDP_DECAP)
  61. printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>n", 
  62. dev->name);
  63. /* Fill in the device structure with ethernet-generic values. */
  64.         ether_setup(dev);
  65. /* Initalize the device structure. */
  66.         dev->hard_start_xmit = ipddp_xmit;
  67.         dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
  68.         if(!dev->priv)
  69.                 return -ENOMEM;
  70.         memset(dev->priv,0,sizeof(struct net_device_stats));
  71.         dev->get_stats      = ipddp_get_stats;
  72.         dev->do_ioctl       = ipddp_ioctl;
  73.         dev->type = ARPHRD_IPDDP;        /* IP over DDP tunnel */
  74.         dev->mtu = 585;
  75.         dev->flags |= IFF_NOARP;
  76.         /*
  77.          *      The worst case header we will need is currently a
  78.          *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
  79.          *      We send over SNAP so that takes another 8 bytes.
  80.          */
  81.         dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
  82.         return 0;
  83. }
  84. /*
  85.  * Get the current statistics. This may be called with the card open or closed.
  86.  */
  87. static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
  88. {
  89.         return dev->priv;
  90. }
  91. /*
  92.  * Transmit LLAP/ELAP frame using aarp_send_ddp.
  93.  */
  94. static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
  95. {
  96. u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
  97.         struct ddpehdr *ddp;
  98.         struct ipddp_route *rt;
  99.         struct at_addr *our_addr;
  100. /*
  101.          * Find appropriate route to use, based only on IP number.
  102.          */
  103.         for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
  104.         {
  105.                 if(rt->ip == paddr)
  106.                         break;
  107.         }
  108.         if(rt == NULL)
  109.                 return 0;
  110.         our_addr = atalk_find_dev_addr(rt->dev);
  111. if(ipddp_mode == IPDDP_DECAP)
  112. /* 
  113.  * Pull off the excess room that should not be there.
  114.  * This is due to a hard-header problem. This is the
  115.  * quick fix for now though, till it breaks.
  116.  */
  117. skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
  118. /* Create the Extended DDP header */
  119. ddp = (struct ddpehdr *)skb->data;
  120.         ddp->deh_len = skb->len;
  121.         ddp->deh_hops = 1;
  122.         ddp->deh_pad = 0;
  123.         ddp->deh_sum = 0;
  124. /*
  125.          * For Localtalk we need aarp_send_ddp to strip the
  126.          * long DDP header and place a shot DDP header on it.
  127.          */
  128.         if(rt->dev->type == ARPHRD_LOCALTLK)
  129.         {
  130.                 ddp->deh_dnet  = 0;   /* FIXME more hops?? */
  131.                 ddp->deh_snet  = 0;
  132.         }
  133.         else
  134.         {
  135.                 ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
  136.                 ddp->deh_snet  = our_addr->s_net;
  137.         }
  138.         ddp->deh_dnode = rt->at.s_node;
  139.         ddp->deh_snode = our_addr->s_node;
  140.         ddp->deh_dport = 72;
  141.         ddp->deh_sport = 72;
  142.         *((__u8 *)(ddp+1)) = 22;         /* ddp type = IP */
  143.         *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
  144.         skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
  145. ((struct net_device_stats *) dev->priv)->tx_packets++;
  146.         ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
  147.         if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
  148.                 dev_kfree_skb(skb);
  149.         return 0;
  150. }
  151. /*
  152.  * Create a routing entry. We first verify that the
  153.  * record does not already exist. If it does we return -EEXIST
  154.  */
  155. static int ipddp_create(struct ipddp_route *new_rt)
  156. {
  157.         struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
  158.         if (rt == NULL)
  159.                 return -ENOMEM;
  160.         rt->ip = new_rt->ip;
  161.         rt->at = new_rt->at;
  162.         rt->next = NULL;
  163.         if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
  164. kfree(rt);
  165.                 return -ENETUNREACH;
  166.         }
  167. if (ipddp_find_route(rt)) {
  168. kfree(rt);
  169. return -EEXIST;
  170. }
  171.         rt->next = ipddp_route_list;
  172.         ipddp_route_list = rt;
  173.         return 0;
  174. }
  175. /*
  176.  * Delete a route, we only delete a FULL match.
  177.  * If route does not exist we return -ENOENT.
  178.  */
  179. static int ipddp_delete(struct ipddp_route *rt)
  180. {
  181.         struct ipddp_route **r = &ipddp_route_list;
  182.         struct ipddp_route *tmp;
  183.         while((tmp = *r) != NULL)
  184.         {
  185.                 if(tmp->ip == rt->ip
  186.                         && tmp->at.s_net == rt->at.s_net
  187.                         && tmp->at.s_node == rt->at.s_node)
  188.                 {
  189.                         *r = tmp->next;
  190.                         kfree(tmp);
  191.                         return 0;
  192.                 }
  193.                 r = &tmp->next;
  194.         }
  195.         return (-ENOENT);
  196. }
  197. /*
  198.  * Find a routing entry, we only return a FULL match
  199.  */
  200. static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
  201. {
  202.         struct ipddp_route *f;
  203.         for(f = ipddp_route_list; f != NULL; f = f->next)
  204.         {
  205.                 if(f->ip == rt->ip
  206.                         && f->at.s_net == rt->at.s_net
  207.                         && f->at.s_node == rt->at.s_node)
  208.                         return (f);
  209.         }
  210.         return (NULL);
  211. }
  212. static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  213. {
  214.         struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
  215.         struct ipddp_route rcp;
  216.         if(!capable(CAP_NET_ADMIN))
  217.                 return -EPERM;
  218. if(copy_from_user(&rcp, rt, sizeof(rcp)))
  219. return -EFAULT;
  220.         switch(cmd)
  221.         {
  222. case SIOCADDIPDDPRT:
  223.                         return (ipddp_create(&rcp));
  224.                 case SIOCFINDIPDDPRT:
  225.                         if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
  226.                                 return -EFAULT;
  227.                         return 0;
  228.                 case SIOCDELIPDDPRT:
  229.                         return (ipddp_delete(&rcp));
  230.                 default:
  231.                         return -EINVAL;
  232.         }
  233. }
  234. static struct net_device dev_ipddp;
  235. MODULE_LICENSE("GPL");
  236. MODULE_PARM(ipddp_mode, "i");
  237. static int __init ipddp_init_module(void)
  238. {
  239. int err;
  240. dev_ipddp.init = ipddp_init;
  241. err=dev_alloc_name(&dev_ipddp, "ipddp%d");
  242.         if(err < 0)
  243.                 return err;
  244. if(register_netdev(&dev_ipddp) != 0)
  245.                 return -EIO;
  246. return 0;
  247. }
  248. static void __exit ipddp_cleanup_module(void)
  249. {
  250.         struct ipddp_route *p;
  251. unregister_netdev(&dev_ipddp);
  252.         kfree(dev_ipddp.priv);
  253.         while (ipddp_route_list) {
  254.                 p = ipddp_route_list->next;
  255.                 kfree(ipddp_route_list);
  256.                 ipddp_route_list = p;
  257.         }
  258. }
  259. module_init(ipddp_init_module);
  260. module_exit(ipddp_cleanup_module);