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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * LAPB protocol module for the COMX driver 
  3.  * for Linux kernel 2.2.X
  4.  *
  5.  * Original author: Tivadar Szemethy <tiv@itc.hu>
  6.  * Maintainer: Gergely Madarasz <gorgo@itc.hu>
  7.  *
  8.  * Copyright (C) 1997-1999 (C) ITConsult-Pro Co. <info@itc.hu>
  9.  *
  10.  * This program is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU General Public License
  12.  * as published by the Free Software Foundation; either version
  13.  * 2 of the License, or (at your option) any later version.
  14.  *
  15.  * Version 0.80 (99/06/14):
  16.  * - cleaned up the source code a bit
  17.  * - ported back to kernel, now works as non-module
  18.  *
  19.  * Changed      (00/10/29, Henner Eisen):
  20.  *  - comx_rx() / comxlapb_data_indication() return status.
  21.  * 
  22.  */
  23. #define VERSION "0.80"
  24. #include <linux/module.h>
  25. #include <linux/version.h>
  26. #include <linux/types.h>
  27. #include <linux/netdevice.h>
  28. #include <linux/proc_fs.h>
  29. #include <linux/if_arp.h>
  30. #include <linux/inetdevice.h>
  31. #include <asm/uaccess.h>
  32. #include <linux/lapb.h>
  33. #include <linux/init.h>
  34. #include "comx.h"
  35. #include "comxhw.h"
  36. static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
  37. int size, struct proc_dir_entry *dir);
  38. static void comxlapb_rx(struct net_device *dev, struct sk_buff *skb) 
  39. {
  40. if (!dev || !dev->priv) {
  41. dev_kfree_skb(skb);
  42. } else {
  43. lapb_data_received(dev->priv, skb);
  44. }
  45. }
  46. static int comxlapb_tx(struct net_device *dev) 
  47. {
  48. netif_wake_queue(dev);
  49. return 0;
  50. }
  51. static int comxlapb_header(struct sk_buff *skb, struct net_device *dev, 
  52. unsigned short type, void *daddr, void *saddr, unsigned len) 
  53. {
  54. return dev->hard_header_len;  
  55. }
  56. static void comxlapb_status(struct net_device *dev, unsigned short status)
  57. {
  58. struct comx_channel *ch;
  59. if (!dev || !(ch = dev->priv)) {
  60. return;
  61. }
  62. if (status & LINE_UP) {
  63. netif_wake_queue(dev);
  64. }
  65. comx_status(dev, status);
  66. }
  67. static int comxlapb_open(struct net_device *dev)
  68. {
  69. struct comx_channel *ch = dev->priv;
  70. int err = 0;
  71. if (!(ch->init_status & HW_OPEN)) {
  72. return -ENODEV;
  73. }
  74. err = lapb_connect_request(ch);
  75. if (ch->debug_flags & DEBUG_COMX_LAPB) {
  76. comx_debug(dev, "%s: lapb opened, error code: %dn", 
  77. dev->name, err);
  78. }
  79. if (!err) {
  80. ch->init_status |= LINE_OPEN;
  81. MOD_INC_USE_COUNT;
  82. }
  83. return err;
  84. }
  85. static int comxlapb_close(struct net_device *dev)
  86. {
  87. struct comx_channel *ch = dev->priv;
  88. if (!(ch->init_status & HW_OPEN)) {
  89. return -ENODEV;
  90. }
  91. if (ch->debug_flags & DEBUG_COMX_LAPB) {
  92. comx_debug(dev, "%s: lapb closedn", dev->name);
  93. }
  94. lapb_disconnect_request(ch);
  95. ch->init_status &= ~LINE_OPEN;
  96. ch->line_status &= ~PROTO_UP;
  97. MOD_DEC_USE_COUNT;
  98. return 0;
  99. }
  100. static int comxlapb_xmit(struct sk_buff *skb, struct net_device *dev)
  101. {
  102. struct comx_channel *ch = dev->priv;
  103. struct sk_buff *skb2;
  104. if (!dev || !(ch = dev->priv) || !(dev->flags & (IFF_UP | IFF_RUNNING))) {
  105. return -ENODEV;
  106. }
  107. if (dev->type == ARPHRD_X25) { // first byte tells what to do 
  108. switch(skb->data[0]) {
  109. case 0x00:
  110. break; // transmit
  111. case 0x01:
  112. lapb_connect_request(ch);
  113. kfree_skb(skb);
  114. return 0;
  115. case 0x02:
  116. lapb_disconnect_request(ch);
  117. default:
  118. kfree_skb(skb);
  119. return 0;
  120. }
  121. skb_pull(skb,1);
  122. }
  123. netif_stop_queue(dev);
  124. if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
  125. lapb_data_request(ch, skb2);
  126. }
  127. return FRAME_ACCEPTED;
  128. }
  129. static int comxlapb_statistics(struct net_device *dev, char *page) 
  130. {
  131. struct lapb_parms_struct parms;
  132. int len = 0;
  133. len += sprintf(page + len, "Line status: ");
  134. if (lapb_getparms(dev->priv, &parms) != LAPB_OK) {
  135. len += sprintf(page + len, "not initializedn");
  136. return len;
  137. }
  138. len += sprintf(page + len, "%s (%s), T1: %d/%d, T2: %d/%d, N2: %d/%d, "
  139. "window: %dn", parms.mode & LAPB_DCE ? "DCE" : "DTE", 
  140. parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD",
  141. parms.t1timer, parms.t1, parms.t2timer, parms.t2, 
  142. parms.n2count, parms.n2, parms.window);
  143. return len;
  144. }
  145. static int comxlapb_read_proc(char *page, char **start, off_t off, int count,
  146. int *eof, void *data)
  147. {
  148. struct proc_dir_entry *file = (struct proc_dir_entry *)data;
  149. struct net_device *dev = file->parent->data;
  150. struct lapb_parms_struct parms;
  151. int len = 0;
  152. if (lapb_getparms(dev->priv, &parms)) {
  153. return -ENODEV;
  154. }
  155. if (strcmp(file->name, FILENAME_T1) == 0) {
  156. len += sprintf(page + len, "%02u / %02un", 
  157. parms.t1timer, parms.t1);
  158. } else if (strcmp(file->name, FILENAME_T2) == 0) {
  159. len += sprintf(page + len, "%02u / %02un", 
  160. parms.t2timer, parms.t2);
  161. } else if (strcmp(file->name, FILENAME_N2) == 0) {
  162. len += sprintf(page + len, "%02u / %02un", 
  163. parms.n2count, parms.n2);
  164. } else if (strcmp(file->name, FILENAME_WINDOW) == 0) {
  165. len += sprintf(page + len, "%un", parms.window);
  166. } else if (strcmp(file->name, FILENAME_MODE) == 0) {
  167. len += sprintf(page + len, "%s, %sn", 
  168. parms.mode & LAPB_DCE ? "DCE" : "DTE",
  169. parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD");
  170. } else {
  171. printk(KERN_ERR "comxlapb: internal error, filename %sn", file->name);
  172. return -EBADF;
  173. }
  174. if (off >= len) {
  175. *eof = 1;
  176. return 0;
  177. }
  178. *start = page + off;
  179. if (count >= len - off) {
  180. *eof = 1;
  181. }
  182. return min_t(int, count, len - off);
  183. }
  184. static int comxlapb_write_proc(struct file *file, const char *buffer, 
  185. u_long count, void *data)
  186. {
  187. struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
  188. struct net_device *dev = entry->parent->data;
  189. struct lapb_parms_struct parms;
  190. unsigned long parm;
  191. char *page;
  192. if (lapb_getparms(dev->priv, &parms)) {
  193. return -ENODEV;
  194. }
  195. if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
  196. return -ENOMEM;
  197. }
  198. copy_from_user(page, buffer, count);
  199. if (*(page + count - 1) == 'n') {
  200. *(page + count - 1) = 0;
  201. }
  202. if (strcmp(entry->name, FILENAME_T1) == 0) {
  203. parm=simple_strtoul(page,NULL,10);
  204. if (parm > 0 && parm < 100) {
  205. parms.t1=parm;
  206. lapb_setparms(dev->priv, &parms);
  207. }
  208. } else if (strcmp(entry->name, FILENAME_T2) == 0) {
  209. parm=simple_strtoul(page, NULL, 10);
  210. if (parm > 0 && parm < 100) {
  211. parms.t2=parm;
  212. lapb_setparms(dev->priv, &parms);
  213. }
  214. } else if (strcmp(entry->name, FILENAME_N2) == 0) {
  215. parm=simple_strtoul(page, NULL, 10);
  216. if (parm > 0 && parm < 100) {
  217. parms.n2=parm;
  218. lapb_setparms(dev->priv, &parms);
  219. }
  220. } else if (strcmp(entry->name, FILENAME_WINDOW) == 0) {
  221. parms.window = simple_strtoul(page, NULL, 10);
  222. lapb_setparms(dev->priv, &parms);
  223. } else if (strcmp(entry->name, FILENAME_MODE) == 0) {
  224. if (comx_strcasecmp(page, "dte") == 0) {
  225. parms.mode &= ~(LAPB_DCE | LAPB_DTE); 
  226. parms.mode |= LAPB_DTE;
  227. } else if (comx_strcasecmp(page, "dce") == 0) {
  228. parms.mode &= ~(LAPB_DTE | LAPB_DCE); 
  229. parms.mode |= LAPB_DCE;
  230. } else if (comx_strcasecmp(page, "std") == 0 || 
  231.     comx_strcasecmp(page, "standard") == 0) {
  232. parms.mode &= ~LAPB_EXTENDED; 
  233. parms.mode |= LAPB_STANDARD;
  234. } else if (comx_strcasecmp(page, "ext") == 0 || 
  235.     comx_strcasecmp(page, "extended") == 0) {
  236. parms.mode &= ~LAPB_STANDARD; 
  237. parms.mode |= LAPB_EXTENDED;
  238. }
  239. lapb_setparms(dev->priv, &parms);
  240. } else {
  241. printk(KERN_ERR "comxlapb_write_proc: internal error, filename %sn", 
  242. entry->name);
  243. return -EBADF;
  244. }
  245. free_page((unsigned long)page);
  246. return count;
  247. }
  248. static void comxlapb_connected(void *token, int reason)
  249. {
  250. struct comx_channel *ch = token; 
  251. struct proc_dir_entry *comxdir = ch->procdir->subdir;
  252. if (ch->debug_flags & DEBUG_COMX_LAPB) {
  253. comx_debug(ch->dev, "%s: lapb connected, reason: %dn", 
  254. ch->dev->name, reason);
  255. }
  256. if (ch->dev->type == ARPHRD_X25) {
  257. unsigned char *p;
  258. struct sk_buff *skb;
  259. if ((skb = dev_alloc_skb(1)) == NULL) {
  260. printk(KERN_ERR "comxlapb: out of memory!n");
  261. return;
  262. }
  263. p = skb_put(skb,1);
  264. *p = 0x01; // link established
  265. skb->dev = ch->dev;
  266. skb->protocol = htons(ETH_P_X25);
  267. skb->mac.raw = skb->data;
  268. skb->pkt_type = PACKET_HOST;
  269. netif_rx(skb);
  270. ch->dev->last_rx = jiffies;
  271. }
  272. for (; comxdir; comxdir = comxdir->next) {
  273. if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
  274. comxdir->mode = S_IFREG | 0444;
  275. }
  276. }
  277. ch->line_status |= PROTO_UP;
  278. comx_status(ch->dev, ch->line_status);
  279. }
  280. static void comxlapb_disconnected(void *token, int reason)
  281. {
  282. struct comx_channel *ch = token; 
  283. struct proc_dir_entry *comxdir = ch->procdir->subdir;
  284. if (ch->debug_flags & DEBUG_COMX_LAPB) {
  285. comx_debug(ch->dev, "%s: lapb disconnected, reason: %dn", 
  286. ch->dev->name, reason);
  287. }
  288. if (ch->dev->type == ARPHRD_X25) {
  289. unsigned char *p;
  290. struct sk_buff *skb;
  291. if ((skb = dev_alloc_skb(1)) == NULL) {
  292. printk(KERN_ERR "comxlapb: out of memory!n");
  293. return;
  294. }
  295. p = skb_put(skb,1);
  296. *p = 0x02; // link disconnected
  297. skb->dev = ch->dev;
  298. skb->protocol = htons(ETH_P_X25);
  299. skb->mac.raw = skb->data;
  300. skb->pkt_type = PACKET_HOST;
  301. netif_rx(skb);
  302. ch->dev->last_rx = jiffies;
  303. }
  304. for (; comxdir; comxdir = comxdir->next) {
  305. if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
  306. comxdir->mode = S_IFREG | 0644;
  307. }
  308. }
  309. ch->line_status &= ~PROTO_UP;
  310. comx_status(ch->dev, ch->line_status);
  311. }
  312. static int comxlapb_data_indication(void *token, struct sk_buff *skb)
  313. {
  314. struct comx_channel *ch = token; 
  315. if (ch->dev->type == ARPHRD_X25) {
  316. skb_push(skb, 1);
  317. skb->data[0] = 0; // indicate data for X25
  318. skb->protocol = htons(ETH_P_X25);
  319. } else {
  320. skb->protocol = htons(ETH_P_IP);
  321. }
  322. skb->dev = ch->dev;
  323. skb->mac.raw = skb->data;
  324. return comx_rx(ch->dev, skb);
  325. }
  326. static void comxlapb_data_transmit(void *token, struct sk_buff *skb)
  327. {
  328. struct comx_channel *ch = token; 
  329. if (ch->HW_send_packet) {
  330. ch->HW_send_packet(ch->dev, skb);
  331. }
  332. }
  333. static int comxlapb_exit(struct net_device *dev) 
  334. {
  335. struct comx_channel *ch = dev->priv;
  336. dev->flags = 0;
  337. dev->type = 0;
  338. dev->mtu = 0;
  339. dev->hard_header_len    = 0;
  340. ch->LINE_rx = NULL;
  341. ch->LINE_tx = NULL;
  342. ch->LINE_status = NULL;
  343. ch->LINE_open = NULL;
  344. ch->LINE_close = NULL;
  345. ch->LINE_xmit = NULL;
  346. ch->LINE_header = NULL;
  347. ch->LINE_statistics = NULL;
  348. if (ch->debug_flags & DEBUG_COMX_LAPB) {
  349. comx_debug(dev, "%s: unregistering lapbn", dev->name);
  350. }
  351. lapb_unregister(dev->priv);
  352. remove_proc_entry(FILENAME_T1, ch->procdir);
  353. remove_proc_entry(FILENAME_T2, ch->procdir);
  354. remove_proc_entry(FILENAME_N2, ch->procdir);
  355. remove_proc_entry(FILENAME_MODE, ch->procdir);
  356. remove_proc_entry(FILENAME_WINDOW, ch->procdir);
  357. MOD_DEC_USE_COUNT;
  358. return 0;
  359. }
  360. static int comxlapb_init(struct net_device *dev)
  361. {
  362. struct comx_channel *ch = dev->priv;
  363. struct lapb_register_struct lapbreg;
  364. dev->mtu = 1500;
  365. dev->hard_header_len    = 4;
  366. dev->addr_len = 0;
  367. ch->LINE_rx = comxlapb_rx;
  368. ch->LINE_tx = comxlapb_tx;
  369. ch->LINE_status = comxlapb_status;
  370. ch->LINE_open = comxlapb_open;
  371. ch->LINE_close = comxlapb_close;
  372. ch->LINE_xmit = comxlapb_xmit;
  373. ch->LINE_header = comxlapb_header;
  374. ch->LINE_statistics = comxlapb_statistics;
  375. lapbreg.connect_confirmation = comxlapb_connected;
  376. lapbreg.connect_indication = comxlapb_connected;
  377. lapbreg.disconnect_confirmation = comxlapb_disconnected;
  378. lapbreg.disconnect_indication = comxlapb_disconnected;
  379. lapbreg.data_indication = comxlapb_data_indication;
  380. lapbreg.data_transmit = comxlapb_data_transmit;
  381. if (lapb_register(dev->priv, &lapbreg)) {
  382. return -ENOMEM;
  383. }
  384. if (ch->debug_flags & DEBUG_COMX_LAPB) {
  385. comx_debug(dev, "%s: lapb registeredn", dev->name);
  386. }
  387. if (!create_comxlapb_proc_entry(FILENAME_T1, 0644, 8, ch->procdir)) {
  388. return -ENOMEM;
  389. }
  390. if (!create_comxlapb_proc_entry(FILENAME_T2, 0644, 8, ch->procdir)) {
  391. return -ENOMEM;
  392. }
  393. if (!create_comxlapb_proc_entry(FILENAME_N2, 0644, 8, ch->procdir)) {
  394. return -ENOMEM;
  395. }
  396. if (!create_comxlapb_proc_entry(FILENAME_MODE, 0644, 14, ch->procdir)) {
  397. return -ENOMEM;
  398. }
  399. if (!create_comxlapb_proc_entry(FILENAME_WINDOW, 0644, 0, ch->procdir)) {
  400. return -ENOMEM;
  401. }
  402. MOD_INC_USE_COUNT;
  403. return 0;
  404. }
  405. static int comxlapb_init_lapb(struct net_device *dev) 
  406. {
  407. dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
  408. dev->type = ARPHRD_LAPB;
  409. return(comxlapb_init(dev));
  410. }
  411. static int comxlapb_init_x25(struct net_device *dev)
  412. {
  413. dev->flags = IFF_NOARP;
  414. dev->type = ARPHRD_X25;
  415. return(comxlapb_init(dev));
  416. }
  417. static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
  418. int size, struct proc_dir_entry *dir)
  419. {
  420. struct proc_dir_entry *new_file;
  421. if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
  422. new_file->data = (void *)new_file;
  423. new_file->read_proc = &comxlapb_read_proc;
  424. new_file->write_proc = &comxlapb_write_proc;
  425. new_file->size = size;
  426. new_file->nlink = 1;
  427. }
  428. return(new_file);
  429. }
  430. static struct comx_protocol comxlapb_protocol = {
  431. "lapb", 
  432. VERSION,
  433. ARPHRD_LAPB, 
  434. comxlapb_init_lapb, 
  435. comxlapb_exit, 
  436. NULL 
  437. };
  438. static struct comx_protocol comx25_protocol = {
  439. "x25", 
  440. VERSION,
  441. ARPHRD_X25, 
  442. comxlapb_init_x25, 
  443. comxlapb_exit, 
  444. NULL 
  445. };
  446. int __init comx_proto_lapb_init(void)
  447. {
  448. int ret;
  449. if ((ret = comx_register_protocol(&comxlapb_protocol)) != 0) {
  450. return ret;
  451. }
  452. return comx_register_protocol(&comx25_protocol);
  453. }
  454. static void __exit comx_proto_lapb_exit(void)
  455. {
  456. comx_unregister_protocol(comxlapb_protocol.name);
  457. comx_unregister_protocol(comx25_protocol.name);
  458. }
  459. #ifdef MODULE
  460. module_init(comx_proto_lapb_init);
  461. #endif
  462. module_exit(comx_proto_lapb_exit);
  463. MODULE_LICENSE("GPL");