comx-proto-fr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:25k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Frame-relay protocol module for the COMX driver 
  3.  * for Linux 2.2.X
  4.  *
  5.  * Original author: Tivadar Szemethy <tiv@itc.hu>
  6.  * Maintainer: Gergely Madarasz <gorgo@itc.hu>
  7.  *
  8.  * Copyright (C) 1998-1999 ITConsult-Pro Co. <info@itc.hu>
  9.  * 
  10.  * Contributors:
  11.  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.73)
  12.  *
  13.  * This program is free software; you can redistribute it and/or
  14.  * modify it under the terms of the GNU General Public License
  15.  * as published by the Free Software Foundation; either version
  16.  * 2 of the License, or (at your option) any later version.
  17.  *
  18.  * Version 0.70 (99/06/14):
  19.  * - cleaned up the source code a bit
  20.  * - ported back to kernel, now works as builtin code 
  21.  *
  22.  * Version 0.71 (99/06/25):
  23.  * - use skb priorities and queues for sending keepalive
  24.  *  - use device queues for slave->master data transmit
  25.  * - set IFF_RUNNING only line protocol up
  26.  * - fixes on slave device flags
  27.  * 
  28.  * Version 0.72 (99/07/09):
  29.  * - handle slave tbusy with master tbusy (should be fixed)
  30.  * - fix the keepalive timer addition/deletion
  31.  *
  32.  * Version 0.73 (00/08/15)
  33.  *  - resource release on failure at fr_master_init and
  34.  *   fr_slave_init    
  35.  */
  36. #define VERSION "0.73"
  37. #include <linux/module.h>
  38. #include <linux/version.h>
  39. #include <linux/types.h>
  40. #include <linux/sched.h>
  41. #include <linux/netdevice.h>
  42. #include <linux/proc_fs.h>
  43. #include <linux/if_arp.h>
  44. #include <linux/inetdevice.h>
  45. #include <linux/pkt_sched.h>
  46. #include <linux/init.h>
  47. #include <asm/uaccess.h>
  48. #include "comx.h"
  49. #include "comxhw.h"
  50. MODULE_AUTHOR("Author: Tivadar Szemethy <tiv@itc.hu>");
  51. MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers"
  52. "for Linux kernel 2.4.X");
  53. MODULE_LICENSE("GPL");
  54. #define FRAD_UI 0x03
  55. #define NLPID_IP 0xcc
  56. #define NLPID_Q933_LMI 0x08
  57. #define NLPID_CISCO_LMI 0x09
  58. #define Q933_ENQ 0x75
  59. #define Q933_LINESTAT 0x51
  60. #define Q933_COUNTERS 0x53
  61. #define MAXALIVECNT 3 /* No. of failures */
  62. struct fr_data {
  63. u16 dlci;
  64. struct net_device *master;
  65. char keepa_pend;
  66. char keepa_freq;
  67. char keepalivecnt, keeploopcnt;
  68. struct timer_list keepa_timer;
  69. u8 local_cnt, remote_cnt;
  70. };
  71. static struct comx_protocol fr_master_protocol;
  72. static struct comx_protocol fr_slave_protocol;
  73. static struct comx_hardware fr_dlci;
  74. static void fr_keepalive_send(struct net_device *dev) 
  75. {
  76. struct comx_channel *ch = dev->priv;
  77. struct fr_data *fr = ch->LINE_privdata;
  78. struct sk_buff *skb;
  79. u8 *fr_packet;
  80. skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC);
  81. if(skb==NULL)
  82. return;
  83.                
  84.         skb_reserve(skb, dev->hard_header_len);
  85.         
  86.         fr_packet=(u8*)skb_put(skb, 13);
  87.                  
  88. fr_packet[0] = (fr->dlci & (1024 - 15)) >> 2;
  89. fr_packet[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1
  90. fr_packet[2] = FRAD_UI;
  91. fr_packet[3] = NLPID_Q933_LMI;
  92. fr_packet[4] = 0;
  93. fr_packet[5] = Q933_ENQ;
  94. fr_packet[6] = Q933_LINESTAT;
  95. fr_packet[7] = 0x01;
  96. fr_packet[8] = 0x01;
  97. fr_packet[9] = Q933_COUNTERS;
  98. fr_packet[10] = 0x02;
  99. fr_packet[11] = ++fr->local_cnt;
  100. fr_packet[12] = fr->remote_cnt;
  101. skb->dev = dev;
  102. skb->priority = TC_PRIO_CONTROL;
  103. dev_queue_xmit(skb);
  104. }
  105. static void fr_keepalive_timerfun(unsigned long d) 
  106. {
  107. struct net_device *dev = (struct net_device *)d;
  108. struct comx_channel *ch = dev->priv;
  109. struct fr_data *fr = ch->LINE_privdata;
  110. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  111. struct comx_channel *sch;
  112. struct fr_data *sfr;
  113. struct net_device *sdev;
  114. if (ch->init_status & LINE_OPEN) {
  115. if (fr->keepalivecnt == MAXALIVECNT) {
  116. comx_status(dev, ch->line_status & ~PROTO_UP);
  117. dev->flags &= ~IFF_RUNNING;
  118. for (; dir ; dir = dir->next) {
  119. if(!S_ISDIR(dir->mode)) {
  120.     continue;
  121. }
  122. if ((sdev = dir->data) && (sch = sdev->priv) && 
  123.     (sdev->type == ARPHRD_DLCI) && 
  124.     (sfr = sch->LINE_privdata) 
  125.     && (sfr->master == dev) && 
  126.     (sdev->flags & IFF_UP)) {
  127. sdev->flags &= ~IFF_RUNNING;
  128. comx_status(sdev, 
  129. sch->line_status & ~PROTO_UP);
  130. }
  131. }
  132. }
  133. if (fr->keepalivecnt <= MAXALIVECNT) {
  134. ++fr->keepalivecnt;
  135. }
  136. fr_keepalive_send(dev);
  137. }
  138. mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq);
  139. }
  140. static void fr_rx_lmi(struct net_device *dev, struct sk_buff *skb, 
  141. u16 dlci, u8 nlpid) 
  142. {
  143. struct comx_channel *ch = dev->priv;
  144. struct fr_data *fr = ch->LINE_privdata;
  145. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  146. struct comx_channel *sch;
  147. struct fr_data *sfr;
  148. struct net_device *sdev;
  149. if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) {
  150. return;
  151. }
  152. fr->remote_cnt = skb->data[7];
  153. if (skb->data[8] == fr->local_cnt) { // keepalive UP!
  154. fr->keepalivecnt = 0;
  155. if ((ch->line_status & LINE_UP) && 
  156.     !(ch->line_status & PROTO_UP)) {
  157. comx_status(dev, ch->line_status |= PROTO_UP);
  158. dev->flags |= IFF_RUNNING;
  159. for (; dir ; dir = dir->next) {
  160. if(!S_ISDIR(dir->mode)) {
  161.     continue;
  162. }
  163. if ((sdev = dir->data) && (sch = sdev->priv) && 
  164.     (sdev->type == ARPHRD_DLCI) && 
  165.     (sfr = sch->LINE_privdata) 
  166.     && (sfr->master == dev) && 
  167.     (sdev->flags & IFF_UP)) {
  168. sdev->flags |= IFF_RUNNING;
  169. comx_status(sdev, 
  170. sch->line_status | PROTO_UP);
  171. }
  172. }
  173. }
  174. }
  175. }
  176. static void fr_set_keepalive(struct net_device *dev, int keepa) 
  177. {
  178. struct comx_channel *ch = dev->priv;
  179. struct fr_data *fr = ch->LINE_privdata;
  180. if (!keepa && fr->keepa_freq) { // switch off
  181. fr->keepa_freq = 0;
  182. if (ch->line_status & LINE_UP) {
  183. comx_status(dev, ch->line_status | PROTO_UP);
  184. dev->flags |= IFF_RUNNING;
  185. del_timer(&fr->keepa_timer);
  186. }
  187. return;
  188. }
  189. if (keepa) { // bekapcs
  190. if(fr->keepa_freq && (ch->line_status & LINE_UP)) {
  191. del_timer(&fr->keepa_timer);
  192. }
  193. fr->keepa_freq = keepa;
  194. fr->local_cnt = fr->remote_cnt = 0;
  195. fr->keepa_timer.expires = jiffies + HZ;
  196. fr->keepa_timer.function = fr_keepalive_timerfun;
  197. fr->keepa_timer.data = (unsigned long)dev;
  198. ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
  199. dev->flags &= ~IFF_RUNNING;
  200. comx_status(dev, ch->line_status);
  201. if(ch->line_status & LINE_UP) {
  202. add_timer(&fr->keepa_timer);
  203. }
  204. }
  205. }
  206. static void fr_rx(struct net_device *dev, struct sk_buff *skb) 
  207. {
  208. struct comx_channel *ch = dev->priv;
  209. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  210. struct net_device *sdev = dev;
  211. struct comx_channel *sch;
  212. struct fr_data *sfr;
  213. u16 dlci;
  214. u8 nlpid;
  215. if(skb->len <= 4 || skb->data[2] != FRAD_UI) {
  216. kfree_skb(skb);
  217. return;
  218. }
  219. /* Itt majd ki kell talalni, melyik slave kapja a csomagot */
  220. dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4);
  221. if ((nlpid = skb->data[3]) == 0) { // Optional padding 
  222. nlpid = skb->data[4];
  223. skb_pull(skb, 1);
  224. }
  225. skb_pull(skb, 4); /* DLCI and header throw away */
  226. if (ch->debug_flags & DEBUG_COMX_DLCI) {
  227. comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02xn", 
  228. dlci, nlpid);
  229. comx_debug_skb(dev, skb, "Contents");
  230. }
  231. /* Megkeressuk, kihez tartozik */
  232. for (; dir ; dir = dir->next) {
  233. if(!S_ISDIR(dir->mode)) {
  234. continue;
  235. }
  236. if ((sdev = dir->data) && (sch = sdev->priv) && 
  237.     (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
  238.     (sfr->master == dev) && (sfr->dlci == dlci)) {
  239. skb->dev = sdev;
  240. if (ch->debug_flags & DEBUG_COMX_DLCI) {
  241. comx_debug(dev, "Passing it to %sn",sdev->name);
  242. }
  243. if (dev != sdev) {
  244. sch->stats.rx_packets++;
  245. sch->stats.rx_bytes += skb->len;
  246. }
  247. break;
  248. }
  249. }
  250. switch(nlpid) {
  251. case NLPID_IP:
  252. skb->protocol = htons(ETH_P_IP);
  253. skb->mac.raw = skb->data;
  254. comx_rx(sdev, skb);
  255. break;
  256. case NLPID_Q933_LMI:
  257. fr_rx_lmi(dev, skb, dlci, nlpid);
  258. default:
  259. kfree_skb(skb);
  260. break;
  261. }
  262. }
  263. static int fr_tx(struct net_device *dev) 
  264. {
  265. struct comx_channel *ch = dev->priv;
  266. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  267. struct net_device *sdev;
  268. struct comx_channel *sch;
  269. struct fr_data *sfr;
  270. int cnt = 1;
  271. /* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel, 
  272.    es annal a slave-nel aki eppen kuldott.
  273.    Egy helyen akkor all, ha a master kuldott.
  274.    Ez megint jo lesz majd, ha utemezni akarunk */
  275.    
  276. /* This should be fixed, the slave tbusy should be set when 
  277.    the masters queue is full and reset when not */
  278. for (; dir ; dir = dir->next) {
  279. if(!S_ISDIR(dir->mode)) {
  280.     continue;
  281. }
  282. if ((sdev = dir->data) && (sch = sdev->priv) && 
  283.     (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
  284.     (sfr->master == dev) && (netif_queue_stopped(sdev))) {
  285.      netif_wake_queue(sdev);
  286. cnt++;
  287. }
  288. }
  289. netif_wake_queue(dev);
  290. return 0;
  291. }
  292. static void fr_status(struct net_device *dev, unsigned short status)
  293. {
  294. struct comx_channel *ch = dev->priv;
  295. struct fr_data *fr = ch->LINE_privdata;
  296. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  297. struct net_device *sdev;
  298. struct comx_channel *sch;
  299. struct fr_data *sfr;
  300. if (status & LINE_UP) {
  301. if (!fr->keepa_freq) {
  302. status |= PROTO_UP;
  303. }
  304. } else {
  305. status &= ~(PROTO_UP | PROTO_LOOP);
  306. }
  307. if (dev == fr->master && fr->keepa_freq) {
  308. if (status & LINE_UP) {
  309. fr->keepa_timer.expires = jiffies + HZ;
  310. add_timer(&fr->keepa_timer);
  311. fr->keepalivecnt = MAXALIVECNT + 1;
  312. fr->keeploopcnt = 0;
  313. } else {
  314. del_timer(&fr->keepa_timer);
  315. }
  316. }
  317. /* Itt a status valtozast vegig kell vinni az osszes slave-n */
  318. for (; dir ; dir = dir->next) {
  319. if(!S_ISDIR(dir->mode)) {
  320.     continue;
  321. }
  322. if ((sdev = dir->data) && (sch = sdev->priv) && 
  323.     (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) && 
  324.     (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
  325. if(status & LINE_UP) {
  326. netif_wake_queue(sdev);
  327. }
  328. comx_status(sdev, status);
  329. if(status & (PROTO_UP | PROTO_LOOP)) {
  330. dev->flags |= IFF_RUNNING;
  331. } else {
  332. dev->flags &= ~IFF_RUNNING;
  333. }
  334. }
  335. }
  336. }
  337. static int fr_open(struct net_device *dev)
  338. {
  339. struct comx_channel *ch = dev->priv;
  340. struct fr_data *fr = ch->LINE_privdata;
  341. struct proc_dir_entry *comxdir = ch->procdir;
  342. struct comx_channel *mch;
  343. if (!(ch->init_status & HW_OPEN)) {
  344. return -ENODEV;
  345. }
  346. if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) ||
  347.     (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) {
  348. printk(KERN_ERR "Trying to open an improperly set FR interface, giving upn");
  349. return -EINVAL;
  350. }
  351. if (!fr->master) {
  352. return -ENODEV;
  353. }
  354. mch = fr->master->priv;
  355. if (fr->master != dev && (!(mch->init_status & LINE_OPEN) 
  356.    || (mch->protocol != &fr_master_protocol))) {
  357. printk(KERN_ERR "Master %s is inactive, or incorrectly set up, "
  358. "unable to open %sn", fr->master->name, dev->name);
  359. return -ENODEV;
  360. }
  361. ch->init_status |= LINE_OPEN;
  362. ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
  363. dev->flags &= ~IFF_RUNNING;
  364. if (fr->master == dev) {
  365. if (fr->keepa_freq) {
  366. fr->keepa_timer.function = fr_keepalive_timerfun;
  367. fr->keepa_timer.data = (unsigned long)dev;
  368. add_timer(&fr->keepa_timer);
  369. } else {
  370. if (ch->line_status & LINE_UP) {
  371. ch->line_status |= PROTO_UP;
  372. dev->flags |= IFF_RUNNING;
  373. }
  374. }
  375. } else {
  376. ch->line_status = mch->line_status;
  377. if(fr->master->flags & IFF_RUNNING) {
  378. dev->flags |= IFF_RUNNING;
  379. }
  380. }
  381. for (; comxdir ; comxdir = comxdir->next) {
  382. if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
  383.    strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
  384.    strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
  385. comxdir->mode = S_IFREG | 0444;
  386. }
  387. }
  388. // comx_status(dev, ch->line_status);
  389. return 0;
  390. }
  391. static int fr_close(struct net_device *dev)
  392. {
  393. struct comx_channel *ch = dev->priv;
  394. struct fr_data *fr = ch->LINE_privdata;
  395. struct proc_dir_entry *comxdir = ch->procdir;
  396. if (fr->master == dev) { // Ha master 
  397. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  398. struct net_device *sdev = dev;
  399. struct comx_channel *sch;
  400. struct fr_data *sfr;
  401. if (!(ch->init_status & HW_OPEN)) {
  402. return -ENODEV;
  403. }
  404. if (fr->keepa_freq) {
  405. del_timer(&fr->keepa_timer);
  406. }
  407. for (; dir ; dir = dir->next) {
  408. if(!S_ISDIR(dir->mode)) {
  409. continue;
  410. }
  411. if ((sdev = dir->data) && (sch = sdev->priv) && 
  412.     (sdev->type == ARPHRD_DLCI) && 
  413.     (sfr = sch->LINE_privdata) &&
  414.     (sfr->master == dev) && 
  415.     (sch->init_status & LINE_OPEN)) {
  416. dev_close(sdev);
  417. }
  418. }
  419. }
  420. ch->init_status &= ~LINE_OPEN;
  421. ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
  422. dev->flags &= ~IFF_RUNNING;
  423. for (; comxdir ; comxdir = comxdir->next) {
  424. if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
  425.     strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
  426.     strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
  427. comxdir->mode = S_IFREG | 0444;
  428. }
  429. }
  430. return 0;
  431. }
  432. static int fr_xmit(struct sk_buff *skb, struct net_device *dev)
  433. {
  434. struct comx_channel *ch = dev->priv;
  435. struct comx_channel *sch, *mch;
  436. struct fr_data *fr = ch->LINE_privdata;
  437. struct fr_data *sfr;
  438. struct net_device *sdev;
  439. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  440. if (!fr->master) {
  441. printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %sn", dev->name);
  442. return 0;
  443. }
  444. mch = fr->master->priv;
  445. /* Ennek majd a slave utemezeskor lesz igazan jelentosege */
  446. if (ch->debug_flags & DEBUG_COMX_DLCI) {
  447. comx_debug_skb(dev, skb, "Sending frame");
  448. }
  449. if (dev != fr->master) {
  450. struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
  451. if (!newskb)
  452. return -ENOMEM;
  453. newskb->dev=fr->master;
  454. dev_queue_xmit(newskb);
  455. ch->stats.tx_bytes += skb->len;
  456. ch->stats.tx_packets++;
  457. dev_kfree_skb(skb);
  458. } else {
  459. netif_stop_queue(dev);
  460. for (; dir ; dir = dir->next) {
  461. if(!S_ISDIR(dir->mode)) {
  462.     continue;
  463. }
  464. if ((sdev = dir->data) && (sch = sdev->priv) && 
  465.     (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
  466.     (sfr->master == dev) && (netif_queue_stopped(sdev))) {
  467. netif_stop_queue(sdev);
  468. }
  469. }
  470.  
  471. switch(mch->HW_send_packet(dev, skb)) {
  472. case FRAME_QUEUED:
  473. netif_wake_queue(dev);
  474. break;
  475. case FRAME_ACCEPTED:
  476. case FRAME_DROPPED:
  477. break;
  478. case FRAME_ERROR:
  479. printk(KERN_ERR "%s: Transmit frame error (len %d)n", 
  480. dev->name, skb->len);
  481. break;
  482. }
  483. }
  484. return 0;
  485. }
  486. static int fr_header(struct sk_buff *skb, struct net_device *dev, 
  487. unsigned short type, void *daddr, void *saddr, unsigned len) 
  488. {
  489. struct comx_channel *ch = dev->priv;
  490. struct fr_data *fr = ch->LINE_privdata;
  491. skb_push(skb, dev->hard_header_len);   
  492. /* Put in DLCI */
  493. skb->data[0] = (fr->dlci & (1024 - 15)) >> 2;
  494. skb->data[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1
  495. skb->data[2] = FRAD_UI;
  496. skb->data[3] = NLPID_IP;
  497. return dev->hard_header_len;  
  498. }
  499. static int fr_statistics(struct net_device *dev, char *page) 
  500. {
  501. struct comx_channel *ch = dev->priv;
  502. struct fr_data *fr = ch->LINE_privdata;
  503. int len = 0;
  504. if (fr->master == dev) {
  505. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  506. struct net_device *sdev;
  507. struct comx_channel *sch;
  508. struct fr_data *sfr;
  509. int slaves = 0;
  510. len += sprintf(page + len, 
  511. "This is a Frame Relay master devicenSlaves: ");
  512. for (; dir ; dir = dir->next) {
  513. if(!S_ISDIR(dir->mode)) {
  514. continue;
  515. }
  516. if ((sdev = dir->data) && (sch = sdev->priv) && 
  517.     (sdev->type == ARPHRD_DLCI) &&
  518.     (sfr = sch->LINE_privdata) && 
  519.     (sfr->master == dev) && (sdev != dev)) {
  520. slaves++;
  521. len += sprintf(page + len, "%s ", sdev->name);
  522. }
  523. }
  524. len += sprintf(page + len, "%sn", slaves ? "" : "(none)");
  525. if (fr->keepa_freq) {
  526. len += sprintf(page + len, "Line keepalive (value %d) "
  527. "status %s [%d]n", fr->keepa_freq, 
  528. ch->line_status & PROTO_LOOP ? "LOOP" :
  529. ch->line_status & PROTO_UP ? "UP" : "DOWN", 
  530. fr->keepalivecnt);
  531. } else {
  532. len += sprintf(page + len, "Line keepalive protocol "
  533. "is not setn");
  534. }
  535. } else { // if slave
  536. len += sprintf(page + len, 
  537. "This is a Frame Relay slave device, master: %sn",
  538. fr->master ? fr->master->name : "(not set)");
  539. }
  540. return len;
  541. }
  542. static int fr_read_proc(char *page, char **start, off_t off, int count,
  543. int *eof, void *data)
  544. {
  545. struct proc_dir_entry *file = (struct proc_dir_entry *)data;
  546. struct net_device *dev = file->parent->data;
  547. struct comx_channel *ch = dev->priv;
  548. struct fr_data *fr = NULL;
  549. int len = 0;
  550. if (ch) {
  551. fr = ch->LINE_privdata;
  552. }
  553. if (strcmp(file->name, FILENAME_DLCI) == 0) {
  554. len = sprintf(page, "%04dn", fr->dlci);
  555. } else if (strcmp(file->name, FILENAME_MASTER) == 0) {
  556. len = sprintf(page, "%-9sn", fr->master ? fr->master->name :
  557. "(none)");
  558. } else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) {
  559. len = fr->keepa_freq ? sprintf(page, "% 3dn", fr->keepa_freq) 
  560. : sprintf(page, "offn");
  561. } else {
  562. printk(KERN_ERR "comxfr: internal error, filename %sn", file->name);
  563. return -EBADF;
  564. }
  565. if (off >= len) {
  566. *eof = 1;
  567. return 0;
  568. }
  569. *start = page + off;
  570. if (count >= len - off) *eof = 1;
  571. return min_t(int, count, len - off);
  572. }
  573. static int fr_write_proc(struct file *file, const char *buffer, 
  574. u_long count, void *data)
  575. {
  576. struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
  577. struct net_device *dev = entry->parent->data;
  578. struct comx_channel *ch = dev->priv;
  579. struct fr_data *fr = NULL; 
  580. char *page;
  581. if (ch) {
  582. fr = ch->LINE_privdata;
  583. }
  584. if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
  585. return -ENOMEM;
  586. }
  587. copy_from_user(page, buffer, count);
  588. if (*(page + count - 1) == 'n') {
  589. *(page + count - 1) = 0;
  590. }
  591. if (strcmp(entry->name, FILENAME_DLCI) == 0) {
  592. u16 dlci_new = simple_strtoul(page, NULL, 10);
  593. if (dlci_new > 1023) {
  594. printk(KERN_ERR "Invalid DLCI valuen");
  595. }
  596. else fr->dlci = dlci_new;
  597. } else if (strcmp(entry->name, FILENAME_MASTER) == 0) {
  598. struct net_device *new_master = dev_get_by_name(page);
  599. if (new_master && new_master->type == ARPHRD_FRAD) {
  600. struct comx_channel *sch = new_master->priv;
  601. struct fr_data *sfr = sch->LINE_privdata;
  602. if (sfr && sfr->master == new_master) {
  603. if(fr->master)
  604. dev_put(fr->master);
  605. fr->master = new_master;
  606. /* Megorokli a master statuszat */
  607. ch->line_status = sch->line_status;
  608. }
  609. }
  610. } else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) {
  611. int keepa_new = -1;
  612. if (strcmp(page, KEEPALIVE_OFF) == 0) {
  613. keepa_new = 0;
  614. } else {
  615. keepa_new = simple_strtoul(page, NULL, 10);
  616. }
  617. if (keepa_new < 0 || keepa_new > 100) {
  618. printk(KERN_ERR "invalid keepaliven");
  619. } else {
  620. if (fr->keepa_freq && keepa_new != fr->keepa_freq) {
  621. fr_set_keepalive(dev, 0);
  622. }
  623. if (keepa_new) {
  624. fr_set_keepalive(dev, keepa_new);
  625. }
  626. }
  627. } else {
  628. printk(KERN_ERR "comxfr_write_proc: internal error, filename %sn", 
  629. entry->name);
  630. count = -EBADF;
  631. }
  632. free_page((unsigned long)page);
  633. return count;
  634. }
  635. static int fr_exit(struct net_device *dev) 
  636. {
  637. struct comx_channel *ch = dev->priv;
  638. struct fr_data *fr = ch->LINE_privdata;
  639. struct net_device *sdev = dev;
  640. struct comx_channel *sch;
  641. struct fr_data *sfr;
  642. struct proc_dir_entry *dir = ch->procdir->parent->subdir;
  643. /* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */
  644. if (fr->master && fr->master == dev) {
  645. for (; dir ; dir = dir->next) {
  646. if(!S_ISDIR(dir->mode)) {
  647. continue;
  648. }
  649. if ((sdev = dir->data) && (sch = sdev->priv) && 
  650.     (sdev->type == ARPHRD_DLCI) && 
  651.     (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
  652. dev_close(sdev);
  653. sfr->master = NULL;
  654. }
  655. }
  656. }
  657. dev->flags = 0;
  658. dev->type = 0;
  659. dev->mtu = 0;
  660. dev->hard_header_len    = 0;
  661. ch->LINE_rx = NULL;
  662. ch->LINE_tx = NULL;
  663. ch->LINE_status = NULL;
  664. ch->LINE_open = NULL;
  665. ch->LINE_close = NULL;
  666. ch->LINE_xmit = NULL;
  667. ch->LINE_header = NULL;
  668. ch->LINE_rebuild_header = NULL;
  669. ch->LINE_statistics = NULL;
  670. ch->LINE_status = 0;
  671. if (fr->master != dev) { // if not master, remove dlci
  672. if(fr->master)
  673. dev_put(fr->master);
  674. remove_proc_entry(FILENAME_DLCI, ch->procdir);
  675. remove_proc_entry(FILENAME_MASTER, ch->procdir);
  676. } else {
  677. if (fr->keepa_freq) {
  678. fr_set_keepalive(dev, 0);
  679. }
  680. remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir);
  681. remove_proc_entry(FILENAME_DLCI, ch->procdir);
  682. }
  683. kfree(fr);
  684. ch->LINE_privdata = NULL;
  685. MOD_DEC_USE_COUNT;
  686. return 0;
  687. }
  688. static int fr_master_init(struct net_device *dev)
  689. {
  690. struct comx_channel *ch = dev->priv;
  691. struct fr_data *fr;
  692. struct proc_dir_entry *new_file;
  693. if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), 
  694.     GFP_KERNEL)) == NULL) {
  695. return -ENOMEM;
  696. }
  697. memset(fr, 0, sizeof(struct fr_data));
  698. fr->master = dev; // this means master
  699. fr->dlci = 0; // let's say default
  700. dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
  701. dev->type = ARPHRD_FRAD;
  702. dev->mtu = 1500;
  703. dev->hard_header_len    = 4;
  704. dev->addr_len = 0;
  705. ch->LINE_rx = fr_rx;
  706. ch->LINE_tx = fr_tx;
  707. ch->LINE_status = fr_status;
  708. ch->LINE_open = fr_open;
  709. ch->LINE_close = fr_close;
  710. ch->LINE_xmit = fr_xmit;
  711. ch->LINE_header = fr_header;
  712. ch->LINE_rebuild_header = NULL;
  713. ch->LINE_statistics = fr_statistics;
  714. if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, 
  715.     ch->procdir)) == NULL) {
  716. goto cleanup_LINE_privdata;
  717. }
  718. new_file->data = (void *)new_file;
  719. new_file->read_proc = &fr_read_proc;
  720. new_file->write_proc = &fr_write_proc;
  721. new_file->size = 5;
  722. new_file->nlink = 1;
  723. if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644, 
  724.     ch->procdir)) == NULL) {
  725. goto cleanup_filename_dlci;
  726. }
  727. new_file->data = (void *)new_file;
  728. new_file->read_proc = &fr_read_proc;
  729. new_file->write_proc = &fr_write_proc;
  730. new_file->size = 4;
  731. new_file->nlink = 1;
  732. fr_set_keepalive(dev, 0);
  733. MOD_INC_USE_COUNT;
  734. return 0;
  735. cleanup_filename_dlci:
  736.  remove_proc_entry(FILENAME_DLCI, ch->procdir);
  737. cleanup_LINE_privdata:
  738. kfree(fr);
  739. return -EIO;
  740. }
  741. static int fr_slave_init(struct net_device *dev)
  742. {
  743. struct comx_channel *ch = dev->priv;
  744. struct fr_data *fr;
  745. struct proc_dir_entry *new_file;
  746. if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), 
  747.     GFP_KERNEL)) == NULL) {
  748. return -ENOMEM;
  749. }
  750. memset(fr, 0, sizeof(struct fr_data));
  751. dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
  752. dev->type = ARPHRD_DLCI;
  753. dev->mtu = 1500;
  754. dev->hard_header_len    = 4;
  755. dev->addr_len = 0;
  756. ch->LINE_rx = fr_rx;
  757. ch->LINE_tx = fr_tx;
  758. ch->LINE_status = fr_status;
  759. ch->LINE_open = fr_open;
  760. ch->LINE_close = fr_close;
  761. ch->LINE_xmit = fr_xmit;
  762. ch->LINE_header = fr_header;
  763. ch->LINE_rebuild_header = NULL;
  764. ch->LINE_statistics = fr_statistics;
  765. if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, 
  766.     ch->procdir)) == NULL) {
  767. goto cleanup_LINE_privdata;
  768. }
  769. new_file->data = (void *)new_file;
  770. new_file->read_proc = &fr_read_proc;
  771. new_file->write_proc = &fr_write_proc;
  772. new_file->size = 5;
  773. new_file->nlink = 1;
  774. if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644, 
  775.     ch->procdir)) == NULL) {
  776. goto cleanup_filename_dlci;
  777. }
  778. new_file->data = (void *)new_file;
  779. new_file->read_proc = &fr_read_proc;
  780. new_file->write_proc = &fr_write_proc;
  781. new_file->size = 10;
  782. new_file->nlink = 1;
  783. MOD_INC_USE_COUNT;
  784. return 0;
  785. cleanup_filename_dlci:
  786.          remove_proc_entry(FILENAME_DLCI, ch->procdir);
  787. cleanup_LINE_privdata:
  788. kfree(fr);
  789. return -EIO;
  790. }
  791. static int dlci_open(struct net_device *dev)
  792. {
  793. struct comx_channel *ch = dev->priv;
  794. ch->init_status |= HW_OPEN;
  795. MOD_INC_USE_COUNT;
  796. return 0;
  797. }
  798. static int dlci_close(struct net_device *dev)
  799. {
  800. struct comx_channel *ch = dev->priv;
  801. ch->init_status &= ~HW_OPEN;
  802. MOD_DEC_USE_COUNT;
  803. return 0;
  804. }
  805. static int dlci_txe(struct net_device *dev)
  806. {
  807. struct comx_channel *ch = dev->priv;
  808. struct fr_data *fr = ch->LINE_privdata;
  809. if (!fr->master) {
  810. return 0;
  811. }
  812. ch = fr->master->priv;
  813. fr = ch->LINE_privdata;
  814. return ch->HW_txe(fr->master);
  815. }
  816. static int dlci_statistics(struct net_device *dev, char *page) 
  817. {
  818. return 0;
  819. }
  820. static int dlci_init(struct net_device *dev)
  821. {
  822. struct comx_channel *ch = dev->priv;
  823. ch->HW_open = dlci_open;
  824. ch->HW_close = dlci_close;
  825. ch->HW_txe = dlci_txe;
  826. ch->HW_statistics = dlci_statistics;
  827. /* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */
  828. MOD_INC_USE_COUNT;
  829. return 0;
  830. }
  831. static int dlci_exit(struct net_device *dev)
  832. {
  833. struct comx_channel *ch = dev->priv;
  834. ch->HW_open = NULL;
  835. ch->HW_close = NULL;
  836. ch->HW_txe = NULL;
  837. ch->HW_statistics = NULL;
  838. MOD_DEC_USE_COUNT;
  839. return 0;
  840. }
  841. static int dlci_dump(struct net_device *dev)
  842. {
  843. printk(KERN_INFO "dlci_dump %s, HOGY MI ???n", dev->name);
  844. return -1;
  845. }
  846. static struct comx_protocol fr_master_protocol = {
  847. name: "frad", 
  848. version: VERSION,
  849. encap_type: ARPHRD_FRAD, 
  850. line_init: fr_master_init, 
  851. line_exit: fr_exit, 
  852. };
  853. static struct comx_protocol fr_slave_protocol = {
  854. name: "ietf-ip", 
  855. version: VERSION,
  856. encap_type: ARPHRD_DLCI, 
  857. line_init: fr_slave_init, 
  858. line_exit: fr_exit, 
  859. };
  860. static struct comx_hardware fr_dlci = { 
  861. name: "dlci", 
  862. version: VERSION,
  863. hw_init: dlci_init, 
  864. hw_exit: dlci_exit, 
  865. hw_dump: dlci_dump, 
  866. };
  867. #ifdef MODULE
  868. #define comx_proto_fr_init init_module
  869. #endif
  870. int __init comx_proto_fr_init(void)
  871. {
  872. int ret; 
  873. if ((ret = comx_register_hardware(&fr_dlci))) {
  874. return ret;
  875. }
  876. if ((ret = comx_register_protocol(&fr_master_protocol))) {
  877. return ret;
  878. }
  879. return comx_register_protocol(&fr_slave_protocol);
  880. }
  881. #ifdef MODULE
  882. void cleanup_module(void)
  883. {
  884. comx_unregister_hardware(fr_dlci.name);
  885. comx_unregister_protocol(fr_master_protocol.name);
  886. comx_unregister_protocol(fr_slave_protocol.name);
  887. }
  888. #endif /* MODULE */