2 * Frame-relay protocol module for the COMX driver
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>
11 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.73)
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.
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
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
28 * Version 0.72 (99/07/09):
29 * - handle slave tbusy with master tbusy (should be fixed)
30 * - fix the keepalive timer addition/deletion
32 * Version 0.73 (00/08/15)
33 * - resource release on failure at fr_master_init and
37 #define VERSION "0.73"
39 #include <linux/module.h>
40 #include <linux/types.h>
41 #include <linux/jiffies.h>
42 #include <linux/netdevice.h>
43 #include <linux/proc_fs.h>
44 #include <linux/if_arp.h>
45 #include <linux/inetdevice.h>
46 #include <linux/pkt_sched.h>
47 #include <linux/init.h>
49 #include <asm/uaccess.h>
54 MODULE_AUTHOR("Author: Tivadar Szemethy <tiv@itc.hu>");
55 MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers"
56 "for Linux kernel 2.4.X");
57 MODULE_LICENSE("GPL");
61 #define NLPID_Q933_LMI 0x08
62 #define NLPID_CISCO_LMI 0x09
64 #define Q933_LINESTAT 0x51
65 #define Q933_COUNTERS 0x53
67 #define MAXALIVECNT 3 /* No. of failures */
71 struct net_device *master;
74 char keepalivecnt, keeploopcnt;
75 struct timer_list keepa_timer;
76 u8 local_cnt, remote_cnt;
79 static struct comx_protocol fr_master_protocol;
80 static struct comx_protocol fr_slave_protocol;
81 static struct comx_hardware fr_dlci;
83 static void fr_keepalive_send(struct net_device *dev)
85 struct comx_channel *ch = dev->priv;
86 struct fr_data *fr = ch->LINE_privdata;
90 skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC);
95 skb_reserve(skb, dev->hard_header_len);
97 fr_packet=(u8*)skb_put(skb, 13);
99 fr_packet[0] = (fr->dlci & (1024 - 15)) >> 2;
100 fr_packet[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1
101 fr_packet[2] = FRAD_UI;
102 fr_packet[3] = NLPID_Q933_LMI;
104 fr_packet[5] = Q933_ENQ;
105 fr_packet[6] = Q933_LINESTAT;
108 fr_packet[9] = Q933_COUNTERS;
109 fr_packet[10] = 0x02;
110 fr_packet[11] = ++fr->local_cnt;
111 fr_packet[12] = fr->remote_cnt;
114 skb->priority = TC_PRIO_CONTROL;
118 static void fr_keepalive_timerfun(unsigned long d)
120 struct net_device *dev = (struct net_device *)d;
121 struct comx_channel *ch = dev->priv;
122 struct fr_data *fr = ch->LINE_privdata;
123 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
124 struct comx_channel *sch;
126 struct net_device *sdev;
128 if (ch->init_status & LINE_OPEN) {
129 if (fr->keepalivecnt == MAXALIVECNT) {
130 comx_status(dev, ch->line_status & ~PROTO_UP);
131 dev->flags &= ~IFF_RUNNING;
132 for (; dir ; dir = dir->next) {
133 if(!S_ISDIR(dir->mode)) {
137 if ((sdev = dir->data) && (sch = sdev->priv) &&
138 (sdev->type == ARPHRD_DLCI) &&
139 (sfr = sch->LINE_privdata)
140 && (sfr->master == dev) &&
141 (sdev->flags & IFF_UP)) {
142 sdev->flags &= ~IFF_RUNNING;
144 sch->line_status & ~PROTO_UP);
148 if (fr->keepalivecnt <= MAXALIVECNT) {
151 fr_keepalive_send(dev);
153 mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq);
156 static void fr_rx_lmi(struct net_device *dev, struct sk_buff *skb,
159 struct comx_channel *ch = dev->priv;
160 struct fr_data *fr = ch->LINE_privdata;
161 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
162 struct comx_channel *sch;
164 struct net_device *sdev;
166 if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) {
170 fr->remote_cnt = skb->data[7];
171 if (skb->data[8] == fr->local_cnt) { // keepalive UP!
172 fr->keepalivecnt = 0;
173 if ((ch->line_status & LINE_UP) &&
174 !(ch->line_status & PROTO_UP)) {
175 comx_status(dev, ch->line_status |= PROTO_UP);
176 dev->flags |= IFF_RUNNING;
177 for (; dir ; dir = dir->next) {
178 if(!S_ISDIR(dir->mode)) {
182 if ((sdev = dir->data) && (sch = sdev->priv) &&
183 (sdev->type == ARPHRD_DLCI) &&
184 (sfr = sch->LINE_privdata)
185 && (sfr->master == dev) &&
186 (sdev->flags & IFF_UP)) {
187 sdev->flags |= IFF_RUNNING;
189 sch->line_status | PROTO_UP);
196 static void fr_set_keepalive(struct net_device *dev, int keepa)
198 struct comx_channel *ch = dev->priv;
199 struct fr_data *fr = ch->LINE_privdata;
201 if (!keepa && fr->keepa_freq) { // switch off
203 if (ch->line_status & LINE_UP) {
204 comx_status(dev, ch->line_status | PROTO_UP);
205 dev->flags |= IFF_RUNNING;
206 del_timer(&fr->keepa_timer);
211 if (keepa) { // bekapcs
212 if(fr->keepa_freq && (ch->line_status & LINE_UP)) {
213 del_timer(&fr->keepa_timer);
215 fr->keepa_freq = keepa;
216 fr->local_cnt = fr->remote_cnt = 0;
217 init_timer(&fr->keepa_timer);
218 fr->keepa_timer.expires = jiffies + HZ;
219 fr->keepa_timer.function = fr_keepalive_timerfun;
220 fr->keepa_timer.data = (unsigned long)dev;
221 ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
222 dev->flags &= ~IFF_RUNNING;
223 comx_status(dev, ch->line_status);
224 if(ch->line_status & LINE_UP) {
225 add_timer(&fr->keepa_timer);
230 static void fr_rx(struct net_device *dev, struct sk_buff *skb)
232 struct comx_channel *ch = dev->priv;
233 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
234 struct net_device *sdev = dev;
235 struct comx_channel *sch;
240 if(skb->len <= 4 || skb->data[2] != FRAD_UI) {
245 /* Itt majd ki kell talalni, melyik slave kapja a csomagot */
246 dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4);
247 if ((nlpid = skb->data[3]) == 0) { // Optional padding
248 nlpid = skb->data[4];
251 skb_pull(skb, 4); /* DLCI and header throw away */
253 if (ch->debug_flags & DEBUG_COMX_DLCI) {
254 comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02x\n",
256 comx_debug_skb(dev, skb, "Contents");
259 /* Megkeressuk, kihez tartozik */
260 for (; dir ; dir = dir->next) {
261 if(!S_ISDIR(dir->mode)) {
264 if ((sdev = dir->data) && (sch = sdev->priv) &&
265 (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
266 (sfr->master == dev) && (sfr->dlci == dlci)) {
268 if (ch->debug_flags & DEBUG_COMX_DLCI) {
269 comx_debug(dev, "Passing it to %s\n",sdev->name);
272 sch->stats.rx_packets++;
273 sch->stats.rx_bytes += skb->len;
280 skb->protocol = htons(ETH_P_IP);
281 skb->mac.raw = skb->data;
285 fr_rx_lmi(dev, skb, dlci, nlpid);
292 static int fr_tx(struct net_device *dev)
294 struct comx_channel *ch = dev->priv;
295 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
296 struct net_device *sdev;
297 struct comx_channel *sch;
301 /* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel,
302 es annal a slave-nel aki eppen kuldott.
303 Egy helyen akkor all, ha a master kuldott.
304 Ez megint jo lesz majd, ha utemezni akarunk */
306 /* This should be fixed, the slave tbusy should be set when
307 the masters queue is full and reset when not */
309 for (; dir ; dir = dir->next) {
310 if(!S_ISDIR(dir->mode)) {
313 if ((sdev = dir->data) && (sch = sdev->priv) &&
314 (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
315 (sfr->master == dev) && (netif_queue_stopped(sdev))) {
316 netif_wake_queue(sdev);
321 netif_wake_queue(dev);
325 static void fr_status(struct net_device *dev, unsigned short status)
327 struct comx_channel *ch = dev->priv;
328 struct fr_data *fr = ch->LINE_privdata;
329 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
330 struct net_device *sdev;
331 struct comx_channel *sch;
334 if (status & LINE_UP) {
335 if (!fr->keepa_freq) {
339 status &= ~(PROTO_UP | PROTO_LOOP);
342 if (dev == fr->master && fr->keepa_freq) {
343 if (status & LINE_UP) {
344 fr->keepa_timer.expires = jiffies + HZ;
345 add_timer(&fr->keepa_timer);
346 fr->keepalivecnt = MAXALIVECNT + 1;
349 del_timer(&fr->keepa_timer);
353 /* Itt a status valtozast vegig kell vinni az osszes slave-n */
354 for (; dir ; dir = dir->next) {
355 if(!S_ISDIR(dir->mode)) {
359 if ((sdev = dir->data) && (sch = sdev->priv) &&
360 (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) &&
361 (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
362 if(status & LINE_UP) {
363 netif_wake_queue(sdev);
365 comx_status(sdev, status);
366 if(status & (PROTO_UP | PROTO_LOOP)) {
367 dev->flags |= IFF_RUNNING;
369 dev->flags &= ~IFF_RUNNING;
375 static int fr_open(struct net_device *dev)
377 struct comx_channel *ch = dev->priv;
378 struct fr_data *fr = ch->LINE_privdata;
379 struct proc_dir_entry *comxdir = ch->procdir;
380 struct comx_channel *mch;
382 if (!(ch->init_status & HW_OPEN)) {
386 if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) ||
387 (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) {
388 printk(KERN_ERR "Trying to open an improperly set FR interface, giving up\n");
395 mch = fr->master->priv;
396 if (fr->master != dev && (!(mch->init_status & LINE_OPEN)
397 || (mch->protocol != &fr_master_protocol))) {
398 printk(KERN_ERR "Master %s is inactive, or incorrectly set up, "
399 "unable to open %s\n", fr->master->name, dev->name);
403 ch->init_status |= LINE_OPEN;
404 ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
405 dev->flags &= ~IFF_RUNNING;
407 if (fr->master == dev) {
408 if (fr->keepa_freq) {
409 fr->keepa_timer.function = fr_keepalive_timerfun;
410 fr->keepa_timer.data = (unsigned long)dev;
411 add_timer(&fr->keepa_timer);
413 if (ch->line_status & LINE_UP) {
414 ch->line_status |= PROTO_UP;
415 dev->flags |= IFF_RUNNING;
419 ch->line_status = mch->line_status;
420 if(fr->master->flags & IFF_RUNNING) {
421 dev->flags |= IFF_RUNNING;
425 for (; comxdir ; comxdir = comxdir->next) {
426 if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
427 strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
428 strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
429 comxdir->mode = S_IFREG | 0444;
432 // comx_status(dev, ch->line_status);
436 static int fr_close(struct net_device *dev)
438 struct comx_channel *ch = dev->priv;
439 struct fr_data *fr = ch->LINE_privdata;
440 struct proc_dir_entry *comxdir = ch->procdir;
442 if (fr->master == dev) { // Ha master
443 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
444 struct net_device *sdev = dev;
445 struct comx_channel *sch;
448 if (!(ch->init_status & HW_OPEN)) {
452 if (fr->keepa_freq) {
453 del_timer(&fr->keepa_timer);
456 for (; dir ; dir = dir->next) {
457 if(!S_ISDIR(dir->mode)) {
460 if ((sdev = dir->data) && (sch = sdev->priv) &&
461 (sdev->type == ARPHRD_DLCI) &&
462 (sfr = sch->LINE_privdata) &&
463 (sfr->master == dev) &&
464 (sch->init_status & LINE_OPEN)) {
470 ch->init_status &= ~LINE_OPEN;
471 ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
472 dev->flags &= ~IFF_RUNNING;
474 for (; comxdir ; comxdir = comxdir->next) {
475 if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
476 strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
477 strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
478 comxdir->mode = S_IFREG | 0444;
485 static int fr_xmit(struct sk_buff *skb, struct net_device *dev)
487 struct comx_channel *ch = dev->priv;
488 struct comx_channel *sch, *mch;
489 struct fr_data *fr = ch->LINE_privdata;
491 struct net_device *sdev;
492 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
495 printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %s\n", dev->name);
499 mch = fr->master->priv;
501 /* Ennek majd a slave utemezeskor lesz igazan jelentosege */
502 if (ch->debug_flags & DEBUG_COMX_DLCI) {
503 comx_debug_skb(dev, skb, "Sending frame");
506 if (dev != fr->master) {
507 struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
510 newskb->dev=fr->master;
511 dev_queue_xmit(newskb);
512 ch->stats.tx_bytes += skb->len;
513 ch->stats.tx_packets++;
516 netif_stop_queue(dev);
517 for (; dir ; dir = dir->next) {
518 if(!S_ISDIR(dir->mode)) {
521 if ((sdev = dir->data) && (sch = sdev->priv) &&
522 (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
523 (sfr->master == dev) && (netif_queue_stopped(sdev))) {
524 netif_stop_queue(sdev);
528 switch(mch->HW_send_packet(dev, skb)) {
530 netif_wake_queue(dev);
536 printk(KERN_ERR "%s: Transmit frame error (len %d)\n",
537 dev->name, skb->len);
544 static int fr_header(struct sk_buff *skb, struct net_device *dev,
545 unsigned short type, void *daddr, void *saddr, unsigned len)
547 struct comx_channel *ch = dev->priv;
548 struct fr_data *fr = ch->LINE_privdata;
550 skb_push(skb, dev->hard_header_len);
552 skb->data[0] = (fr->dlci & (1024 - 15)) >> 2;
553 skb->data[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1
554 skb->data[2] = FRAD_UI;
555 skb->data[3] = NLPID_IP;
557 return dev->hard_header_len;
560 static int fr_statistics(struct net_device *dev, char *page)
562 struct comx_channel *ch = dev->priv;
563 struct fr_data *fr = ch->LINE_privdata;
566 if (fr->master == dev) {
567 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
568 struct net_device *sdev;
569 struct comx_channel *sch;
573 len += sprintf(page + len,
574 "This is a Frame Relay master device\nSlaves: ");
575 for (; dir ; dir = dir->next) {
576 if(!S_ISDIR(dir->mode)) {
579 if ((sdev = dir->data) && (sch = sdev->priv) &&
580 (sdev->type == ARPHRD_DLCI) &&
581 (sfr = sch->LINE_privdata) &&
582 (sfr->master == dev) && (sdev != dev)) {
584 len += sprintf(page + len, "%s ", sdev->name);
587 len += sprintf(page + len, "%s\n", slaves ? "" : "(none)");
588 if (fr->keepa_freq) {
589 len += sprintf(page + len, "Line keepalive (value %d) "
590 "status %s [%d]\n", fr->keepa_freq,
591 ch->line_status & PROTO_LOOP ? "LOOP" :
592 ch->line_status & PROTO_UP ? "UP" : "DOWN",
595 len += sprintf(page + len, "Line keepalive protocol "
599 len += sprintf(page + len,
600 "This is a Frame Relay slave device, master: %s\n",
601 fr->master ? fr->master->name : "(not set)");
606 static int fr_read_proc(char *page, char **start, off_t off, int count,
607 int *eof, void *data)
609 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
610 struct net_device *dev = file->parent->data;
611 struct comx_channel *ch = dev->priv;
612 struct fr_data *fr = NULL;
616 fr = ch->LINE_privdata;
619 if (strcmp(file->name, FILENAME_DLCI) == 0) {
620 len = sprintf(page, "%04d\n", fr->dlci);
621 } else if (strcmp(file->name, FILENAME_MASTER) == 0) {
622 len = sprintf(page, "%-9s\n", fr->master ? fr->master->name :
624 } else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) {
625 len = fr->keepa_freq ? sprintf(page, "% 3d\n", fr->keepa_freq)
626 : sprintf(page, "off\n");
628 printk(KERN_ERR "comxfr: internal error, filename %s\n", file->name);
638 if (count >= len - off) *eof = 1;
639 return min_t(int, count, len - off);
642 static int fr_write_proc(struct file *file, const char *buffer,
643 u_long count, void *data)
645 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
646 struct net_device *dev = entry->parent->data;
647 struct comx_channel *ch = dev->priv;
648 struct fr_data *fr = NULL;
652 fr = ch->LINE_privdata;
655 if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
659 if (copy_from_user(page, buffer, count)) {
660 free_page((unsigned long)page);
663 if (*(page + count - 1) == '\n') {
664 *(page + count - 1) = 0;
667 if (strcmp(entry->name, FILENAME_DLCI) == 0) {
668 u16 dlci_new = simple_strtoul(page, NULL, 10);
670 if (dlci_new > 1023) {
671 printk(KERN_ERR "Invalid DLCI value\n");
673 else fr->dlci = dlci_new;
674 } else if (strcmp(entry->name, FILENAME_MASTER) == 0) {
675 struct net_device *new_master = dev_get_by_name(page);
677 if (new_master && new_master->type == ARPHRD_FRAD) {
678 struct comx_channel *sch = new_master->priv;
679 struct fr_data *sfr = sch->LINE_privdata;
681 if (sfr && sfr->master == new_master) {
684 fr->master = new_master;
685 /* Megorokli a master statuszat */
686 ch->line_status = sch->line_status;
689 } else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) {
692 if (strcmp(page, KEEPALIVE_OFF) == 0) {
695 keepa_new = simple_strtoul(page, NULL, 10);
698 if (keepa_new < 0 || keepa_new > 100) {
699 printk(KERN_ERR "invalid keepalive\n");
701 if (fr->keepa_freq && keepa_new != fr->keepa_freq) {
702 fr_set_keepalive(dev, 0);
705 fr_set_keepalive(dev, keepa_new);
709 printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n",
714 free_page((unsigned long)page);
718 static int fr_exit(struct net_device *dev)
720 struct comx_channel *ch = dev->priv;
721 struct fr_data *fr = ch->LINE_privdata;
722 struct net_device *sdev = dev;
723 struct comx_channel *sch;
725 struct proc_dir_entry *dir = ch->procdir->parent->subdir;
727 /* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */
728 if (fr->master && fr->master == dev) {
729 for (; dir ; dir = dir->next) {
730 if(!S_ISDIR(dir->mode)) {
733 if ((sdev = dir->data) && (sch = sdev->priv) &&
734 (sdev->type == ARPHRD_DLCI) &&
735 (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
744 dev->hard_header_len = 0;
748 ch->LINE_status = NULL;
749 ch->LINE_open = NULL;
750 ch->LINE_close = NULL;
751 ch->LINE_xmit = NULL;
752 ch->LINE_header = NULL;
753 ch->LINE_rebuild_header = NULL;
754 ch->LINE_statistics = NULL;
758 if (fr->master != dev) { // if not master, remove dlci
761 remove_proc_entry(FILENAME_DLCI, ch->procdir);
762 remove_proc_entry(FILENAME_MASTER, ch->procdir);
764 if (fr->keepa_freq) {
765 fr_set_keepalive(dev, 0);
767 remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir);
768 remove_proc_entry(FILENAME_DLCI, ch->procdir);
772 ch->LINE_privdata = NULL;
778 static int fr_master_init(struct net_device *dev)
780 struct comx_channel *ch = dev->priv;
782 struct proc_dir_entry *new_file;
784 if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data),
785 GFP_KERNEL)) == NULL) {
788 memset(fr, 0, sizeof(struct fr_data));
789 fr->master = dev; // this means master
790 fr->dlci = 0; // let's say default
792 dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
793 dev->type = ARPHRD_FRAD;
795 dev->hard_header_len = 4;
800 ch->LINE_status = fr_status;
801 ch->LINE_open = fr_open;
802 ch->LINE_close = fr_close;
803 ch->LINE_xmit = fr_xmit;
804 ch->LINE_header = fr_header;
805 ch->LINE_rebuild_header = NULL;
806 ch->LINE_statistics = fr_statistics;
808 if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644,
809 ch->procdir)) == NULL) {
810 goto cleanup_LINE_privdata;
812 new_file->data = (void *)new_file;
813 new_file->read_proc = &fr_read_proc;
814 new_file->write_proc = &fr_write_proc;
818 if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644,
819 ch->procdir)) == NULL) {
820 goto cleanup_filename_dlci;
822 new_file->data = (void *)new_file;
823 new_file->read_proc = &fr_read_proc;
824 new_file->write_proc = &fr_write_proc;
828 fr_set_keepalive(dev, 0);
832 cleanup_filename_dlci:
833 remove_proc_entry(FILENAME_DLCI, ch->procdir);
834 cleanup_LINE_privdata:
839 static int fr_slave_init(struct net_device *dev)
841 struct comx_channel *ch = dev->priv;
843 struct proc_dir_entry *new_file;
845 if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data),
846 GFP_KERNEL)) == NULL) {
849 memset(fr, 0, sizeof(struct fr_data));
851 dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
852 dev->type = ARPHRD_DLCI;
854 dev->hard_header_len = 4;
859 ch->LINE_status = fr_status;
860 ch->LINE_open = fr_open;
861 ch->LINE_close = fr_close;
862 ch->LINE_xmit = fr_xmit;
863 ch->LINE_header = fr_header;
864 ch->LINE_rebuild_header = NULL;
865 ch->LINE_statistics = fr_statistics;
867 if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644,
868 ch->procdir)) == NULL) {
869 goto cleanup_LINE_privdata;
872 new_file->data = (void *)new_file;
873 new_file->read_proc = &fr_read_proc;
874 new_file->write_proc = &fr_write_proc;
878 if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644,
879 ch->procdir)) == NULL) {
880 goto cleanup_filename_dlci;
882 new_file->data = (void *)new_file;
883 new_file->read_proc = &fr_read_proc;
884 new_file->write_proc = &fr_write_proc;
889 cleanup_filename_dlci:
890 remove_proc_entry(FILENAME_DLCI, ch->procdir);
891 cleanup_LINE_privdata:
896 static int dlci_open(struct net_device *dev)
898 struct comx_channel *ch = dev->priv;
900 ch->init_status |= HW_OPEN;
906 static int dlci_close(struct net_device *dev)
908 struct comx_channel *ch = dev->priv;
910 ch->init_status &= ~HW_OPEN;
916 static int dlci_txe(struct net_device *dev)
918 struct comx_channel *ch = dev->priv;
919 struct fr_data *fr = ch->LINE_privdata;
925 ch = fr->master->priv;
926 fr = ch->LINE_privdata;
927 return ch->HW_txe(fr->master);
930 static int dlci_statistics(struct net_device *dev, char *page)
935 static int dlci_init(struct net_device *dev)
937 struct comx_channel *ch = dev->priv;
939 ch->HW_open = dlci_open;
940 ch->HW_close = dlci_close;
941 ch->HW_txe = dlci_txe;
942 ch->HW_statistics = dlci_statistics;
944 /* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */
950 static int dlci_exit(struct net_device *dev)
952 struct comx_channel *ch = dev->priv;
957 ch->HW_statistics = NULL;
963 static int dlci_dump(struct net_device *dev)
965 printk(KERN_INFO "dlci_dump %s, HOGY MI ???\n", dev->name);
969 static struct comx_protocol fr_master_protocol = {
972 .encap_type = ARPHRD_FRAD,
973 .line_init = fr_master_init,
974 .line_exit = fr_exit,
977 static struct comx_protocol fr_slave_protocol = {
980 .encap_type = ARPHRD_DLCI,
981 .line_init = fr_slave_init,
982 .line_exit = fr_exit,
985 static struct comx_hardware fr_dlci = {
988 .hw_init = dlci_init,
989 .hw_exit = dlci_exit,
990 .hw_dump = dlci_dump,
993 static int __init comx_proto_fr_init(void)
997 if ((ret = comx_register_hardware(&fr_dlci))) {
1000 if ((ret = comx_register_protocol(&fr_master_protocol))) {
1003 return comx_register_protocol(&fr_slave_protocol);
1006 static void __exit comx_proto_fr_exit(void)
1008 comx_unregister_hardware(fr_dlci.name);
1009 comx_unregister_protocol(fr_master_protocol.name);
1010 comx_unregister_protocol(fr_slave_protocol.name);
1013 module_init(comx_proto_fr_init);
1014 module_exit(comx_proto_fr_exit);