ipddp.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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 <[email protected]>
  7. * - DDP-IP Decap by: Jay Schulist <[email protected]>
  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 <[email protected]>
  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 <[email protected]>
  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/compat.h>
  26. #include <linux/module.h>
  27. #include <linux/kernel.h>
  28. #include <linux/init.h>
  29. #include <linux/netdevice.h>
  30. #include <linux/etherdevice.h>
  31. #include <linux/ip.h>
  32. #include <linux/atalk.h>
  33. #include <linux/if_arp.h>
  34. #include <linux/slab.h>
  35. #include <net/route.h>
  36. #include <linux/uaccess.h>
  37. #include "ipddp.h" /* Our stuff */
  38. static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <[email protected]>\n";
  39. static struct ipddp_route *ipddp_route_list;
  40. static DEFINE_SPINLOCK(ipddp_route_lock);
  41. #ifdef CONFIG_IPDDP_ENCAP
  42. static int ipddp_mode = IPDDP_ENCAP;
  43. #else
  44. static int ipddp_mode = IPDDP_DECAP;
  45. #endif
  46. /* Index to functions, as function prototypes. */
  47. static netdev_tx_t ipddp_xmit(struct sk_buff *skb,
  48. struct net_device *dev);
  49. static int ipddp_create(struct ipddp_route *new_rt);
  50. static int ipddp_delete(struct ipddp_route *rt);
  51. static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
  52. static int ipddp_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
  53. void __user *data, int cmd);
  54. static const struct net_device_ops ipddp_netdev_ops = {
  55. .ndo_start_xmit = ipddp_xmit,
  56. .ndo_siocdevprivate = ipddp_siocdevprivate,
  57. .ndo_set_mac_address = eth_mac_addr,
  58. .ndo_validate_addr = eth_validate_addr,
  59. };
  60. static struct net_device * __init ipddp_init(void)
  61. {
  62. static unsigned version_printed;
  63. struct net_device *dev;
  64. int err;
  65. dev = alloc_etherdev(0);
  66. if (!dev)
  67. return ERR_PTR(-ENOMEM);
  68. netif_keep_dst(dev);
  69. strcpy(dev->name, "ipddp%d");
  70. if (version_printed++ == 0)
  71. printk(version);
  72. /* Initialize the device structure. */
  73. dev->netdev_ops = &ipddp_netdev_ops;
  74. dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */
  75. dev->mtu = 585;
  76. dev->flags |= IFF_NOARP;
  77. /*
  78. * The worst case header we will need is currently a
  79. * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
  80. * We send over SNAP so that takes another 8 bytes.
  81. */
  82. dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
  83. err = register_netdev(dev);
  84. if (err) {
  85. free_netdev(dev);
  86. return ERR_PTR(err);
  87. }
  88. /* Let the user now what mode we are in */
  89. if(ipddp_mode == IPDDP_ENCAP)
  90. printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <[email protected]>\n",
  91. dev->name);
  92. if(ipddp_mode == IPDDP_DECAP)
  93. printk("%s: Appletalk-IP Decap. mode by Jay Schulist <[email protected]>\n",
  94. dev->name);
  95. return dev;
  96. }
  97. /*
  98. * Transmit LLAP/ELAP frame using aarp_send_ddp.
  99. */
  100. static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
  101. {
  102. struct rtable *rtable = skb_rtable(skb);
  103. __be32 paddr = 0;
  104. struct ddpehdr *ddp;
  105. struct ipddp_route *rt;
  106. struct atalk_addr *our_addr;
  107. if (rtable->rt_gw_family == AF_INET)
  108. paddr = rtable->rt_gw4;
  109. spin_lock(&ipddp_route_lock);
  110. /*
  111. * Find appropriate route to use, based only on IP number.
  112. */
  113. for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
  114. {
  115. if(rt->ip == paddr)
  116. break;
  117. }
  118. if(rt == NULL) {
  119. spin_unlock(&ipddp_route_lock);
  120. return NETDEV_TX_OK;
  121. }
  122. our_addr = atalk_find_dev_addr(rt->dev);
  123. if(ipddp_mode == IPDDP_DECAP)
  124. /*
  125. * Pull off the excess room that should not be there.
  126. * This is due to a hard-header problem. This is the
  127. * quick fix for now though, till it breaks.
  128. */
  129. skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
  130. /* Create the Extended DDP header */
  131. ddp = (struct ddpehdr *)skb->data;
  132. ddp->deh_len_hops = htons(skb->len + (1<<10));
  133. ddp->deh_sum = 0;
  134. /*
  135. * For Localtalk we need aarp_send_ddp to strip the
  136. * long DDP header and place a shot DDP header on it.
  137. */
  138. if(rt->dev->type == ARPHRD_LOCALTLK)
  139. {
  140. ddp->deh_dnet = 0; /* FIXME more hops?? */
  141. ddp->deh_snet = 0;
  142. }
  143. else
  144. {
  145. ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */
  146. ddp->deh_snet = our_addr->s_net;
  147. }
  148. ddp->deh_dnode = rt->at.s_node;
  149. ddp->deh_snode = our_addr->s_node;
  150. ddp->deh_dport = 72;
  151. ddp->deh_sport = 72;
  152. *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
  153. skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
  154. dev->stats.tx_packets++;
  155. dev->stats.tx_bytes += skb->len;
  156. aarp_send_ddp(rt->dev, skb, &rt->at, NULL);
  157. spin_unlock(&ipddp_route_lock);
  158. return NETDEV_TX_OK;
  159. }
  160. /*
  161. * Create a routing entry. We first verify that the
  162. * record does not already exist. If it does we return -EEXIST
  163. */
  164. static int ipddp_create(struct ipddp_route *new_rt)
  165. {
  166. struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL);
  167. if (rt == NULL)
  168. return -ENOMEM;
  169. rt->ip = new_rt->ip;
  170. rt->at = new_rt->at;
  171. rt->next = NULL;
  172. if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
  173. kfree(rt);
  174. return -ENETUNREACH;
  175. }
  176. spin_lock_bh(&ipddp_route_lock);
  177. if (__ipddp_find_route(rt)) {
  178. spin_unlock_bh(&ipddp_route_lock);
  179. kfree(rt);
  180. return -EEXIST;
  181. }
  182. rt->next = ipddp_route_list;
  183. ipddp_route_list = rt;
  184. spin_unlock_bh(&ipddp_route_lock);
  185. return 0;
  186. }
  187. /*
  188. * Delete a route, we only delete a FULL match.
  189. * If route does not exist we return -ENOENT.
  190. */
  191. static int ipddp_delete(struct ipddp_route *rt)
  192. {
  193. struct ipddp_route **r = &ipddp_route_list;
  194. struct ipddp_route *tmp;
  195. spin_lock_bh(&ipddp_route_lock);
  196. while((tmp = *r) != NULL)
  197. {
  198. if(tmp->ip == rt->ip &&
  199. tmp->at.s_net == rt->at.s_net &&
  200. tmp->at.s_node == rt->at.s_node)
  201. {
  202. *r = tmp->next;
  203. spin_unlock_bh(&ipddp_route_lock);
  204. kfree(tmp);
  205. return 0;
  206. }
  207. r = &tmp->next;
  208. }
  209. spin_unlock_bh(&ipddp_route_lock);
  210. return -ENOENT;
  211. }
  212. /*
  213. * Find a routing entry, we only return a FULL match
  214. */
  215. static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
  216. {
  217. struct ipddp_route *f;
  218. for(f = ipddp_route_list; f != NULL; f = f->next)
  219. {
  220. if(f->ip == rt->ip &&
  221. f->at.s_net == rt->at.s_net &&
  222. f->at.s_node == rt->at.s_node)
  223. return f;
  224. }
  225. return NULL;
  226. }
  227. static int ipddp_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
  228. void __user *data, int cmd)
  229. {
  230. struct ipddp_route rcp, rcp2, *rp;
  231. if (in_compat_syscall())
  232. return -EOPNOTSUPP;
  233. if(!capable(CAP_NET_ADMIN))
  234. return -EPERM;
  235. if (copy_from_user(&rcp, data, sizeof(rcp)))
  236. return -EFAULT;
  237. switch(cmd)
  238. {
  239. case SIOCADDIPDDPRT:
  240. return ipddp_create(&rcp);
  241. case SIOCFINDIPDDPRT:
  242. spin_lock_bh(&ipddp_route_lock);
  243. rp = __ipddp_find_route(&rcp);
  244. if (rp) {
  245. memset(&rcp2, 0, sizeof(rcp2));
  246. rcp2.ip = rp->ip;
  247. rcp2.at = rp->at;
  248. rcp2.flags = rp->flags;
  249. }
  250. spin_unlock_bh(&ipddp_route_lock);
  251. if (rp) {
  252. if (copy_to_user(data, &rcp2,
  253. sizeof(struct ipddp_route)))
  254. return -EFAULT;
  255. return 0;
  256. } else
  257. return -ENOENT;
  258. case SIOCDELIPDDPRT:
  259. return ipddp_delete(&rcp);
  260. default:
  261. return -EINVAL;
  262. }
  263. }
  264. static struct net_device *dev_ipddp;
  265. MODULE_LICENSE("GPL");
  266. module_param(ipddp_mode, int, 0);
  267. static int __init ipddp_init_module(void)
  268. {
  269. dev_ipddp = ipddp_init();
  270. return PTR_ERR_OR_ZERO(dev_ipddp);
  271. }
  272. static void __exit ipddp_cleanup_module(void)
  273. {
  274. struct ipddp_route *p;
  275. unregister_netdev(dev_ipddp);
  276. free_netdev(dev_ipddp);
  277. while (ipddp_route_list) {
  278. p = ipddp_route_list->next;
  279. kfree(ipddp_route_list);
  280. ipddp_route_list = p;
  281. }
  282. }
  283. module_init(ipddp_init_module);
  284. module_exit(ipddp_cleanup_module);