2 * LAPB protocol module for the COMX driver
3 * for Linux kernel 2.2.X
5 * Original author: Tivadar Szemethy <tiv@itc.hu>
6 * Maintainer: Gergely Madarasz <gorgo@itc.hu>
8 * Copyright (C) 1997-1999 (C) 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.80 (99/06/14):
16 * - cleaned up the source code a bit
17 * - ported back to kernel, now works as non-module
19 * Changed (00/10/29, Henner Eisen):
20 * - comx_rx() / comxlapb_data_indication() return status.
24 #define VERSION "0.80"
26 #include <linux/module.h>
27 #include <linux/types.h>
28 #include <linux/netdevice.h>
29 #include <linux/proc_fs.h>
30 #include <linux/if_arp.h>
31 #include <linux/inetdevice.h>
32 #include <asm/uaccess.h>
33 #include <linux/lapb.h>
34 #include <linux/init.h>
39 static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
40 int size, struct proc_dir_entry *dir);
42 static void comxlapb_rx(struct net_device *dev, struct sk_buff *skb)
44 if (!dev || !dev->priv) {
47 lapb_data_received(dev, skb);
51 static int comxlapb_tx(struct net_device *dev)
53 netif_wake_queue(dev);
57 static int comxlapb_header(struct sk_buff *skb, struct net_device *dev,
58 unsigned short type, void *daddr, void *saddr, unsigned len)
60 return dev->hard_header_len;
63 static void comxlapb_status(struct net_device *dev, unsigned short status)
65 struct comx_channel *ch;
67 if (!dev || !(ch = dev->priv)) {
70 if (status & LINE_UP) {
71 netif_wake_queue(dev);
73 comx_status(dev, status);
76 static int comxlapb_open(struct net_device *dev)
78 struct comx_channel *ch = dev->priv;
81 if (!(ch->init_status & HW_OPEN)) {
85 err = lapb_connect_request(dev);
87 if (ch->debug_flags & DEBUG_COMX_LAPB) {
88 comx_debug(dev, "%s: lapb opened, error code: %d\n",
93 ch->init_status |= LINE_OPEN;
99 static int comxlapb_close(struct net_device *dev)
101 struct comx_channel *ch = dev->priv;
103 if (!(ch->init_status & HW_OPEN)) {
107 if (ch->debug_flags & DEBUG_COMX_LAPB) {
108 comx_debug(dev, "%s: lapb closed\n", dev->name);
111 lapb_disconnect_request(dev);
113 ch->init_status &= ~LINE_OPEN;
114 ch->line_status &= ~PROTO_UP;
119 static int comxlapb_xmit(struct sk_buff *skb, struct net_device *dev)
121 struct comx_channel *ch = dev->priv;
122 struct sk_buff *skb2;
124 if (!dev || !(ch = dev->priv) || !(dev->flags & (IFF_UP | IFF_RUNNING))) {
128 if (dev->type == ARPHRD_X25) { // first byte tells what to do
129 switch(skb->data[0]) {
133 lapb_connect_request(dev);
137 lapb_disconnect_request(dev);
145 netif_stop_queue(dev);
147 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
148 lapb_data_request(dev, skb2);
151 return FRAME_ACCEPTED;
154 static int comxlapb_statistics(struct net_device *dev, char *page)
156 struct lapb_parms_struct parms;
159 len += sprintf(page + len, "Line status: ");
160 if (lapb_getparms(dev, &parms) != LAPB_OK) {
161 len += sprintf(page + len, "not initialized\n");
164 len += sprintf(page + len, "%s (%s), T1: %d/%d, T2: %d/%d, N2: %d/%d, "
165 "window: %d\n", parms.mode & LAPB_DCE ? "DCE" : "DTE",
166 parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD",
167 parms.t1timer, parms.t1, parms.t2timer, parms.t2,
168 parms.n2count, parms.n2, parms.window);
173 static int comxlapb_read_proc(char *page, char **start, off_t off, int count,
174 int *eof, void *data)
176 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
177 struct net_device *dev = file->parent->data;
178 struct lapb_parms_struct parms;
181 if (lapb_getparms(dev, &parms)) {
185 if (strcmp(file->name, FILENAME_T1) == 0) {
186 len += sprintf(page + len, "%02u / %02u\n",
187 parms.t1timer, parms.t1);
188 } else if (strcmp(file->name, FILENAME_T2) == 0) {
189 len += sprintf(page + len, "%02u / %02u\n",
190 parms.t2timer, parms.t2);
191 } else if (strcmp(file->name, FILENAME_N2) == 0) {
192 len += sprintf(page + len, "%02u / %02u\n",
193 parms.n2count, parms.n2);
194 } else if (strcmp(file->name, FILENAME_WINDOW) == 0) {
195 len += sprintf(page + len, "%u\n", parms.window);
196 } else if (strcmp(file->name, FILENAME_MODE) == 0) {
197 len += sprintf(page + len, "%s, %s\n",
198 parms.mode & LAPB_DCE ? "DCE" : "DTE",
199 parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD");
201 printk(KERN_ERR "comxlapb: internal error, filename %s\n", file->name);
211 if (count >= len - off) {
214 return min_t(int, count, len - off);
217 static int comxlapb_write_proc(struct file *file, const char *buffer,
218 u_long count, void *data)
220 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
221 struct net_device *dev = entry->parent->data;
222 struct lapb_parms_struct parms;
226 if (lapb_getparms(dev, &parms)) {
230 if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
234 if (copy_from_user(page, buffer, count)) {
235 free_page((unsigned long)page);
238 if (*(page + count - 1) == '\n') {
239 *(page + count - 1) = 0;
242 if (strcmp(entry->name, FILENAME_T1) == 0) {
243 parm=simple_strtoul(page,NULL,10);
244 if (parm > 0 && parm < 100) {
246 lapb_setparms(dev, &parms);
248 } else if (strcmp(entry->name, FILENAME_T2) == 0) {
249 parm=simple_strtoul(page, NULL, 10);
250 if (parm > 0 && parm < 100) {
252 lapb_setparms(dev, &parms);
254 } else if (strcmp(entry->name, FILENAME_N2) == 0) {
255 parm=simple_strtoul(page, NULL, 10);
256 if (parm > 0 && parm < 100) {
258 lapb_setparms(dev, &parms);
260 } else if (strcmp(entry->name, FILENAME_WINDOW) == 0) {
261 parms.window = simple_strtoul(page, NULL, 10);
262 lapb_setparms(dev, &parms);
263 } else if (strcmp(entry->name, FILENAME_MODE) == 0) {
264 if (comx_strcasecmp(page, "dte") == 0) {
265 parms.mode &= ~(LAPB_DCE | LAPB_DTE);
266 parms.mode |= LAPB_DTE;
267 } else if (comx_strcasecmp(page, "dce") == 0) {
268 parms.mode &= ~(LAPB_DTE | LAPB_DCE);
269 parms.mode |= LAPB_DCE;
270 } else if (comx_strcasecmp(page, "std") == 0 ||
271 comx_strcasecmp(page, "standard") == 0) {
272 parms.mode &= ~LAPB_EXTENDED;
273 parms.mode |= LAPB_STANDARD;
274 } else if (comx_strcasecmp(page, "ext") == 0 ||
275 comx_strcasecmp(page, "extended") == 0) {
276 parms.mode &= ~LAPB_STANDARD;
277 parms.mode |= LAPB_EXTENDED;
279 lapb_setparms(dev, &parms);
281 printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n",
286 free_page((unsigned long)page);
290 static void comxlapb_connected(struct net_device *dev, int reason)
292 struct comx_channel *ch = dev->priv;
293 struct proc_dir_entry *comxdir = ch->procdir->subdir;
295 if (ch->debug_flags & DEBUG_COMX_LAPB) {
296 comx_debug(ch->dev, "%s: lapb connected, reason: %d\n",
297 ch->dev->name, reason);
300 if (ch->dev->type == ARPHRD_X25) {
304 if ((skb = dev_alloc_skb(1)) == NULL) {
305 printk(KERN_ERR "comxlapb: out of memory!\n");
309 *p = 0x01; // link established
311 skb->protocol = htons(ETH_P_X25);
312 skb->mac.raw = skb->data;
313 skb->pkt_type = PACKET_HOST;
316 ch->dev->last_rx = jiffies;
319 for (; comxdir; comxdir = comxdir->next) {
320 if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
321 comxdir->mode = S_IFREG | 0444;
326 ch->line_status |= PROTO_UP;
327 comx_status(ch->dev, ch->line_status);
330 static void comxlapb_disconnected(struct net_device *dev, int reason)
332 struct comx_channel *ch = dev->priv;
333 struct proc_dir_entry *comxdir = ch->procdir->subdir;
335 if (ch->debug_flags & DEBUG_COMX_LAPB) {
336 comx_debug(ch->dev, "%s: lapb disconnected, reason: %d\n",
337 ch->dev->name, reason);
340 if (ch->dev->type == ARPHRD_X25) {
344 if ((skb = dev_alloc_skb(1)) == NULL) {
345 printk(KERN_ERR "comxlapb: out of memory!\n");
349 *p = 0x02; // link disconnected
351 skb->protocol = htons(ETH_P_X25);
352 skb->mac.raw = skb->data;
353 skb->pkt_type = PACKET_HOST;
356 ch->dev->last_rx = jiffies;
359 for (; comxdir; comxdir = comxdir->next) {
360 if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
361 comxdir->mode = S_IFREG | 0644;
365 ch->line_status &= ~PROTO_UP;
366 comx_status(ch->dev, ch->line_status);
369 static int comxlapb_data_indication(struct net_device *dev, struct sk_buff *skb)
371 struct comx_channel *ch = dev->priv;
373 if (ch->dev->type == ARPHRD_X25) {
379 skb->data[0] = 0; // indicate data for X25
380 skb->protocol = htons(ETH_P_X25);
382 skb->protocol = htons(ETH_P_IP);
386 skb->mac.raw = skb->data;
387 return comx_rx(ch->dev, skb);
390 static void comxlapb_data_transmit(struct net_device *dev, struct sk_buff *skb)
392 struct comx_channel *ch = dev->priv;
394 if (ch->HW_send_packet) {
395 ch->HW_send_packet(ch->dev, skb);
399 static int comxlapb_exit(struct net_device *dev)
401 struct comx_channel *ch = dev->priv;
406 dev->hard_header_len = 0;
410 ch->LINE_status = NULL;
411 ch->LINE_open = NULL;
412 ch->LINE_close = NULL;
413 ch->LINE_xmit = NULL;
414 ch->LINE_header = NULL;
415 ch->LINE_statistics = NULL;
417 if (ch->debug_flags & DEBUG_COMX_LAPB) {
418 comx_debug(dev, "%s: unregistering lapb\n", dev->name);
420 lapb_unregister(dev);
422 remove_proc_entry(FILENAME_T1, ch->procdir);
423 remove_proc_entry(FILENAME_T2, ch->procdir);
424 remove_proc_entry(FILENAME_N2, ch->procdir);
425 remove_proc_entry(FILENAME_MODE, ch->procdir);
426 remove_proc_entry(FILENAME_WINDOW, ch->procdir);
432 static int comxlapb_init(struct net_device *dev)
434 struct comx_channel *ch = dev->priv;
435 struct lapb_register_struct lapbreg;
438 dev->hard_header_len = 4;
441 ch->LINE_rx = comxlapb_rx;
442 ch->LINE_tx = comxlapb_tx;
443 ch->LINE_status = comxlapb_status;
444 ch->LINE_open = comxlapb_open;
445 ch->LINE_close = comxlapb_close;
446 ch->LINE_xmit = comxlapb_xmit;
447 ch->LINE_header = comxlapb_header;
448 ch->LINE_statistics = comxlapb_statistics;
450 lapbreg.connect_confirmation = comxlapb_connected;
451 lapbreg.connect_indication = comxlapb_connected;
452 lapbreg.disconnect_confirmation = comxlapb_disconnected;
453 lapbreg.disconnect_indication = comxlapb_disconnected;
454 lapbreg.data_indication = comxlapb_data_indication;
455 lapbreg.data_transmit = comxlapb_data_transmit;
456 if (lapb_register(dev, &lapbreg)) {
459 if (ch->debug_flags & DEBUG_COMX_LAPB) {
460 comx_debug(dev, "%s: lapb registered\n", dev->name);
463 if (!create_comxlapb_proc_entry(FILENAME_T1, 0644, 8, ch->procdir)) {
466 if (!create_comxlapb_proc_entry(FILENAME_T2, 0644, 8, ch->procdir)) {
469 if (!create_comxlapb_proc_entry(FILENAME_N2, 0644, 8, ch->procdir)) {
472 if (!create_comxlapb_proc_entry(FILENAME_MODE, 0644, 14, ch->procdir)) {
475 if (!create_comxlapb_proc_entry(FILENAME_WINDOW, 0644, 0, ch->procdir)) {
483 static int comxlapb_init_lapb(struct net_device *dev)
485 dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
486 dev->type = ARPHRD_LAPB;
488 return(comxlapb_init(dev));
491 static int comxlapb_init_x25(struct net_device *dev)
493 dev->flags = IFF_NOARP;
494 dev->type = ARPHRD_X25;
496 return(comxlapb_init(dev));
499 static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
500 int size, struct proc_dir_entry *dir)
502 struct proc_dir_entry *new_file;
504 if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
505 new_file->data = (void *)new_file;
506 new_file->read_proc = &comxlapb_read_proc;
507 new_file->write_proc = &comxlapb_write_proc;
508 new_file->size = size;
514 static struct comx_protocol comxlapb_protocol = {
523 static struct comx_protocol comx25_protocol = {
532 static int __init comx_proto_lapb_init(void)
536 if ((ret = comx_register_protocol(&comxlapb_protocol)) != 0) {
539 return comx_register_protocol(&comx25_protocol);
542 static void __exit comx_proto_lapb_exit(void)
544 comx_unregister_protocol(comxlapb_protocol.name);
545 comx_unregister_protocol(comx25_protocol.name);
548 module_init(comx_proto_lapb_init);
549 module_exit(comx_proto_lapb_exit);
551 MODULE_LICENSE("GPL");