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>
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
) {
48 lapb_data_received(dev
->priv
, skb
);
52 static int comxlapb_tx(struct net_device
*dev
)
54 netif_wake_queue(dev
);
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
)) {
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
;
82 if (!(ch
->init_status
& HW_OPEN
)) {
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",
94 ch
->init_status
|= LINE_OPEN
;
100 static int comxlapb_close(struct net_device
*dev
)
102 struct comx_channel
*ch
= dev
->priv
;
104 if (!(ch
->init_status
& HW_OPEN
)) {
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
;
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
))) {
129 if (dev
->type
== ARPHRD_X25
) { // first byte tells what to do
130 switch(skb
->data
[0]) {
134 lapb_connect_request(ch
);
138 lapb_disconnect_request(ch
);
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
;
160 len
+= sprintf(page
+ len
, "Line status: ");
161 if (lapb_getparms(dev
->priv
, &parms
) != LAPB_OK
) {
162 len
+= sprintf(page
+ len
, "not initialized\n");
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
);
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
;
182 if (lapb_getparms(dev
->priv
, &parms
)) {
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");
202 printk(KERN_ERR
"comxlapb: internal error, filename %s\n", file
->name
);
212 if (count
>= len
- off
) {
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
;
227 if (lapb_getparms(dev
->priv
, &parms
)) {
231 if (!(page
= (char *)__get_free_page(GFP_KERNEL
))) {
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) {
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) {
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) {
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
);
279 printk(KERN_ERR
"comxlapb_write_proc: internal error, filename %s\n",
284 free_page((unsigned long)page
);
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
) {
302 if ((skb
= dev_alloc_skb(1)) == NULL
) {
303 printk(KERN_ERR
"comxlapb: out of memory!\n");
307 *p
= 0x01; // link established
309 skb
->protocol
= htons(ETH_P_X25
);
310 skb
->mac
.raw
= skb
->data
;
311 skb
->pkt_type
= PACKET_HOST
;
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
) {
341 if ((skb
= dev_alloc_skb(1)) == NULL
) {
342 printk(KERN_ERR
"comxlapb: out of memory!\n");
346 *p
= 0x02; // link disconnected
348 skb
->protocol
= htons(ETH_P_X25
);
349 skb
->mac
.raw
= skb
->data
;
350 skb
->pkt_type
= PACKET_HOST
;
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
) {
371 skb
->data
[0] = 0; // indicate data for X25
372 skb
->protocol
= htons(ETH_P_X25
);
374 skb
->protocol
= htons(ETH_P_IP
);
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
;
398 dev
->hard_header_len
= 0;
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
);
424 static int comxlapb_init(struct net_device
*dev
)
426 struct comx_channel
*ch
= dev
->priv
;
427 struct lapb_register_struct lapbreg
;
430 dev
->hard_header_len
= 4;
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
)) {
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
)) {
458 if (!create_comxlapb_proc_entry(FILENAME_T2
, 0644, 8, ch
->procdir
)) {
461 if (!create_comxlapb_proc_entry(FILENAME_N2
, 0644, 8, ch
->procdir
)) {
464 if (!create_comxlapb_proc_entry(FILENAME_MODE
, 0644, 14, ch
->procdir
)) {
467 if (!create_comxlapb_proc_entry(FILENAME_WINDOW
, 0644, 0, ch
->procdir
)) {
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
;
506 static struct comx_protocol comxlapb_protocol
= {
515 static struct comx_protocol comx25_protocol
= {
524 int __init
comx_proto_lapb_init(void)
528 if ((ret
= comx_register_protocol(&comxlapb_protocol
)) != 0) {
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
);
541 module_init(comx_proto_lapb_init
);
543 module_exit(comx_proto_lapb_exit
);