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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * DLCI Implementation of Frame Relay protocol for Linux, according to
  3.  * RFC 1490.  This generic device provides en/decapsulation for an
  4.  * underlying hardware driver.  Routes & IPs are assigned to these
  5.  * interfaces.  Requires 'dlcicfg' program to create usable 
  6.  * interfaces, the initial one, 'dlci' is for IOCTL use only.
  7.  *
  8.  * Version: @(#)dlci.c 0.35 4 Jan 1997
  9.  *
  10.  * Author: Mike McLagan <mike.mclagan@linux.org>
  11.  *
  12.  * Changes:
  13.  *
  14.  * 0.15 Mike Mclagan Packet freeing, bug in kmalloc call
  15.  * DLCI_RET handling
  16.  * 0.20 Mike McLagan More conservative on which packets
  17.  * are returned for retry and whic are
  18.  * are dropped.  If DLCI_RET_DROP is
  19.  * returned from the FRAD, the packet is
  20.  *   sent back to Linux for re-transmission
  21.  * 0.25 Mike McLagan Converted to use SIOC IOCTL calls
  22.  * 0.30 Jim Freeman Fixed to allow IPX traffic
  23.  * 0.35 Michael Elizabeth Fixed incorrect memcpy_fromfs
  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. #include <linux/config.h> /* for CONFIG_DLCI_COUNT */
  31. #include <linux/module.h>
  32. #include <linux/kernel.h>
  33. #include <linux/sched.h>
  34. #include <linux/types.h>
  35. #include <linux/fcntl.h>
  36. #include <linux/interrupt.h>
  37. #include <linux/ptrace.h>
  38. #include <linux/ioport.h>
  39. #include <linux/in.h>
  40. #include <linux/slab.h>
  41. #include <linux/string.h>
  42. #include <linux/init.h>
  43. #include <asm/system.h>
  44. #include <asm/bitops.h>
  45. #include <asm/io.h>
  46. #include <asm/dma.h>
  47. #include <asm/uaccess.h>
  48. #include <linux/errno.h>
  49. #include <linux/netdevice.h>
  50. #include <linux/skbuff.h>
  51. #include <linux/if_arp.h>
  52. #include <linux/if_frad.h>
  53. #include <net/sock.h>
  54. static const char devname[] = "dlci";
  55. static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
  56. static struct net_device *open_dev[CONFIG_DLCI_COUNT];
  57. static char *basename[16];
  58. int dlci_init(struct net_device *dev);
  59. /* allow FRAD's to register their name as a valid FRAD */
  60. int register_frad(const char *name)
  61. {
  62. int i;
  63. if (!name)
  64. return(-EINVAL);
  65. for (i=0;i<sizeof(basename) / sizeof(char *);i++)
  66. {
  67. if (!basename[i])
  68. break;
  69. /* take care of multiple registrations */
  70. if (strcmp(basename[i], name) == 0)
  71. return(0);
  72. }
  73. if (i == sizeof(basename) / sizeof(char *))
  74. return(-EMLINK);
  75. basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
  76. if (!basename[i])
  77. return(-ENOMEM);
  78. strcpy(basename[i], name);
  79. return(0);
  80. }
  81. int unregister_frad(const char *name)
  82. {
  83. int i;
  84. if (!name)
  85. return(-EINVAL);
  86. for (i=0;i<sizeof(basename) / sizeof(char *);i++)
  87. if (basename[i] && (strcmp(basename[i], name) == 0))
  88. break;
  89. if (i == sizeof(basename) / sizeof(char *))
  90. return(-EINVAL);
  91. kfree(basename[i]);
  92. basename[i] = NULL;
  93. return(0);
  94. }
  95. /* 
  96.  * these encapsulate the RFC 1490 requirements as well as 
  97.  * deal with packet transmission and reception, working with
  98.  * the upper network layers 
  99.  */
  100. static int dlci_header(struct sk_buff *skb, struct net_device *dev, 
  101.                            unsigned short type, void *daddr, void *saddr, 
  102.                            unsigned len)
  103. {
  104. struct frhdr hdr;
  105. struct dlci_local *dlp;
  106. unsigned int hlen;
  107. char *dest;
  108. dlp = dev->priv;
  109. hdr.control = FRAD_I_UI;
  110. switch(type)
  111. {
  112. case ETH_P_IP:
  113. hdr.IP_NLPID = FRAD_P_IP;
  114. hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
  115. break;
  116. /* feel free to add other types, if necessary */
  117. default:
  118. hdr.pad = FRAD_P_PADDING;
  119. hdr.NLPID = FRAD_P_SNAP;
  120. memset(hdr.OUI, 0, sizeof(hdr.OUI));
  121. hdr.PID = htons(type);
  122. hlen = sizeof(hdr);
  123. break;
  124. }
  125. dest = skb_push(skb, hlen);
  126. if (!dest)
  127. return(0);
  128. memcpy(dest, &hdr, hlen);
  129. return(hlen);
  130. }
  131. static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
  132. {
  133. struct dlci_local *dlp;
  134. struct frhdr *hdr;
  135. int process, header;
  136. dlp = dev->priv;
  137. hdr = (struct frhdr *) skb->data;
  138. process = 0;
  139. header = 0;
  140. skb->dev = dev;
  141. if (hdr->control != FRAD_I_UI)
  142. {
  143. printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.n", dev->name, hdr->control);
  144. dlp->stats.rx_errors++;
  145. }
  146. else
  147. switch(hdr->IP_NLPID)
  148. {
  149. case FRAD_P_PADDING:
  150. if (hdr->NLPID != FRAD_P_SNAP)
  151. {
  152. printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.n", dev->name, hdr->NLPID);
  153. dlp->stats.rx_errors++;
  154. break;
  155. }
  156.  
  157. if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
  158. {
  159. printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
  160. dlp->stats.rx_errors++;
  161. break;
  162. }
  163. /* at this point, it's an EtherType frame */
  164. header = sizeof(struct frhdr);
  165. /* Already in network order ! */
  166. skb->protocol = hdr->PID;
  167. process = 1;
  168. break;
  169. case FRAD_P_IP:
  170. header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
  171. skb->protocol = htons(ETH_P_IP);
  172. process = 1;
  173. break;
  174. case FRAD_P_SNAP:
  175. case FRAD_P_Q933:
  176. case FRAD_P_CLNP:
  177. printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.n", dev->name, hdr->pad);
  178. dlp->stats.rx_errors++;
  179. break;
  180. default:
  181. printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.n", dev->name, hdr->pad);
  182. dlp->stats.rx_errors++;
  183. break;
  184. }
  185. if (process)
  186. {
  187. /* we've set up the protocol, so discard the header */
  188. skb->mac.raw = skb->data; 
  189. skb_pull(skb, header);
  190. dlp->stats.rx_bytes += skb->len;
  191. netif_rx(skb);
  192. dlp->stats.rx_packets++;
  193. dev->last_rx = jiffies;
  194. }
  195. else
  196. dev_kfree_skb(skb);
  197. }
  198. static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
  199. {
  200. struct dlci_local *dlp;
  201. int ret;
  202. ret = 0;
  203. if (!skb || !dev)
  204. return(0);
  205. dlp = dev->priv;
  206. netif_stop_queue(dev);
  207. ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
  208. switch (ret)
  209. {
  210. case DLCI_RET_OK:
  211. dlp->stats.tx_packets++;
  212. ret = 0;
  213. break;
  214. case DLCI_RET_ERR:
  215. dlp->stats.tx_errors++;
  216. ret = 0;
  217. break;
  218. case DLCI_RET_DROP:
  219. dlp->stats.tx_dropped++;
  220. ret = 1;
  221. break;
  222. }
  223. /* Alan Cox recommends always returning 0, and always freeing the packet */
  224. /* experience suggest a slightly more conservative approach */
  225. if (!ret)
  226. {
  227. dev_kfree_skb(skb);
  228. netif_wake_queue(dev);
  229. }
  230. return(ret);
  231. }
  232. int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get)
  233. {
  234. struct dlci_conf config;
  235. struct dlci_local *dlp;
  236. struct frad_local *flp;
  237. int err;
  238. dlp = dev->priv;
  239. flp = dlp->slave->priv;
  240. if (!get)
  241. {
  242. if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
  243. return -EFAULT;
  244. if (config.flags & ~DLCI_VALID_FLAGS)
  245. return(-EINVAL);
  246. memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
  247. dlp->configured = 1;
  248. }
  249. err = (*flp->dlci_conf)(dlp->slave, dev, get);
  250. if (err)
  251. return(err);
  252. if (get)
  253. {
  254. if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
  255. return -EFAULT;
  256. }
  257. return(0);
  258. }
  259. int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  260. {
  261. struct dlci_local *dlp;
  262. if (!capable(CAP_NET_ADMIN))
  263. return(-EPERM);
  264. dlp = dev->priv;
  265. switch(cmd)
  266. {
  267. case DLCI_GET_SLAVE:
  268. if (!*(short *)(dev->dev_addr))
  269. return(-EINVAL);
  270. strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
  271. break;
  272. case DLCI_GET_CONF:
  273. case DLCI_SET_CONF:
  274. if (!*(short *)(dev->dev_addr))
  275. return(-EINVAL);
  276. return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
  277. break;
  278. default: 
  279. return(-EOPNOTSUPP);
  280. }
  281. return(0);
  282. }
  283. static int dlci_change_mtu(struct net_device *dev, int new_mtu)
  284. {
  285. struct dlci_local *dlp;
  286. dlp = dev->priv;
  287. return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
  288. }
  289. static int dlci_open(struct net_device *dev)
  290. {
  291. struct dlci_local *dlp;
  292. struct frad_local *flp;
  293. int err;
  294. dlp = dev->priv;
  295. if (!*(short *)(dev->dev_addr))
  296. return(-EINVAL);
  297. if (!netif_running(dlp->slave))
  298. return(-ENOTCONN);
  299. flp = dlp->slave->priv;
  300. err = (*flp->activate)(dlp->slave, dev);
  301. if (err)
  302. return(err);
  303. netif_start_queue(dev);
  304. return 0;
  305. }
  306. static int dlci_close(struct net_device *dev)
  307. {
  308. struct dlci_local *dlp;
  309. struct frad_local *flp;
  310. int err;
  311. netif_stop_queue(dev);
  312. dlp = dev->priv;
  313. flp = dlp->slave->priv;
  314. err = (*flp->deactivate)(dlp->slave, dev);
  315. return 0;
  316. }
  317. static struct net_device_stats *dlci_get_stats(struct net_device *dev)
  318. {
  319. struct dlci_local *dlp;
  320. dlp = dev->priv;
  321. return(&dlp->stats);
  322. }
  323. int dlci_add(struct dlci_add *dlci)
  324. {
  325. struct net_device *master, *slave;
  326. struct dlci_local *dlp;
  327. struct frad_local *flp;
  328. int err, i;
  329. char buf[10];
  330. /* validate slave device */
  331. slave = __dev_get_by_name(dlci->devname);
  332. if (!slave)
  333. return(-ENODEV);
  334. if (slave->type != ARPHRD_FRAD)
  335. return(-EINVAL);
  336. /* check for registration */
  337. for (i=0;i<sizeof(basename) / sizeof(char *); i++)
  338. if ((basename[i]) && 
  339.  (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) && 
  340.  (strlen(dlci->devname) > strlen(basename[i])))
  341. break;
  342. if (i == sizeof(basename) / sizeof(char *))
  343. return(-EINVAL);
  344. /* check for too many open devices : should this be dynamic ? */
  345. for(i=0;i<CONFIG_DLCI_COUNT;i++)
  346. if (!open_dev[i])
  347. break;
  348. if (i == CONFIG_DLCI_COUNT)
  349. return(-ENOSPC);  /*  #### Alan: Comments on this?? */
  350. /* create device name */
  351. sprintf(buf, "%s%02i", devname, i);
  352. master = kmalloc(sizeof(*master), GFP_KERNEL);
  353. if (!master)
  354. return(-ENOMEM);
  355. memset(master, 0, sizeof(*master));
  356. strcpy(master->name, buf);
  357. master->init = dlci_init;
  358. master->flags = 0;
  359. err = register_netdev(master);
  360. if (err < 0)
  361. {
  362. kfree(master);
  363. return(err);
  364. }
  365. *(short *)(master->dev_addr) = dlci->dlci;
  366. dlp = (struct dlci_local *) master->priv;
  367. dlp->slave = slave;
  368. flp = slave->priv;
  369. err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
  370. if (err < 0)
  371. {
  372. unregister_netdev(master);
  373. kfree(master->priv);
  374. kfree(master);
  375. return(err);
  376. }
  377. strcpy(dlci->devname, buf);
  378. open_dev[i] = master;
  379. MOD_INC_USE_COUNT;
  380. return(0);
  381. }
  382. int dlci_del(struct dlci_add *dlci)
  383. {
  384. struct dlci_local *dlp;
  385. struct frad_local *flp;
  386. struct net_device *master, *slave;
  387. int i, err;
  388. /* validate slave device */
  389. master = __dev_get_by_name(dlci->devname);
  390. if (!master)
  391. return(-ENODEV);
  392. if (netif_running(master))
  393. return(-EBUSY);
  394. dlp = master->priv;
  395. slave = dlp->slave;
  396. flp = slave->priv;
  397. err = (*flp->deassoc)(slave, master);
  398. if (err)
  399. return(err);
  400. unregister_netdev(master);
  401. for(i=0;i<CONFIG_DLCI_COUNT;i++)
  402. if (master == open_dev[i])
  403. break;
  404. if (i<CONFIG_DLCI_COUNT)
  405. open_dev[i] = NULL;
  406. kfree(master->priv);
  407. kfree(master);
  408. MOD_DEC_USE_COUNT;
  409. return(0);
  410. }
  411. int dlci_ioctl(unsigned int cmd, void *arg)
  412. {
  413. struct dlci_add add;
  414. int err;
  415. if (!capable(CAP_NET_ADMIN))
  416. return(-EPERM);
  417. if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
  418. return -EFAULT;
  419. switch (cmd)
  420. {
  421. case SIOCADDDLCI:
  422. err = dlci_add(&add);
  423. if (!err)
  424. if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
  425. return -EFAULT;
  426. break;
  427. case SIOCDELDLCI:
  428. err = dlci_del(&add);
  429. break;
  430. default:
  431. err = -EINVAL;
  432. }
  433. return(err);
  434. }
  435. int dlci_init(struct net_device *dev)
  436. {
  437. struct dlci_local *dlp;
  438. dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
  439. if (!dev->priv)
  440. return(-ENOMEM);
  441. memset(dev->priv, 0, sizeof(struct dlci_local));
  442. dlp = dev->priv;
  443. dev->flags = 0;
  444. dev->open = dlci_open;
  445. dev->stop = dlci_close;
  446. dev->do_ioctl = dlci_dev_ioctl;
  447. dev->hard_start_xmit = dlci_transmit;
  448. dev->hard_header = dlci_header;
  449. dev->get_stats = dlci_get_stats;
  450. dev->change_mtu = dlci_change_mtu;
  451. dlp->receive = dlci_receive;
  452. dev->type = ARPHRD_DLCI;
  453. dev->hard_header_len = sizeof(struct frhdr);
  454. dev->addr_len = sizeof(short);
  455. memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
  456. return(0);
  457. }
  458. int __init dlci_setup(void)
  459. {
  460. int i;
  461. printk("%s.n", version);
  462. for(i=0;i<CONFIG_DLCI_COUNT;i++)
  463. open_dev[i] = NULL;
  464. for(i=0;i<sizeof(basename) / sizeof(char *);i++)
  465. basename[i] = NULL;
  466. return(0);
  467. }
  468. #ifdef MODULE
  469. extern int (*dlci_ioctl_hook)(unsigned int, void *);
  470. int init_module(void)
  471. {
  472. dlci_ioctl_hook = dlci_ioctl;
  473. return(dlci_setup());
  474. }
  475. void cleanup_module(void)
  476. {
  477. dlci_ioctl_hook = NULL;
  478. }
  479. #endif /* MODULE */
  480. MODULE_AUTHOR("Mike McLagan");
  481. MODULE_DESCRIPTION("Frame Relay DLCI layer");
  482. MODULE_LICENSE("GPL");