Merge with 2.3.99-pre9.
[linux-2.6/linux-mips.git] / drivers / net / wan / comx-proto-fr.c
blobf32c84e768468cfee34a723b8685c32a1886dc6d
1 /*
2 * Frame-relay protocol module for the COMX driver
3 * for Linux 2.2.X
5 * Original author: Tivadar Szemethy <tiv@itc.hu>
6 * Maintainer: Gergely Madarasz <gorgo@itc.hu>
8 * Copyright (C) 1998-1999 ITConsult-Pro Co. <info@itc.hu>
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.
15 * Version 0.70 (99/06/14):
16 * - cleaned up the source code a bit
17 * - ported back to kernel, now works as builtin code
19 * Version 0.71 (99/06/25):
20 * - use skb priorities and queues for sending keepalive
21 * - use device queues for slave->master data transmit
22 * - set IFF_RUNNING only line protocol up
23 * - fixes on slave device flags
25 * Version 0.72 (99/07/09):
26 * - handle slave tbusy with master tbusy (should be fixed)
27 * - fix the keepalive timer addition/deletion
30 #define VERSION "0.72"
32 #include <linux/module.h>
33 #include <linux/version.h>
34 #include <linux/types.h>
35 #include <linux/sched.h>
36 #include <linux/netdevice.h>
37 #include <linux/proc_fs.h>
38 #include <linux/if_arp.h>
39 #include <linux/inetdevice.h>
40 #include <linux/pkt_sched.h>
41 #include <linux/init.h>
42 #include <asm/uaccess.h>
44 #include "comx.h"
45 #include "comxhw.h"
47 MODULE_AUTHOR("Author: Tivadar Szemethy <tiv@itc.hu>");
48 MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers"
49 "for Linux kernel 2.2.X");
51 #define FRAD_UI 0x03
52 #define NLPID_IP 0xcc
53 #define NLPID_Q933_LMI 0x08
54 #define NLPID_CISCO_LMI 0x09
55 #define Q933_ENQ 0x75
56 #define Q933_LINESTAT 0x51
57 #define Q933_COUNTERS 0x53
59 #define MAXALIVECNT 3 /* No. of failures */
61 struct fr_data {
62 u16 dlci;
63 struct net_device *master;
64 char keepa_pend;
65 char keepa_freq;
66 char keepalivecnt, keeploopcnt;
67 struct timer_list keepa_timer;
68 u8 local_cnt, remote_cnt;
71 static struct comx_protocol fr_master_protocol;
72 static struct comx_protocol fr_slave_protocol;
73 static struct comx_hardware fr_dlci;
75 static void fr_keepalive_send(struct net_device *dev)
77 struct comx_channel *ch = dev->priv;
78 struct fr_data *fr = ch->LINE_privdata;
79 struct sk_buff *skb;
80 u8 *fr_packet;
82 skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC);
84 if(skb==NULL)
85 return;
87 skb_reserve(skb, dev->hard_header_len);
89 fr_packet=(u8*)skb_put(skb, 13);
91 fr_packet[0] = (fr->dlci & (1024 - 15)) >> 2;
92 fr_packet[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1
93 fr_packet[2] = FRAD_UI;
94 fr_packet[3] = NLPID_Q933_LMI;
95 fr_packet[4] = 0;
96 fr_packet[5] = Q933_ENQ;
97 fr_packet[6] = Q933_LINESTAT;
98 fr_packet[7] = 0x01;
99 fr_packet[8] = 0x01;
100 fr_packet[9] = Q933_COUNTERS;
101 fr_packet[10] = 0x02;
102 fr_packet[11] = ++fr->local_cnt;
103 fr_packet[12] = fr->remote_cnt;
105 skb->dev = dev;
106 skb->priority = TC_PRIO_CONTROL;
107 dev_queue_xmit(skb);
110 static void fr_keepalive_timerfun(unsigned long d)
112 struct net_device *dev = (struct net_device *)d;
113 struct comx_channel *ch = dev->priv;
114 struct fr_data *fr = ch->LINE_privdata;
115 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
116 struct comx_channel *sch;
117 struct fr_data *sfr;
118 struct net_device *sdev;
120 if (ch->init_status & LINE_OPEN) {
121 if (fr->keepalivecnt == MAXALIVECNT) {
122 comx_status(dev, ch->line_status & ~PROTO_UP);
123 dev->flags &= ~IFF_RUNNING;
124 for (; dir ; dir = dir->next) {
125 if(!S_ISDIR(dir->mode)) {
126 continue;
129 if ((sdev = dir->data) && (sch = sdev->priv) &&
130 (sdev->type == ARPHRD_DLCI) &&
131 (sfr = sch->LINE_privdata)
132 && (sfr->master == dev) &&
133 (sdev->flags & IFF_UP)) {
134 sdev->flags &= ~IFF_RUNNING;
135 comx_status(sdev,
136 sch->line_status & ~PROTO_UP);
140 if (fr->keepalivecnt <= MAXALIVECNT) {
141 ++fr->keepalivecnt;
143 fr_keepalive_send(dev);
145 mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq);
148 static void fr_rx_lmi(struct net_device *dev, struct sk_buff *skb,
149 u16 dlci, u8 nlpid)
151 struct comx_channel *ch = dev->priv;
152 struct fr_data *fr = ch->LINE_privdata;
153 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
154 struct comx_channel *sch;
155 struct fr_data *sfr;
156 struct net_device *sdev;
158 if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) {
159 return;
162 fr->remote_cnt = skb->data[7];
163 if (skb->data[8] == fr->local_cnt) { // keepalive UP!
164 fr->keepalivecnt = 0;
165 if ((ch->line_status & LINE_UP) &&
166 !(ch->line_status & PROTO_UP)) {
167 comx_status(dev, ch->line_status |= PROTO_UP);
168 dev->flags |= IFF_RUNNING;
169 for (; dir ; dir = dir->next) {
170 if(!S_ISDIR(dir->mode)) {
171 continue;
174 if ((sdev = dir->data) && (sch = sdev->priv) &&
175 (sdev->type == ARPHRD_DLCI) &&
176 (sfr = sch->LINE_privdata)
177 && (sfr->master == dev) &&
178 (sdev->flags & IFF_UP)) {
179 sdev->flags |= IFF_RUNNING;
180 comx_status(sdev,
181 sch->line_status | PROTO_UP);
188 static void fr_set_keepalive(struct net_device *dev, int keepa)
190 struct comx_channel *ch = dev->priv;
191 struct fr_data *fr = ch->LINE_privdata;
193 if (!keepa && fr->keepa_freq) { // switch off
194 fr->keepa_freq = 0;
195 if (ch->line_status & LINE_UP) {
196 comx_status(dev, ch->line_status | PROTO_UP);
197 dev->flags |= IFF_RUNNING;
198 del_timer(&fr->keepa_timer);
200 return;
203 if (keepa) { // bekapcs
204 if(fr->keepa_freq && (ch->line_status & LINE_UP)) {
205 del_timer(&fr->keepa_timer);
207 fr->keepa_freq = keepa;
208 fr->local_cnt = fr->remote_cnt = 0;
209 fr->keepa_timer.expires = jiffies + HZ;
210 fr->keepa_timer.function = fr_keepalive_timerfun;
211 fr->keepa_timer.data = (unsigned long)dev;
212 ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
213 dev->flags &= ~IFF_RUNNING;
214 comx_status(dev, ch->line_status);
215 if(ch->line_status & LINE_UP) {
216 add_timer(&fr->keepa_timer);
221 static void fr_rx(struct net_device *dev, struct sk_buff *skb)
223 struct comx_channel *ch = dev->priv;
224 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
225 struct net_device *sdev = dev;
226 struct comx_channel *sch;
227 struct fr_data *sfr;
228 u16 dlci;
229 u8 nlpid;
231 if(skb->len <= 4 || skb->data[2] != FRAD_UI) {
232 kfree_skb(skb);
233 return;
236 /* Itt majd ki kell talalni, melyik slave kapja a csomagot */
237 dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4);
238 if ((nlpid = skb->data[3]) == 0) { // Optional padding
239 nlpid = skb->data[4];
240 skb_pull(skb, 1);
242 skb_pull(skb, 4); /* DLCI and header throw away */
244 if (ch->debug_flags & DEBUG_COMX_DLCI) {
245 comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02x\n",
246 dlci, nlpid);
247 comx_debug_skb(dev, skb, "Contents");
250 /* Megkeressuk, kihez tartozik */
251 for (; dir ; dir = dir->next) {
252 if(!S_ISDIR(dir->mode)) {
253 continue;
255 if ((sdev = dir->data) && (sch = sdev->priv) &&
256 (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
257 (sfr->master == dev) && (sfr->dlci == dlci)) {
258 skb->dev = sdev;
259 if (ch->debug_flags & DEBUG_COMX_DLCI) {
260 comx_debug(dev, "Passing it to %s\n",sdev->name);
262 if (dev != sdev) {
263 sch->stats.rx_packets++;
264 sch->stats.rx_bytes += skb->len;
266 break;
269 switch(nlpid) {
270 case NLPID_IP:
271 skb->protocol = htons(ETH_P_IP);
272 skb->mac.raw = skb->data;
273 comx_rx(sdev, skb);
274 break;
275 case NLPID_Q933_LMI:
276 fr_rx_lmi(dev, skb, dlci, nlpid);
277 default:
278 kfree_skb(skb);
279 break;
283 static int fr_tx(struct net_device *dev)
285 struct comx_channel *ch = dev->priv;
286 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
287 struct net_device *sdev;
288 struct comx_channel *sch;
289 struct fr_data *sfr;
290 int cnt = 1;
292 /* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel,
293 es annal a slave-nel aki eppen kuldott.
294 Egy helyen akkor all, ha a master kuldott.
295 Ez megint jo lesz majd, ha utemezni akarunk */
297 /* This should be fixed, the slave tbusy should be set when
298 the masters queue is full and reset when not */
300 for (; dir ; dir = dir->next) {
301 if(!S_ISDIR(dir->mode)) {
302 continue;
304 if ((sdev = dir->data) && (sch = sdev->priv) &&
305 (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
306 (sfr->master == dev) && (netif_queue_stopped(sdev))) {
307 netif_wake_queue(sdev);
308 cnt++;
312 netif_wake_queue(dev);
313 return 0;
316 static void fr_status(struct net_device *dev, unsigned short status)
318 struct comx_channel *ch = dev->priv;
319 struct fr_data *fr = ch->LINE_privdata;
320 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
321 struct net_device *sdev;
322 struct comx_channel *sch;
323 struct fr_data *sfr;
325 if (status & LINE_UP) {
326 if (!fr->keepa_freq) {
327 status |= PROTO_UP;
329 } else {
330 status &= ~(PROTO_UP | PROTO_LOOP);
333 if (dev == fr->master && fr->keepa_freq) {
334 if (status & LINE_UP) {
335 fr->keepa_timer.expires = jiffies + HZ;
336 add_timer(&fr->keepa_timer);
337 fr->keepalivecnt = MAXALIVECNT + 1;
338 fr->keeploopcnt = 0;
339 } else {
340 del_timer(&fr->keepa_timer);
344 /* Itt a status valtozast vegig kell vinni az osszes slave-n */
345 for (; dir ; dir = dir->next) {
346 if(!S_ISDIR(dir->mode)) {
347 continue;
350 if ((sdev = dir->data) && (sch = sdev->priv) &&
351 (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) &&
352 (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
353 if(status & LINE_UP) {
354 netif_wake_queue(sdev);
356 comx_status(sdev, status);
357 if(status & (PROTO_UP | PROTO_LOOP)) {
358 dev->flags |= IFF_RUNNING;
359 } else {
360 dev->flags &= ~IFF_RUNNING;
366 static int fr_open(struct net_device *dev)
368 struct comx_channel *ch = dev->priv;
369 struct fr_data *fr = ch->LINE_privdata;
370 struct proc_dir_entry *comxdir = ch->procdir;
371 struct comx_channel *mch;
373 if (!(ch->init_status & HW_OPEN)) {
374 return -ENODEV;
377 if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) ||
378 (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) {
379 printk(KERN_ERR "Trying to open an improperly set FR interface, giving up\n");
380 return -EINVAL;
383 if (!fr->master) {
384 return -ENODEV;
386 mch = fr->master->priv;
387 if (fr->master != dev && (!(mch->init_status & LINE_OPEN)
388 || (mch->protocol != &fr_master_protocol))) {
389 printk(KERN_ERR "Master %s is inactive, or incorrectly set up, "
390 "unable to open %s\n", fr->master->name, dev->name);
391 return -ENODEV;
394 ch->init_status |= LINE_OPEN;
395 ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
396 dev->flags &= ~IFF_RUNNING;
398 if (fr->master == dev) {
399 if (fr->keepa_freq) {
400 fr->keepa_timer.function = fr_keepalive_timerfun;
401 fr->keepa_timer.data = (unsigned long)dev;
402 add_timer(&fr->keepa_timer);
403 } else {
404 if (ch->line_status & LINE_UP) {
405 ch->line_status |= PROTO_UP;
406 dev->flags |= IFF_RUNNING;
409 } else {
410 ch->line_status = mch->line_status;
411 if(fr->master->flags & IFF_RUNNING) {
412 dev->flags |= IFF_RUNNING;
416 for (; comxdir ; comxdir = comxdir->next) {
417 if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
418 strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
419 strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
420 comxdir->mode = S_IFREG | 0444;
423 // comx_status(dev, ch->line_status);
424 return 0;
427 static int fr_close(struct net_device *dev)
429 struct comx_channel *ch = dev->priv;
430 struct fr_data *fr = ch->LINE_privdata;
431 struct proc_dir_entry *comxdir = ch->procdir;
433 if (fr->master == dev) { // Ha master
434 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
435 struct net_device *sdev = dev;
436 struct comx_channel *sch;
437 struct fr_data *sfr;
439 if (!(ch->init_status & HW_OPEN)) {
440 return -ENODEV;
443 if (fr->keepa_freq) {
444 del_timer(&fr->keepa_timer);
447 for (; dir ; dir = dir->next) {
448 if(!S_ISDIR(dir->mode)) {
449 continue;
451 if ((sdev = dir->data) && (sch = sdev->priv) &&
452 (sdev->type == ARPHRD_DLCI) &&
453 (sfr = sch->LINE_privdata) &&
454 (sfr->master == dev) &&
455 (sch->init_status & LINE_OPEN)) {
456 dev_close(sdev);
461 ch->init_status &= ~LINE_OPEN;
462 ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
463 dev->flags &= ~IFF_RUNNING;
465 for (; comxdir ; comxdir = comxdir->next) {
466 if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
467 strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
468 strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
469 comxdir->mode = S_IFREG | 0444;
473 return 0;
476 static int fr_xmit(struct sk_buff *skb, struct net_device *dev)
478 struct comx_channel *ch = dev->priv;
479 struct comx_channel *sch, *mch;
480 struct fr_data *fr = ch->LINE_privdata;
481 struct fr_data *sfr;
482 struct net_device *sdev;
483 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
485 if (!fr->master) {
486 printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %s\n", dev->name);
487 return 0;
490 mch = fr->master->priv;
492 /* Ennek majd a slave utemezeskor lesz igazan jelentosege */
493 if (ch->debug_flags & DEBUG_COMX_DLCI) {
494 comx_debug_skb(dev, skb, "Sending frame");
497 if (dev != fr->master) {
498 struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
499 newskb->dev=fr->master;
500 dev_queue_xmit(newskb);
501 dev_kfree_skb(skb);
502 ch->stats.tx_packets++;
503 ch->stats.tx_bytes += skb->len;
504 } else {
505 netif_stop_queue(dev);
506 for (; dir ; dir = dir->next) {
507 if(!S_ISDIR(dir->mode)) {
508 continue;
510 if ((sdev = dir->data) && (sch = sdev->priv) &&
511 (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
512 (sfr->master == dev) && (netif_queue_stopped(sdev))) {
513 netif_stop_queue(sdev);
517 switch(mch->HW_send_packet(dev, skb)) {
518 case FRAME_QUEUED:
519 netif_wake_queue(dev);
520 break;
521 case FRAME_ACCEPTED:
522 case FRAME_DROPPED:
523 break;
524 case FRAME_ERROR:
525 printk(KERN_ERR "%s: Transmit frame error (len %d)\n",
526 dev->name, skb->len);
527 break;
530 return 0;
533 static int fr_header(struct sk_buff *skb, struct net_device *dev,
534 unsigned short type, void *daddr, void *saddr, unsigned len)
536 struct comx_channel *ch = dev->priv;
537 struct fr_data *fr = ch->LINE_privdata;
539 skb_push(skb, dev->hard_header_len);
540 /* Put in DLCI */
541 skb->data[0] = (fr->dlci & (1024 - 15)) >> 2;
542 skb->data[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1
543 skb->data[2] = FRAD_UI;
544 skb->data[3] = NLPID_IP;
546 return dev->hard_header_len;
549 static int fr_statistics(struct net_device *dev, char *page)
551 struct comx_channel *ch = dev->priv;
552 struct fr_data *fr = ch->LINE_privdata;
553 int len = 0;
555 if (fr->master == dev) {
556 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
557 struct net_device *sdev;
558 struct comx_channel *sch;
559 struct fr_data *sfr;
560 int slaves = 0;
562 len += sprintf(page + len,
563 "This is a Frame Relay master device\nSlaves: ");
564 for (; dir ; dir = dir->next) {
565 if(!S_ISDIR(dir->mode)) {
566 continue;
568 if ((sdev = dir->data) && (sch = sdev->priv) &&
569 (sdev->type == ARPHRD_DLCI) &&
570 (sfr = sch->LINE_privdata) &&
571 (sfr->master == dev) && (sdev != dev)) {
572 slaves++;
573 len += sprintf(page + len, "%s ", sdev->name);
576 len += sprintf(page + len, "%s\n", slaves ? "" : "(none)");
577 if (fr->keepa_freq) {
578 len += sprintf(page + len, "Line keepalive (value %d) "
579 "status %s [%d]\n", fr->keepa_freq,
580 ch->line_status & PROTO_LOOP ? "LOOP" :
581 ch->line_status & PROTO_UP ? "UP" : "DOWN",
582 fr->keepalivecnt);
583 } else {
584 len += sprintf(page + len, "Line keepalive protocol "
585 "is not set\n");
587 } else { // if slave
588 len += sprintf(page + len,
589 "This is a Frame Relay slave device, master: %s\n",
590 fr->master ? fr->master->name : "(not set)");
592 return len;
595 static int fr_read_proc(char *page, char **start, off_t off, int count,
596 int *eof, void *data)
598 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
599 struct net_device *dev = file->parent->data;
600 struct comx_channel *ch = dev->priv;
601 struct fr_data *fr = NULL;
602 int len = 0;
604 if (ch) {
605 fr = ch->LINE_privdata;
608 if (strcmp(file->name, FILENAME_DLCI) == 0) {
609 len = sprintf(page, "%04d\n", fr->dlci);
610 } else if (strcmp(file->name, FILENAME_MASTER) == 0) {
611 len = sprintf(page, "%-9s\n", fr->master ? fr->master->name :
612 "(none)");
613 } else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) {
614 len = fr->keepa_freq ? sprintf(page, "% 3d\n", fr->keepa_freq)
615 : sprintf(page, "off\n");
616 } else {
617 printk(KERN_ERR "comxfr: internal error, filename %s\n", file->name);
618 return -EBADF;
621 if (off >= len) {
622 *eof = 1;
623 return 0;
626 *start = page + off;
627 if (count >= len - off) *eof = 1;
628 return ( min(count, len - off) );
631 static int fr_write_proc(struct file *file, const char *buffer,
632 u_long count, void *data)
634 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
635 struct net_device *dev = entry->parent->data;
636 struct comx_channel *ch = dev->priv;
637 struct fr_data *fr = NULL;
638 char *page;
640 if (ch) {
641 fr = ch->LINE_privdata;
644 if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
645 return -ENOMEM;
648 copy_from_user(page, buffer, count);
649 if (*(page + count - 1) == '\n') {
650 *(page + count - 1) = 0;
653 if (strcmp(entry->name, FILENAME_DLCI) == 0) {
654 u16 dlci_new = simple_strtoul(page, NULL, 10);
656 if (dlci_new > 1023) {
657 printk(KERN_ERR "Invalid DLCI value\n");
659 else fr->dlci = dlci_new;
660 } else if (strcmp(entry->name, FILENAME_MASTER) == 0) {
661 struct net_device *new_master = dev_get_by_name(page);
663 if (new_master && new_master->type == ARPHRD_FRAD) {
664 struct comx_channel *sch = new_master->priv;
665 struct fr_data *sfr = sch->LINE_privdata;
667 if (sfr && sfr->master == new_master) {
668 if(fr->master)
669 dev_put(fr->master);
670 fr->master = new_master;
671 /* Megorokli a master statuszat */
672 ch->line_status = sch->line_status;
675 } else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) {
676 int keepa_new = -1;
678 if (strcmp(page, KEEPALIVE_OFF) == 0) {
679 keepa_new = 0;
680 } else {
681 keepa_new = simple_strtoul(page, NULL, 10);
684 if (keepa_new < 0 || keepa_new > 100) {
685 printk(KERN_ERR "invalid keepalive\n");
686 } else {
687 if (fr->keepa_freq && keepa_new != fr->keepa_freq) {
688 fr_set_keepalive(dev, 0);
690 if (keepa_new) {
691 fr_set_keepalive(dev, keepa_new);
694 } else {
695 printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n",
696 entry->name);
697 return -EBADF;
700 free_page((unsigned long)page);
701 return count;
704 static int fr_exit(struct net_device *dev)
706 struct comx_channel *ch = dev->priv;
707 struct fr_data *fr = ch->LINE_privdata;
708 struct net_device *sdev = dev;
709 struct comx_channel *sch;
710 struct fr_data *sfr;
711 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
713 /* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */
714 if (fr->master && fr->master == dev) {
715 for (; dir ; dir = dir->next) {
716 if(!S_ISDIR(dir->mode)) {
717 continue;
719 if ((sdev = dir->data) && (sch = sdev->priv) &&
720 (sdev->type == ARPHRD_DLCI) &&
721 (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
722 dev_close(sdev);
723 sfr->master = NULL;
727 dev->flags = 0;
728 dev->type = 0;
729 dev->mtu = 0;
730 dev->hard_header_len = 0;
732 ch->LINE_rx = NULL;
733 ch->LINE_tx = NULL;
734 ch->LINE_status = NULL;
735 ch->LINE_open = NULL;
736 ch->LINE_close = NULL;
737 ch->LINE_xmit = NULL;
738 ch->LINE_header = NULL;
739 ch->LINE_rebuild_header = NULL;
740 ch->LINE_statistics = NULL;
742 ch->LINE_status = 0;
744 if (fr->master != dev) { // if not master, remove dlci
745 if(fr->master)
746 dev_put(fr->master);
747 remove_proc_entry(FILENAME_DLCI, ch->procdir);
748 remove_proc_entry(FILENAME_MASTER, ch->procdir);
749 } else {
750 if (fr->keepa_freq) {
751 fr_set_keepalive(dev, 0);
753 remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir);
754 remove_proc_entry(FILENAME_DLCI, ch->procdir);
757 kfree(fr);
758 ch->LINE_privdata = NULL;
760 MOD_DEC_USE_COUNT;
761 return 0;
764 static int fr_master_init(struct net_device *dev)
766 struct comx_channel *ch = dev->priv;
767 struct fr_data *fr;
768 struct proc_dir_entry *new_file;
770 if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data),
771 GFP_KERNEL)) == NULL) {
772 return -ENOMEM;
774 memset(fr, 0, sizeof(struct fr_data));
775 fr->master = dev; // this means master
776 fr->dlci = 0; // let's say default
778 dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
779 dev->type = ARPHRD_FRAD;
780 dev->mtu = 1500;
781 dev->hard_header_len = 4;
782 dev->addr_len = 0;
784 ch->LINE_rx = fr_rx;
785 ch->LINE_tx = fr_tx;
786 ch->LINE_status = fr_status;
787 ch->LINE_open = fr_open;
788 ch->LINE_close = fr_close;
789 ch->LINE_xmit = fr_xmit;
790 ch->LINE_header = fr_header;
791 ch->LINE_rebuild_header = NULL;
792 ch->LINE_statistics = fr_statistics;
794 if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644,
795 ch->procdir)) == NULL) {
796 return -ENOMEM;
798 new_file->data = (void *)new_file;
799 new_file->read_proc = &fr_read_proc;
800 new_file->write_proc = &fr_write_proc;
801 new_file->size = 5;
802 new_file->nlink = 1;
804 if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644,
805 ch->procdir)) == NULL) {
806 return -ENOMEM;
808 new_file->data = (void *)new_file;
809 new_file->read_proc = &fr_read_proc;
810 new_file->write_proc = &fr_write_proc;
811 new_file->size = 4;
812 new_file->nlink = 1;
814 fr_set_keepalive(dev, 0);
816 MOD_INC_USE_COUNT;
817 return 0;
820 static int fr_slave_init(struct net_device *dev)
822 struct comx_channel *ch = dev->priv;
823 struct fr_data *fr;
824 struct proc_dir_entry *new_file;
826 if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data),
827 GFP_KERNEL)) == NULL) {
828 return -ENOMEM;
830 memset(fr, 0, sizeof(struct fr_data));
832 dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
833 dev->type = ARPHRD_DLCI;
834 dev->mtu = 1500;
835 dev->hard_header_len = 4;
836 dev->addr_len = 0;
838 ch->LINE_rx = fr_rx;
839 ch->LINE_tx = fr_tx;
840 ch->LINE_status = fr_status;
841 ch->LINE_open = fr_open;
842 ch->LINE_close = fr_close;
843 ch->LINE_xmit = fr_xmit;
844 ch->LINE_header = fr_header;
845 ch->LINE_rebuild_header = NULL;
846 ch->LINE_statistics = fr_statistics;
848 if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644,
849 ch->procdir)) == NULL) {
850 return -ENOMEM;
853 new_file->data = (void *)new_file;
854 new_file->read_proc = &fr_read_proc;
855 new_file->write_proc = &fr_write_proc;
856 new_file->size = 5;
857 new_file->nlink = 1;
859 if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644,
860 ch->procdir)) == NULL) {
861 return -EIO;
863 new_file->data = (void *)new_file;
864 new_file->read_proc = &fr_read_proc;
865 new_file->write_proc = &fr_write_proc;
866 new_file->size = 10;
867 new_file->nlink = 1;
868 MOD_INC_USE_COUNT;
869 return 0;
872 static int dlci_open(struct net_device *dev)
874 struct comx_channel *ch = dev->priv;
876 ch->init_status |= HW_OPEN;
878 MOD_INC_USE_COUNT;
879 return 0;
882 static int dlci_close(struct net_device *dev)
884 struct comx_channel *ch = dev->priv;
886 ch->init_status &= ~HW_OPEN;
888 MOD_DEC_USE_COUNT;
889 return 0;
892 static int dlci_txe(struct net_device *dev)
894 struct comx_channel *ch = dev->priv;
895 struct fr_data *fr = ch->LINE_privdata;
897 if (!fr->master) {
898 return 0;
901 ch = fr->master->priv;
902 fr = ch->LINE_privdata;
903 return ch->HW_txe(fr->master);
906 static int dlci_statistics(struct net_device *dev, char *page)
908 return 0;
911 static int dlci_init(struct net_device *dev)
913 struct comx_channel *ch = dev->priv;
915 ch->HW_open = dlci_open;
916 ch->HW_close = dlci_close;
917 ch->HW_txe = dlci_txe;
918 ch->HW_statistics = dlci_statistics;
920 /* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */
922 MOD_INC_USE_COUNT;
923 return 0;
926 static int dlci_exit(struct net_device *dev)
928 struct comx_channel *ch = dev->priv;
930 ch->HW_open = NULL;
931 ch->HW_close = NULL;
932 ch->HW_txe = NULL;
933 ch->HW_statistics = NULL;
935 MOD_DEC_USE_COUNT;
936 return 0;
939 static int dlci_dump(struct net_device *dev)
941 printk(KERN_INFO "dlci_dump %s, HOGY MI ???\n", dev->name);
942 return -1;
945 static struct comx_protocol fr_master_protocol = {
946 "frad",
947 VERSION,
948 ARPHRD_FRAD,
949 fr_master_init,
950 fr_exit,
951 NULL
954 static struct comx_protocol fr_slave_protocol = {
955 "ietf-ip",
956 VERSION,
957 ARPHRD_DLCI,
958 fr_slave_init,
959 fr_exit,
960 NULL
963 static struct comx_hardware fr_dlci = {
964 "dlci",
965 VERSION,
966 dlci_init,
967 dlci_exit,
968 dlci_dump,
969 NULL
972 #ifdef MODULE
973 #define comx_proto_fr_init init_module
974 #endif
976 int __init comx_proto_fr_init(void)
978 int ret;
980 if ((ret = comx_register_hardware(&fr_dlci))) {
981 return ret;
983 if ((ret = comx_register_protocol(&fr_master_protocol))) {
984 return ret;
986 return comx_register_protocol(&fr_slave_protocol);
989 #ifdef MODULE
990 void cleanup_module(void)
992 comx_unregister_hardware(fr_dlci.name);
993 comx_unregister_protocol(fr_master_protocol.name);
994 comx_unregister_protocol(fr_slave_protocol.name);
996 #endif /* MODULE */