File: /usr/src/linux/drivers/net/wan/comx-proto-fr.c

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     
37     #define VERSION "0.73"
38     
39     #include <linux/module.h>
40     #include <linux/version.h>
41     #include <linux/types.h>
42     #include <linux/sched.h>
43     #include <linux/netdevice.h>
44     #include <linux/proc_fs.h>
45     #include <linux/if_arp.h>
46     #include <linux/inetdevice.h>
47     #include <linux/pkt_sched.h>
48     #include <linux/init.h>
49     #include <asm/uaccess.h>
50     
51     #include "comx.h"
52     #include "comxhw.h"
53     
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");
58     
59     #define	FRAD_UI		0x03
60     #define	NLPID_IP	0xcc
61     #define	NLPID_Q933_LMI	0x08
62     #define	NLPID_CISCO_LMI	0x09	
63     #define Q933_ENQ	0x75
64     #define	Q933_LINESTAT	0x51
65     #define	Q933_COUNTERS	0x53
66     
67     #define	MAXALIVECNT	3		/* No. of failures */
68     
69     struct fr_data {
70     	u16	dlci;
71     	struct	net_device *master;
72     	char	keepa_pend;
73     	char	keepa_freq;
74     	char	keepalivecnt, keeploopcnt;
75     	struct	timer_list keepa_timer;
76     	u8	local_cnt, remote_cnt;
77     };
78     
79     static struct comx_protocol fr_master_protocol;
80     static struct comx_protocol fr_slave_protocol;
81     static struct comx_hardware fr_dlci;
82     
83     static void fr_keepalive_send(struct net_device *dev) 
84     {
85     	struct comx_channel *ch = dev->priv;
86     	struct fr_data *fr = ch->LINE_privdata;
87     	struct sk_buff *skb;
88     	u8 *fr_packet;
89     	
90     	skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC);
91     	
92     	if(skb==NULL)
93     		return;
94                    
95             skb_reserve(skb, dev->hard_header_len);
96             
97             fr_packet=(u8*)skb_put(skb, 13);
98                      
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;
103     	fr_packet[4] = 0;
104     	fr_packet[5] = Q933_ENQ;
105     	fr_packet[6] = Q933_LINESTAT;
106     	fr_packet[7] = 0x01;
107     	fr_packet[8] = 0x01;
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;
112     
113     	skb->dev = dev;
114     	skb->priority = TC_PRIO_CONTROL;
115     	dev_queue_xmit(skb);
116     }
117     
118     static void fr_keepalive_timerfun(unsigned long d) 
119     {
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;
125     	struct fr_data *sfr;
126     	struct net_device *sdev;
127     
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)) {
134     				    continue;
135     				}
136     	
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;
143     					comx_status(sdev, 
144     						sch->line_status & ~PROTO_UP);
145     				}
146     			}
147     		}
148     		if (fr->keepalivecnt <= MAXALIVECNT) {
149     			++fr->keepalivecnt;
150     		}
151     		fr_keepalive_send(dev);
152     	}
153     	mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq);
154     }
155     
156     static void fr_rx_lmi(struct net_device *dev, struct sk_buff *skb, 
157     	u16 dlci, u8 nlpid) 
158     {
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;
163     	struct fr_data *sfr;
164     	struct net_device *sdev;
165     
166     	if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) {
167     		return;
168     	}
169     
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)) {
179     				    continue;
180     				}
181     	
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;
188     					comx_status(sdev, 
189     						sch->line_status | PROTO_UP);
190     				}
191     			}
192     		}
193     	}
194     }
195     
196     static void fr_set_keepalive(struct net_device *dev, int keepa) 
197     {
198     	struct comx_channel *ch = dev->priv;
199     	struct fr_data *fr = ch->LINE_privdata;
200     
201     	if (!keepa && fr->keepa_freq) { // switch off
202     		fr->keepa_freq = 0;
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);
207     		}
208     		return;
209     	}
210     
211     	if (keepa) { // bekapcs
212     		if(fr->keepa_freq && (ch->line_status & LINE_UP)) {
213     			del_timer(&fr->keepa_timer);
214     		}
215     		fr->keepa_freq = keepa;
216     		fr->local_cnt = fr->remote_cnt = 0;
217     		fr->keepa_timer.expires = jiffies + HZ;
218     		fr->keepa_timer.function = fr_keepalive_timerfun;
219     		fr->keepa_timer.data = (unsigned long)dev;
220     		ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
221     		dev->flags &= ~IFF_RUNNING;
222     		comx_status(dev, ch->line_status);
223     		if(ch->line_status & LINE_UP) {
224     			add_timer(&fr->keepa_timer);
225     		}
226     	}
227     }
228     
229     static void fr_rx(struct net_device *dev, struct sk_buff *skb) 
230     {
231     	struct comx_channel *ch = dev->priv;
232     	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
233     	struct net_device *sdev = dev;
234     	struct comx_channel *sch;
235     	struct fr_data *sfr;
236     	u16 dlci;
237     	u8 nlpid;
238     
239     	if(skb->len <= 4 || skb->data[2] != FRAD_UI) {
240     		kfree_skb(skb);
241     		return;
242     	}
243     
244     	/* Itt majd ki kell talalni, melyik slave kapja a csomagot */
245     	dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4);
246     	if ((nlpid = skb->data[3]) == 0) { // Optional padding 
247     		nlpid = skb->data[4];
248     		skb_pull(skb, 1);
249     	}
250     	skb_pull(skb, 4);	/* DLCI and header throw away */
251     
252     	if (ch->debug_flags & DEBUG_COMX_DLCI) {
253     		comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02x\n", 
254     			dlci, nlpid);
255     		comx_debug_skb(dev, skb, "Contents");
256     	}
257     
258     	/* Megkeressuk, kihez tartozik */
259     	for (; dir ; dir = dir->next) {
260     		if(!S_ISDIR(dir->mode)) {
261     			continue;
262     		}
263     		if ((sdev = dir->data) && (sch = sdev->priv) && 
264     		    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
265     		    (sfr->master == dev) && (sfr->dlci == dlci)) {
266     			skb->dev = sdev;	
267     			if (ch->debug_flags & DEBUG_COMX_DLCI) {
268     				comx_debug(dev, "Passing it to %s\n",sdev->name);
269     			}
270     			if (dev != sdev) {
271     				sch->stats.rx_packets++;
272     				sch->stats.rx_bytes += skb->len;
273     			}
274     			break;
275     		}
276     	}
277     	switch(nlpid) {
278     		case NLPID_IP:
279     			skb->protocol = htons(ETH_P_IP);
280     			skb->mac.raw = skb->data;
281     			comx_rx(sdev, skb);
282     			break;
283     		case NLPID_Q933_LMI:
284     			fr_rx_lmi(dev, skb, dlci, nlpid);
285     		default:
286     			kfree_skb(skb);
287     			break;
288     	}
289     }
290     
291     static int fr_tx(struct net_device *dev) 
292     {
293     	struct comx_channel *ch = dev->priv;
294     	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
295     	struct net_device *sdev;
296     	struct comx_channel *sch;
297     	struct fr_data *sfr;
298     	int cnt = 1;
299     
300     	/* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel, 
301     	   es annal a slave-nel aki eppen kuldott.
302     	   Egy helyen akkor all, ha a master kuldott.
303     	   Ez megint jo lesz majd, ha utemezni akarunk */
304     	   
305     	/* This should be fixed, the slave tbusy should be set when 
306     	   the masters queue is full and reset when not */
307     
308     	for (; dir ; dir = dir->next) {
309     		if(!S_ISDIR(dir->mode)) {
310     		    continue;
311     		}
312     		if ((sdev = dir->data) && (sch = sdev->priv) && 
313     		    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
314     		    (sfr->master == dev) && (netif_queue_stopped(sdev))) {
315     		    	netif_wake_queue(sdev);
316     			cnt++;
317     		}
318     	}
319     
320     	netif_wake_queue(dev);
321     	return 0;
322     }
323     
324     static void fr_status(struct net_device *dev, unsigned short status)
325     {
326     	struct comx_channel *ch = dev->priv;
327     	struct fr_data *fr = ch->LINE_privdata;
328     	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
329     	struct net_device *sdev;
330     	struct comx_channel *sch;
331     	struct fr_data *sfr;
332     
333     	if (status & LINE_UP) {
334     		if (!fr->keepa_freq) {
335     			status |= PROTO_UP;
336     		}
337     	} else {
338     		status &= ~(PROTO_UP | PROTO_LOOP);
339     	}
340     
341     	if (dev == fr->master && fr->keepa_freq) {
342     		if (status & LINE_UP) {
343     			fr->keepa_timer.expires = jiffies + HZ;
344     			add_timer(&fr->keepa_timer);
345     			fr->keepalivecnt = MAXALIVECNT + 1;
346     			fr->keeploopcnt = 0;
347     		} else {
348     			del_timer(&fr->keepa_timer);
349     		}
350     	}
351     		
352     	/* Itt a status valtozast vegig kell vinni az osszes slave-n */
353     	for (; dir ; dir = dir->next) {
354     		if(!S_ISDIR(dir->mode)) {
355     		    continue;
356     		}
357     	
358     		if ((sdev = dir->data) && (sch = sdev->priv) && 
359     		    (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) && 
360     		    (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
361     			if(status & LINE_UP) {
362     				netif_wake_queue(sdev);
363     			}
364     			comx_status(sdev, status);
365     			if(status & (PROTO_UP | PROTO_LOOP)) {
366     				dev->flags |= IFF_RUNNING;
367     			} else {
368     				dev->flags &= ~IFF_RUNNING;
369     			}
370     		}
371     	}
372     }
373     
374     static int fr_open(struct net_device *dev)
375     {
376     	struct comx_channel *ch = dev->priv;
377     	struct fr_data *fr = ch->LINE_privdata;
378     	struct proc_dir_entry *comxdir = ch->procdir;
379     	struct comx_channel *mch;
380     
381     	if (!(ch->init_status & HW_OPEN)) {
382     		return -ENODEV;
383     	}
384     
385     	if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) ||
386     	    (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) {
387     		printk(KERN_ERR "Trying to open an improperly set FR interface, giving up\n");
388     		return -EINVAL;
389     	}
390     
391     	if (!fr->master) {
392     		return -ENODEV;
393     	}
394     	mch = fr->master->priv;
395     	if (fr->master != dev && (!(mch->init_status & LINE_OPEN) 
396     	   || (mch->protocol != &fr_master_protocol))) {
397     		printk(KERN_ERR "Master %s is inactive, or incorrectly set up, "
398     			"unable to open %s\n", fr->master->name, dev->name);
399     		return -ENODEV;
400     	}
401     
402     	ch->init_status |= LINE_OPEN;
403     	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
404     	dev->flags &= ~IFF_RUNNING;
405     
406     	if (fr->master == dev) {
407     		if (fr->keepa_freq) {
408     			fr->keepa_timer.function = fr_keepalive_timerfun;
409     			fr->keepa_timer.data = (unsigned long)dev;
410     			add_timer(&fr->keepa_timer);
411     		} else {
412     			if (ch->line_status & LINE_UP) {
413     				ch->line_status |= PROTO_UP;
414     				dev->flags |= IFF_RUNNING;
415     			}
416     		}
417     	} else {
418     		ch->line_status = mch->line_status;
419     		if(fr->master->flags & IFF_RUNNING) {
420     			dev->flags |= IFF_RUNNING;
421     		}
422     	}
423     
424     	for (; comxdir ; comxdir = comxdir->next) {
425     		if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
426     		   strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
427     		   strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
428     			comxdir->mode = S_IFREG | 0444;
429     		}
430     	}
431     //	comx_status(dev, ch->line_status);
432     	return 0;
433     }
434     
435     static int fr_close(struct net_device *dev)
436     {
437     	struct comx_channel *ch = dev->priv;
438     	struct fr_data *fr = ch->LINE_privdata;
439     	struct proc_dir_entry *comxdir = ch->procdir;
440     
441     	if (fr->master == dev) { // Ha master 
442     		struct proc_dir_entry *dir = ch->procdir->parent->subdir;
443     		struct net_device *sdev = dev;
444     		struct comx_channel *sch;
445     		struct fr_data *sfr;
446     
447     		if (!(ch->init_status & HW_OPEN)) {
448     			return -ENODEV;
449     		}
450     
451     		if (fr->keepa_freq) {
452     			del_timer(&fr->keepa_timer);
453     		}
454     		
455     		for (; dir ; dir = dir->next) {
456     			if(!S_ISDIR(dir->mode)) {
457     				continue;
458     			}
459     			if ((sdev = dir->data) && (sch = sdev->priv) && 
460     			    (sdev->type == ARPHRD_DLCI) && 
461     			    (sfr = sch->LINE_privdata) &&
462     			    (sfr->master == dev) && 
463     			    (sch->init_status & LINE_OPEN)) {
464     				dev_close(sdev);
465     			}
466     		}
467     	}
468     
469     	ch->init_status &= ~LINE_OPEN;
470     	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
471     	dev->flags &= ~IFF_RUNNING;
472     
473     	for (; comxdir ; comxdir = comxdir->next) {
474     		if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
475     		    strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
476     		    strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
477     			comxdir->mode = S_IFREG | 0444;
478     		}
479     	}
480     
481     	return 0;
482     }
483     
484     static int fr_xmit(struct sk_buff *skb, struct net_device *dev)
485     {
486     	struct comx_channel *ch = dev->priv;
487     	struct comx_channel *sch, *mch;
488     	struct fr_data *fr = ch->LINE_privdata;
489     	struct fr_data *sfr;
490     	struct net_device *sdev;
491     	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
492     
493     	if (!fr->master) {
494     		printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %s\n", dev->name);
495     		return 0;
496     	}
497     
498     	mch = fr->master->priv;
499     
500     	/* Ennek majd a slave utemezeskor lesz igazan jelentosege */
501     	if (ch->debug_flags & DEBUG_COMX_DLCI) {
502     		comx_debug_skb(dev, skb, "Sending frame");
503     	}
504     
505     	if (dev != fr->master) {
506     		struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
507     		if (!newskb)
508     			return -ENOMEM;
509     		newskb->dev=fr->master;
510     		dev_queue_xmit(newskb);
511     		ch->stats.tx_bytes += skb->len;
512     		ch->stats.tx_packets++;
513     		dev_kfree_skb(skb);
514     	} else {
515     		netif_stop_queue(dev);
516     		for (; dir ; dir = dir->next) {
517     			if(!S_ISDIR(dir->mode)) {
518     			    continue;
519     			}
520     			if ((sdev = dir->data) && (sch = sdev->priv) && 
521     			    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
522     			    (sfr->master == dev) && (netif_queue_stopped(sdev))) {
523     				netif_stop_queue(sdev);
524     			}
525     		}
526     		 	
527     		switch(mch->HW_send_packet(dev, skb)) {
528     			case FRAME_QUEUED:
529     				netif_wake_queue(dev);
530     				break;
531     			case FRAME_ACCEPTED:
532     			case FRAME_DROPPED:
533     				break;
534     			case FRAME_ERROR:
535     				printk(KERN_ERR "%s: Transmit frame error (len %d)\n", 
536     					dev->name, skb->len);
537     				break;
538     		}
539     	}
540     	return 0;
541     }
542     
543     static int fr_header(struct sk_buff *skb, struct net_device *dev, 
544     	unsigned short type, void *daddr, void *saddr, unsigned len) 
545     {
546     	struct comx_channel *ch = dev->priv;
547     	struct fr_data *fr = ch->LINE_privdata;
548     
549     	skb_push(skb, dev->hard_header_len);	  
550     	/* Put in DLCI */
551     	skb->data[0] = (fr->dlci & (1024 - 15)) >> 2;
552     	skb->data[1] = (fr->dlci & 15) << 4 | 1;	// EA bit 1
553     	skb->data[2] = FRAD_UI;
554     	skb->data[3] = NLPID_IP;
555     
556     	return dev->hard_header_len;  
557     }
558     
559     static int fr_statistics(struct net_device *dev, char *page) 
560     {
561     	struct comx_channel *ch = dev->priv;
562     	struct fr_data *fr = ch->LINE_privdata;
563     	int len = 0;
564     
565     	if (fr->master == dev) {
566     		struct proc_dir_entry *dir = ch->procdir->parent->subdir;
567     		struct net_device *sdev;
568     		struct comx_channel *sch;
569     		struct fr_data *sfr;
570     		int slaves = 0;
571     
572     		len += sprintf(page + len, 
573     			"This is a Frame Relay master device\nSlaves: ");
574     		for (; dir ; dir = dir->next) {
575     			if(!S_ISDIR(dir->mode)) {
576     				continue;
577     			}
578     			if ((sdev = dir->data) && (sch = sdev->priv) && 
579     			    (sdev->type == ARPHRD_DLCI) &&
580     			    (sfr = sch->LINE_privdata) && 
581     			    (sfr->master == dev) && (sdev != dev)) {
582     				slaves++;
583     				len += sprintf(page + len, "%s ", sdev->name);
584     			}
585     		}
586     		len += sprintf(page + len, "%s\n", slaves ? "" : "(none)");
587     		if (fr->keepa_freq) {
588     			len += sprintf(page + len, "Line keepalive (value %d) "
589     				"status %s [%d]\n", fr->keepa_freq, 
590     				ch->line_status & PROTO_LOOP ? "LOOP" :
591     				ch->line_status & PROTO_UP ? "UP" : "DOWN", 
592     				fr->keepalivecnt);
593     		} else {
594     			len += sprintf(page + len, "Line keepalive protocol "
595     				"is not set\n");
596     		}
597     	} else {		// if slave
598     		len += sprintf(page + len, 
599     			"This is a Frame Relay slave device, master: %s\n",
600     			fr->master ? fr->master->name : "(not set)");
601     	}
602     	return len;
603     }
604     
605     static int fr_read_proc(char *page, char **start, off_t off, int count,
606     	int *eof, void *data)
607     {
608     	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
609     	struct net_device *dev = file->parent->data;
610     	struct comx_channel *ch = dev->priv;
611     	struct fr_data *fr = NULL;
612     	int len = 0;
613     
614     	if (ch) {
615     		fr = ch->LINE_privdata;
616     	}
617     
618     	if (strcmp(file->name, FILENAME_DLCI) == 0) {
619     		len = sprintf(page, "%04d\n", fr->dlci);
620     	} else if (strcmp(file->name, FILENAME_MASTER) == 0) {
621     		len = sprintf(page, "%-9s\n", fr->master ? fr->master->name :
622     			"(none)");
623     	} else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) {
624     		len = fr->keepa_freq ? sprintf(page, "% 3d\n", fr->keepa_freq) 
625     			: sprintf(page, "off\n");
626     	} else {
627     		printk(KERN_ERR "comxfr: internal error, filename %s\n", file->name);
628     		return -EBADF;
629     	}
630     
631     	if (off >= len) {
632     		*eof = 1;
633     		return 0;
634     	}
635     
636     	*start = page + off;
637     	if (count >= len - off) *eof = 1;
638     	return min_t(int, count, len - off);
639     }
640     
641     static int fr_write_proc(struct file *file, const char *buffer, 
642     	u_long count, void *data)
643     {
644     	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
645     	struct net_device *dev = entry->parent->data;
646     	struct comx_channel *ch = dev->priv;
647     	struct fr_data *fr = NULL; 
648     	char *page;
649     
650     	if (ch) {
651     		fr = ch->LINE_privdata;
652     	}
653     
654     	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
655     		return -ENOMEM;
656     	}
657     
658     	copy_from_user(page, buffer, count);
659     	if (*(page + count - 1) == '\n') {
660     		*(page + count - 1) = 0;
661     	}
662     
663     	if (strcmp(entry->name, FILENAME_DLCI) == 0) {
664     		u16 dlci_new = simple_strtoul(page, NULL, 10);
665     
666     		if (dlci_new > 1023) {
667     			printk(KERN_ERR "Invalid DLCI value\n");
668     		}
669     		else fr->dlci = dlci_new;
670     	} else if (strcmp(entry->name, FILENAME_MASTER) == 0) {
671     		struct net_device *new_master = dev_get_by_name(page);
672     
673     		if (new_master && new_master->type == ARPHRD_FRAD) {
674     			struct comx_channel *sch = new_master->priv;
675     			struct fr_data *sfr = sch->LINE_privdata;
676     
677     			if (sfr && sfr->master == new_master) {
678     				if(fr->master)
679     					dev_put(fr->master);
680     				fr->master = new_master;
681     				/* Megorokli a master statuszat */
682     				ch->line_status = sch->line_status;
683     			}
684     		}
685     	} else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) {
686     		int keepa_new = -1;
687     
688     		if (strcmp(page, KEEPALIVE_OFF) == 0) {
689     			keepa_new = 0;
690     		} else {
691     			keepa_new = simple_strtoul(page, NULL, 10);
692     		}
693     
694     		if (keepa_new < 0 || keepa_new > 100) {
695     			printk(KERN_ERR "invalid keepalive\n");
696     		} else {
697     			if (fr->keepa_freq && keepa_new != fr->keepa_freq) {
698     				fr_set_keepalive(dev, 0);
699     			}
700     			if (keepa_new) {
701     				fr_set_keepalive(dev, keepa_new);
702     			}
703     		}
704     	} else {
705     		printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n", 
706     			entry->name);
707     		count = -EBADF;
708     	}
709     
710     	free_page((unsigned long)page);
711     	return count;
712     }
713     
714     static int fr_exit(struct net_device *dev) 
715     {
716     	struct comx_channel *ch = dev->priv;
717     	struct fr_data *fr = ch->LINE_privdata;
718     	struct net_device *sdev = dev;
719     	struct comx_channel *sch;
720     	struct fr_data *sfr;
721     	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
722     
723     	/* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */
724     	if (fr->master && fr->master == dev) {
725     		for (; dir ; dir = dir->next) {
726     			if(!S_ISDIR(dir->mode)) {
727     				continue;
728     			}
729     			if ((sdev = dir->data) && (sch = sdev->priv) && 
730     			    (sdev->type == ARPHRD_DLCI) && 
731     			    (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
732     				dev_close(sdev);
733     				sfr->master = NULL;
734     			}
735     		}
736     	}
737     	dev->flags		= 0;
738     	dev->type		= 0;
739     	dev->mtu		= 0;
740     	dev->hard_header_len    = 0;
741     
742     	ch->LINE_rx	= NULL;
743     	ch->LINE_tx	= NULL;
744     	ch->LINE_status = NULL;
745     	ch->LINE_open	= NULL;
746     	ch->LINE_close	= NULL;
747     	ch->LINE_xmit	= NULL;
748     	ch->LINE_header	= NULL;
749     	ch->LINE_rebuild_header	= NULL;
750     	ch->LINE_statistics = NULL;
751     
752     	ch->LINE_status = 0;
753     
754     	if (fr->master != dev) { // if not master, remove dlci
755     		if(fr->master)
756     			dev_put(fr->master);
757     		remove_proc_entry(FILENAME_DLCI, ch->procdir);
758     		remove_proc_entry(FILENAME_MASTER, ch->procdir);
759     	} else {
760     		if (fr->keepa_freq) {
761     			fr_set_keepalive(dev, 0);
762     		}
763     		remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir);
764     		remove_proc_entry(FILENAME_DLCI, ch->procdir);
765     	}
766     
767     	kfree(fr);
768     	ch->LINE_privdata = NULL;
769     
770     	MOD_DEC_USE_COUNT;
771     	return 0;
772     }
773     
774     static int fr_master_init(struct net_device *dev)
775     {
776     	struct comx_channel *ch = dev->priv;
777     	struct fr_data *fr;
778     	struct proc_dir_entry *new_file;
779     
780     	if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), 
781     	    GFP_KERNEL)) == NULL) {
782     		return -ENOMEM;
783     	}
784     	memset(fr, 0, sizeof(struct fr_data));
785     	fr->master = dev;	// this means master
786     	fr->dlci = 0;		// let's say default
787     
788     	dev->flags	= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
789     	dev->type	= ARPHRD_FRAD;
790     	dev->mtu	= 1500;
791     	dev->hard_header_len    = 4;		
792     	dev->addr_len	= 0;
793     
794     	ch->LINE_rx	= fr_rx;
795     	ch->LINE_tx	= fr_tx;
796     	ch->LINE_status = fr_status;
797     	ch->LINE_open	= fr_open;
798     	ch->LINE_close	= fr_close;
799     	ch->LINE_xmit	= fr_xmit;
800     	ch->LINE_header	= fr_header;
801     	ch->LINE_rebuild_header	= NULL;
802     	ch->LINE_statistics = fr_statistics;
803     
804     	if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, 
805     	    ch->procdir)) == NULL) {
806     		goto cleanup_LINE_privdata;
807     	}
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 = 5;
812     	new_file->nlink = 1;
813     
814     	if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644, 
815     	    ch->procdir)) == NULL) {
816     		goto cleanup_filename_dlci;
817     	}
818     	new_file->data = (void *)new_file;
819     	new_file->read_proc = &fr_read_proc;
820     	new_file->write_proc = &fr_write_proc;
821     	new_file->size = 4;
822     	new_file->nlink = 1;
823     
824     	fr_set_keepalive(dev, 0);
825     
826     	MOD_INC_USE_COUNT;
827     	return 0;
828     cleanup_filename_dlci:
829     	 remove_proc_entry(FILENAME_DLCI, ch->procdir);
830     cleanup_LINE_privdata:
831     	kfree(fr);
832     	return -EIO;
833     }
834     
835     static int fr_slave_init(struct net_device *dev)
836     {
837     	struct comx_channel *ch = dev->priv;
838     	struct fr_data *fr;
839     	struct proc_dir_entry *new_file;
840     
841     	if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), 
842     	    GFP_KERNEL)) == NULL) {
843     		return -ENOMEM;
844     	}
845     	memset(fr, 0, sizeof(struct fr_data));
846     
847     	dev->flags	= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
848     	dev->type	= ARPHRD_DLCI;
849     	dev->mtu	= 1500;
850     	dev->hard_header_len    = 4;		
851     	dev->addr_len	= 0;
852     
853     	ch->LINE_rx	= fr_rx;
854     	ch->LINE_tx	= fr_tx;
855     	ch->LINE_status = fr_status;
856     	ch->LINE_open	= fr_open;
857     	ch->LINE_close	= fr_close;
858     	ch->LINE_xmit	= fr_xmit;
859     	ch->LINE_header	= fr_header;
860     	ch->LINE_rebuild_header	= NULL;
861     	ch->LINE_statistics = fr_statistics;
862     
863     	if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, 
864     	    ch->procdir)) == NULL) {
865     		goto cleanup_LINE_privdata;
866     	}
867     	
868     	new_file->data = (void *)new_file;
869     	new_file->read_proc = &fr_read_proc;
870     	new_file->write_proc = &fr_write_proc;
871     	new_file->size = 5;
872     	new_file->nlink = 1;
873     
874     	if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644, 
875     	    ch->procdir)) == NULL) {
876     		goto cleanup_filename_dlci;
877     	}
878     	new_file->data = (void *)new_file;
879     	new_file->read_proc = &fr_read_proc;
880     	new_file->write_proc = &fr_write_proc;
881     	new_file->size = 10;
882     	new_file->nlink = 1;
883     	MOD_INC_USE_COUNT;
884     	return 0;
885     cleanup_filename_dlci:
886              remove_proc_entry(FILENAME_DLCI, ch->procdir);
887     cleanup_LINE_privdata:
888     	kfree(fr);
889     	return -EIO;
890     }
891     
892     static int dlci_open(struct net_device *dev)
893     {
894     	struct comx_channel *ch = dev->priv;
895     
896     	ch->init_status |= HW_OPEN;
897     
898     	MOD_INC_USE_COUNT;
899     	return 0;
900     }
901     
902     static int dlci_close(struct net_device *dev)
903     {
904     	struct comx_channel *ch = dev->priv;
905     
906     	ch->init_status &= ~HW_OPEN;
907     
908     	MOD_DEC_USE_COUNT;
909     	return 0;
910     }
911     
912     static int dlci_txe(struct net_device *dev)
913     {
914     	struct comx_channel *ch = dev->priv;
915     	struct fr_data *fr = ch->LINE_privdata;
916     
917     	if (!fr->master) {
918     		return 0;
919     	}
920     
921     	ch = fr->master->priv;
922     	fr = ch->LINE_privdata;
923     	return ch->HW_txe(fr->master);
924     }
925     
926     static int dlci_statistics(struct net_device *dev, char *page) 
927     {
928     	return 0;
929     }
930     
931     static int dlci_init(struct net_device *dev)
932     {
933     	struct comx_channel *ch = dev->priv;
934     
935     	ch->HW_open = dlci_open;
936     	ch->HW_close = dlci_close;
937     	ch->HW_txe = dlci_txe;
938     	ch->HW_statistics = dlci_statistics;
939     
940     	/* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */
941     
942     	MOD_INC_USE_COUNT;
943     	return 0;
944     }
945     
946     static int dlci_exit(struct net_device *dev)
947     {
948     	struct comx_channel *ch = dev->priv;
949     
950     	ch->HW_open = NULL;
951     	ch->HW_close = NULL;
952     	ch->HW_txe = NULL;
953     	ch->HW_statistics = NULL;
954     
955     	MOD_DEC_USE_COUNT;
956     	return 0;
957     }
958     
959     static int dlci_dump(struct net_device *dev)
960     {
961     	printk(KERN_INFO "dlci_dump %s, HOGY MI ???\n", dev->name);
962     	return -1;
963     }
964     
965     static struct comx_protocol fr_master_protocol = {
966     	name:		"frad", 
967     	version:	VERSION,
968     	encap_type:	ARPHRD_FRAD, 
969     	line_init:	fr_master_init, 
970     	line_exit:	fr_exit, 
971     };
972     
973     static struct comx_protocol fr_slave_protocol = {
974     	name:		"ietf-ip", 
975     	version:	VERSION,
976     	encap_type:	ARPHRD_DLCI, 
977     	line_init:	fr_slave_init, 
978     	line_exit:	fr_exit, 
979     };
980     
981     static struct comx_hardware fr_dlci = { 
982     	name:		"dlci", 
983     	version:	VERSION,
984     	hw_init:	dlci_init, 
985     	hw_exit:	dlci_exit, 
986     	hw_dump:	dlci_dump, 
987     };
988     
989     #ifdef MODULE
990     #define comx_proto_fr_init init_module
991     #endif
992     
993     int __init comx_proto_fr_init(void)
994     {
995     	int ret; 
996     
997     	if ((ret = comx_register_hardware(&fr_dlci))) {
998     		return ret;
999     	}
1000     	if ((ret = comx_register_protocol(&fr_master_protocol))) {
1001     		return ret;
1002     	}
1003     	return comx_register_protocol(&fr_slave_protocol);
1004     }
1005     
1006     #ifdef MODULE
1007     void cleanup_module(void)
1008     {
1009     	comx_unregister_hardware(fr_dlci.name);
1010     	comx_unregister_protocol(fr_master_protocol.name);
1011     	comx_unregister_protocol(fr_slave_protocol.name);
1012     }
1013     #endif /* MODULE */
1014     
1015