The LDT fixes in particular fix some potentially random strange behaviour.
[davej-history.git] / drivers / net / wan / comx-proto-lapb.c
blobacbb7f112328030eddc190cf88af848b856f1afe
1 /*
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/version.h>
28 #include <linux/types.h>
29 #include <linux/netdevice.h>
30 #include <linux/proc_fs.h>
31 #include <linux/if_arp.h>
32 #include <linux/inetdevice.h>
33 #include <asm/uaccess.h>
34 #include <linux/lapb.h>
35 #include <linux/init.h>
37 #include "comx.h"
38 #include "comxhw.h"
40 static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
41 int size, struct proc_dir_entry *dir);
43 static void comxlapb_rx(struct net_device *dev, struct sk_buff *skb)
45 if (!dev || !dev->priv) {
46 dev_kfree_skb(skb);
47 } else {
48 lapb_data_received(dev->priv, skb);
52 static int comxlapb_tx(struct net_device *dev)
54 netif_wake_queue(dev);
55 return 0;
58 static int comxlapb_header(struct sk_buff *skb, struct net_device *dev,
59 unsigned short type, void *daddr, void *saddr, unsigned len)
61 return dev->hard_header_len;
64 static void comxlapb_status(struct net_device *dev, unsigned short status)
66 struct comx_channel *ch;
68 if (!dev || !(ch = dev->priv)) {
69 return;
71 if (status & LINE_UP) {
72 netif_wake_queue(dev);
74 comx_status(dev, status);
77 static int comxlapb_open(struct net_device *dev)
79 struct comx_channel *ch = dev->priv;
80 int err = 0;
82 if (!(ch->init_status & HW_OPEN)) {
83 return -ENODEV;
86 err = lapb_connect_request(ch);
88 if (ch->debug_flags & DEBUG_COMX_LAPB) {
89 comx_debug(dev, "%s: lapb opened, error code: %d\n",
90 dev->name, err);
93 if (!err) {
94 ch->init_status |= LINE_OPEN;
95 MOD_INC_USE_COUNT;
97 return err;
100 static int comxlapb_close(struct net_device *dev)
102 struct comx_channel *ch = dev->priv;
104 if (!(ch->init_status & HW_OPEN)) {
105 return -ENODEV;
108 if (ch->debug_flags & DEBUG_COMX_LAPB) {
109 comx_debug(dev, "%s: lapb closed\n", dev->name);
112 lapb_disconnect_request(ch);
114 ch->init_status &= ~LINE_OPEN;
115 ch->line_status &= ~PROTO_UP;
116 MOD_DEC_USE_COUNT;
117 return 0;
120 static int comxlapb_xmit(struct sk_buff *skb, struct net_device *dev)
122 struct comx_channel *ch = dev->priv;
123 struct sk_buff *skb2;
125 if (!dev || !(ch = dev->priv) || !(dev->flags & (IFF_UP | IFF_RUNNING))) {
126 return -ENODEV;
129 if (dev->type == ARPHRD_X25) { // first byte tells what to do
130 switch(skb->data[0]) {
131 case 0x00:
132 break; // transmit
133 case 0x01:
134 lapb_connect_request(ch);
135 kfree_skb(skb);
136 return 0;
137 case 0x02:
138 lapb_disconnect_request(ch);
139 default:
140 kfree_skb(skb);
141 return 0;
143 skb_pull(skb,1);
146 netif_stop_queue(dev);
148 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
149 lapb_data_request(ch, skb2);
152 return FRAME_ACCEPTED;
155 static int comxlapb_statistics(struct net_device *dev, char *page)
157 struct lapb_parms_struct parms;
158 int len = 0;
160 len += sprintf(page + len, "Line status: ");
161 if (lapb_getparms(dev->priv, &parms) != LAPB_OK) {
162 len += sprintf(page + len, "not initialized\n");
163 return len;
165 len += sprintf(page + len, "%s (%s), T1: %d/%d, T2: %d/%d, N2: %d/%d, "
166 "window: %d\n", parms.mode & LAPB_DCE ? "DCE" : "DTE",
167 parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD",
168 parms.t1timer, parms.t1, parms.t2timer, parms.t2,
169 parms.n2count, parms.n2, parms.window);
171 return len;
174 static int comxlapb_read_proc(char *page, char **start, off_t off, int count,
175 int *eof, void *data)
177 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
178 struct net_device *dev = file->parent->data;
179 struct lapb_parms_struct parms;
180 int len = 0;
182 if (lapb_getparms(dev->priv, &parms)) {
183 return -ENODEV;
186 if (strcmp(file->name, FILENAME_T1) == 0) {
187 len += sprintf(page + len, "%02u / %02u\n",
188 parms.t1timer, parms.t1);
189 } else if (strcmp(file->name, FILENAME_T2) == 0) {
190 len += sprintf(page + len, "%02u / %02u\n",
191 parms.t2timer, parms.t2);
192 } else if (strcmp(file->name, FILENAME_N2) == 0) {
193 len += sprintf(page + len, "%02u / %02u\n",
194 parms.n2count, parms.n2);
195 } else if (strcmp(file->name, FILENAME_WINDOW) == 0) {
196 len += sprintf(page + len, "%u\n", parms.window);
197 } else if (strcmp(file->name, FILENAME_MODE) == 0) {
198 len += sprintf(page + len, "%s, %s\n",
199 parms.mode & LAPB_DCE ? "DCE" : "DTE",
200 parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD");
201 } else {
202 printk(KERN_ERR "comxlapb: internal error, filename %s\n", file->name);
203 return -EBADF;
206 if (off >= len) {
207 *eof = 1;
208 return 0;
211 *start = page + off;
212 if (count >= len - off) {
213 *eof = 1;
215 return ( min(count, len - off) );
218 static int comxlapb_write_proc(struct file *file, const char *buffer,
219 u_long count, void *data)
221 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
222 struct net_device *dev = entry->parent->data;
223 struct lapb_parms_struct parms;
224 unsigned long parm;
225 char *page;
227 if (lapb_getparms(dev->priv, &parms)) {
228 return -ENODEV;
231 if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
232 return -ENOMEM;
235 copy_from_user(page, buffer, count);
236 if (*(page + count - 1) == '\n') {
237 *(page + count - 1) = 0;
240 if (strcmp(entry->name, FILENAME_T1) == 0) {
241 parm=simple_strtoul(page,NULL,10);
242 if (parm > 0 && parm < 100) {
243 parms.t1=parm;
244 lapb_setparms(dev->priv, &parms);
246 } else if (strcmp(entry->name, FILENAME_T2) == 0) {
247 parm=simple_strtoul(page, NULL, 10);
248 if (parm > 0 && parm < 100) {
249 parms.t2=parm;
250 lapb_setparms(dev->priv, &parms);
252 } else if (strcmp(entry->name, FILENAME_N2) == 0) {
253 parm=simple_strtoul(page, NULL, 10);
254 if (parm > 0 && parm < 100) {
255 parms.n2=parm;
256 lapb_setparms(dev->priv, &parms);
258 } else if (strcmp(entry->name, FILENAME_WINDOW) == 0) {
259 parms.window = simple_strtoul(page, NULL, 10);
260 lapb_setparms(dev->priv, &parms);
261 } else if (strcmp(entry->name, FILENAME_MODE) == 0) {
262 if (comx_strcasecmp(page, "dte") == 0) {
263 parms.mode &= ~(LAPB_DCE | LAPB_DTE);
264 parms.mode |= LAPB_DTE;
265 } else if (comx_strcasecmp(page, "dce") == 0) {
266 parms.mode &= ~(LAPB_DTE | LAPB_DCE);
267 parms.mode |= LAPB_DCE;
268 } else if (comx_strcasecmp(page, "std") == 0 ||
269 comx_strcasecmp(page, "standard") == 0) {
270 parms.mode &= ~LAPB_EXTENDED;
271 parms.mode |= LAPB_STANDARD;
272 } else if (comx_strcasecmp(page, "ext") == 0 ||
273 comx_strcasecmp(page, "extended") == 0) {
274 parms.mode &= ~LAPB_STANDARD;
275 parms.mode |= LAPB_EXTENDED;
277 lapb_setparms(dev->priv, &parms);
278 } else {
279 printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n",
280 entry->name);
281 return -EBADF;
284 free_page((unsigned long)page);
285 return count;
288 static void comxlapb_connected(void *token, int reason)
290 struct comx_channel *ch = token;
291 struct proc_dir_entry *comxdir = ch->procdir->subdir;
293 if (ch->debug_flags & DEBUG_COMX_LAPB) {
294 comx_debug(ch->dev, "%s: lapb connected, reason: %d\n",
295 ch->dev->name, reason);
298 if (ch->dev->type == ARPHRD_X25) {
299 unsigned char *p;
300 struct sk_buff *skb;
302 if ((skb = dev_alloc_skb(1)) == NULL) {
303 printk(KERN_ERR "comxlapb: out of memory!\n");
304 return;
306 p = skb_put(skb,1);
307 *p = 0x01; // link established
308 skb->dev = ch->dev;
309 skb->protocol = htons(ETH_P_X25);
310 skb->mac.raw = skb->data;
311 skb->pkt_type = PACKET_HOST;
313 netif_rx(skb);
316 for (; comxdir; comxdir = comxdir->next) {
317 if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
318 comxdir->mode = S_IFREG | 0444;
323 ch->line_status |= PROTO_UP;
324 comx_status(ch->dev, ch->line_status);
327 static void comxlapb_disconnected(void *token, int reason)
329 struct comx_channel *ch = token;
330 struct proc_dir_entry *comxdir = ch->procdir->subdir;
332 if (ch->debug_flags & DEBUG_COMX_LAPB) {
333 comx_debug(ch->dev, "%s: lapb disconnected, reason: %d\n",
334 ch->dev->name, reason);
337 if (ch->dev->type == ARPHRD_X25) {
338 unsigned char *p;
339 struct sk_buff *skb;
341 if ((skb = dev_alloc_skb(1)) == NULL) {
342 printk(KERN_ERR "comxlapb: out of memory!\n");
343 return;
345 p = skb_put(skb,1);
346 *p = 0x02; // link disconnected
347 skb->dev = ch->dev;
348 skb->protocol = htons(ETH_P_X25);
349 skb->mac.raw = skb->data;
350 skb->pkt_type = PACKET_HOST;
352 netif_rx(skb);
355 for (; comxdir; comxdir = comxdir->next) {
356 if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
357 comxdir->mode = S_IFREG | 0644;
361 ch->line_status &= ~PROTO_UP;
362 comx_status(ch->dev, ch->line_status);
365 static int comxlapb_data_indication(void *token, struct sk_buff *skb)
367 struct comx_channel *ch = token;
369 if (ch->dev->type == ARPHRD_X25) {
370 skb_push(skb, 1);
371 skb->data[0] = 0; // indicate data for X25
372 skb->protocol = htons(ETH_P_X25);
373 } else {
374 skb->protocol = htons(ETH_P_IP);
377 skb->dev = ch->dev;
378 skb->mac.raw = skb->data;
379 return comx_rx(ch->dev, skb);
382 static void comxlapb_data_transmit(void *token, struct sk_buff *skb)
384 struct comx_channel *ch = token;
386 if (ch->HW_send_packet) {
387 ch->HW_send_packet(ch->dev, skb);
391 static int comxlapb_exit(struct net_device *dev)
393 struct comx_channel *ch = dev->priv;
395 dev->flags = 0;
396 dev->type = 0;
397 dev->mtu = 0;
398 dev->hard_header_len = 0;
400 ch->LINE_rx = NULL;
401 ch->LINE_tx = NULL;
402 ch->LINE_status = NULL;
403 ch->LINE_open = NULL;
404 ch->LINE_close = NULL;
405 ch->LINE_xmit = NULL;
406 ch->LINE_header = NULL;
407 ch->LINE_statistics = NULL;
409 if (ch->debug_flags & DEBUG_COMX_LAPB) {
410 comx_debug(dev, "%s: unregistering lapb\n", dev->name);
412 lapb_unregister(dev->priv);
414 remove_proc_entry(FILENAME_T1, ch->procdir);
415 remove_proc_entry(FILENAME_T2, ch->procdir);
416 remove_proc_entry(FILENAME_N2, ch->procdir);
417 remove_proc_entry(FILENAME_MODE, ch->procdir);
418 remove_proc_entry(FILENAME_WINDOW, ch->procdir);
420 MOD_DEC_USE_COUNT;
421 return 0;
424 static int comxlapb_init(struct net_device *dev)
426 struct comx_channel *ch = dev->priv;
427 struct lapb_register_struct lapbreg;
429 dev->mtu = 1500;
430 dev->hard_header_len = 4;
431 dev->addr_len = 0;
433 ch->LINE_rx = comxlapb_rx;
434 ch->LINE_tx = comxlapb_tx;
435 ch->LINE_status = comxlapb_status;
436 ch->LINE_open = comxlapb_open;
437 ch->LINE_close = comxlapb_close;
438 ch->LINE_xmit = comxlapb_xmit;
439 ch->LINE_header = comxlapb_header;
440 ch->LINE_statistics = comxlapb_statistics;
442 lapbreg.connect_confirmation = comxlapb_connected;
443 lapbreg.connect_indication = comxlapb_connected;
444 lapbreg.disconnect_confirmation = comxlapb_disconnected;
445 lapbreg.disconnect_indication = comxlapb_disconnected;
446 lapbreg.data_indication = comxlapb_data_indication;
447 lapbreg.data_transmit = comxlapb_data_transmit;
448 if (lapb_register(dev->priv, &lapbreg)) {
449 return -ENOMEM;
451 if (ch->debug_flags & DEBUG_COMX_LAPB) {
452 comx_debug(dev, "%s: lapb registered\n", dev->name);
455 if (!create_comxlapb_proc_entry(FILENAME_T1, 0644, 8, ch->procdir)) {
456 return -ENOMEM;
458 if (!create_comxlapb_proc_entry(FILENAME_T2, 0644, 8, ch->procdir)) {
459 return -ENOMEM;
461 if (!create_comxlapb_proc_entry(FILENAME_N2, 0644, 8, ch->procdir)) {
462 return -ENOMEM;
464 if (!create_comxlapb_proc_entry(FILENAME_MODE, 0644, 14, ch->procdir)) {
465 return -ENOMEM;
467 if (!create_comxlapb_proc_entry(FILENAME_WINDOW, 0644, 0, ch->procdir)) {
468 return -ENOMEM;
471 MOD_INC_USE_COUNT;
472 return 0;
475 static int comxlapb_init_lapb(struct net_device *dev)
477 dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
478 dev->type = ARPHRD_LAPB;
480 return(comxlapb_init(dev));
483 static int comxlapb_init_x25(struct net_device *dev)
485 dev->flags = IFF_NOARP;
486 dev->type = ARPHRD_X25;
488 return(comxlapb_init(dev));
491 static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
492 int size, struct proc_dir_entry *dir)
494 struct proc_dir_entry *new_file;
496 if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
497 new_file->data = (void *)new_file;
498 new_file->read_proc = &comxlapb_read_proc;
499 new_file->write_proc = &comxlapb_write_proc;
500 new_file->size = size;
501 new_file->nlink = 1;
503 return(new_file);
506 static struct comx_protocol comxlapb_protocol = {
507 "lapb",
508 VERSION,
509 ARPHRD_LAPB,
510 comxlapb_init_lapb,
511 comxlapb_exit,
512 NULL
515 static struct comx_protocol comx25_protocol = {
516 "x25",
517 VERSION,
518 ARPHRD_X25,
519 comxlapb_init_x25,
520 comxlapb_exit,
521 NULL
524 int __init comx_proto_lapb_init(void)
526 int ret;
528 if ((ret = comx_register_protocol(&comxlapb_protocol)) != 0) {
529 return ret;
531 return comx_register_protocol(&comx25_protocol);
534 static void __exit comx_proto_lapb_exit(void)
536 comx_unregister_protocol(comxlapb_protocol.name);
537 comx_unregister_protocol(comx25_protocol.name);
540 #ifdef MODULE
541 module_init(comx_proto_lapb_init);
542 #endif
543 module_exit(comx_proto_lapb_exit);