2 * cycx_x25.c CYCLOM X Multiprotocol WAN Link Driver. X.25 module.
4 * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5 * Copyright: (c) 1998, 1999 Arnaldo Carvalho de Melo
7 * Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 * ============================================================================
14 * 1999/08/10 acme serialized access to the card thru a spinlock
16 * 1999/08/09 acme removed per channel spinlocks
17 * removed references to enable_tx_int
18 * 1999/05/28 acme fixed nibble_to_byte, ackvc now properly treated
20 * 1999/05/25 acme fixed t1, t2, t21 & t23 configuration
21 * use spinlocks instead of cli/sti in some points
22 * 1999/05/24 acme finished the x25_get_stat function
23 * 1999/05/23 acme dev->type = ARPHRD_X25 (tcpdump only works,
24 * AFAIT, with ARPHRD_ETHER). This seems to be
25 * needed to use socket(AF_X25)...
26 * Now the config file must specify a peer media
27 * address for svc channes over a crossover cable.
28 * Removed hold_timeout from x25_channel_t,
30 * A little enhancement in the DEBUG processing
31 * 1999/05/22 acme go to DISCONNECTED in disconnect_confirm_intr,
32 * instead of chan_disc.
33 * 1999/05/16 marcelo fixed timer initialization in SVCs
34 * 1999/01/05 acme x25_configure now get (most of) all
36 * 1999/01/05 acme pktlen now (correctly) uses log2 (value
38 * 1999/01/03 acme judicious use of data types (u8, u16, u32, etc)
39 * 1999/01/03 acme cyx_isr: reset dpmbase to acknowledge
40 * indication (interrupt from cyclom 2x)
41 * 1999/01/02 acme cyx_isr: first hackings...
42 * 1999/01/0203 acme when initializing an array don't give less
43 * elements than declared...
44 * example: char send_cmd[6] = "?\xFF\x10";
45 * you'll gonna lose a couple hours, 'cause your
46 * brain won't admit that there's an error in the
47 * above declaration... the side effect is that
48 * memset is put into the unresolved symbols
49 * instead of using the inline memset functions...
50 * 1999/01/02 acme began chan_connect, chan_send, x25_send
51 * Dec 31, 1998 Arnaldo x25_configure
52 * this code can be compiled as non module
53 * Dec 27, 1998 Arnaldo code cleanup
54 * IPX code wiped out! let's decrease code
55 * complexity for now, remember: I'm learning! :)
56 * bps_to_speed_code OK
57 * Dec 26, 1998 Arnaldo Minimal debug code cleanup
58 * Aug 08, 1998 Arnaldo Initial version.
60 #define CYCLOMX_X25_DEBUG 1
62 #include <linux/version.h>
63 #include <linux/kernel.h> /* printk(), and other useful stuff */
64 #include <linux/stddef.h> /* offsetof(), etc. */
65 #include <linux/errno.h> /* return codes */
66 #include <linux/string.h> /* inline memset(), etc. */
67 #include <linux/malloc.h> /* kmalloc(), kfree() */
68 #include <linux/wanrouter.h> /* WAN router definitions */
69 #include <asm/byteorder.h> /* htons(), etc. */
70 #include <linux/if_arp.h> /* ARPHRD_X25 */
71 #include <linux/cyclomx.h> /* CYCLOM X common user API definitions */
72 #include <linux/cycx_x25.h> /* X.25 firmware API definitions */
74 /* Defines & Macros */
75 #define MAX_CMD_RETRY 5
76 #define X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */
79 /* This is an extention of the 'struct net_device' we create for each network
80 interface to keep the rest of X.25 channel-specific data. */
81 typedef struct x25_channel
{
82 char name
[WAN_IFNAME_SZ
+1]; /* interface name, ASCIIZ */
83 char addr
[WAN_ADDRESS_SZ
+1]; /* media address, ASCIIZ */
84 char *local_addr
; /* local media address, ASCIIZ -
85 svc thru crossover cable */
86 s16 lcn
; /* logical channel number/conn.req.key*/
88 struct timer_list timer
; /* timer used for svc channel disc. */
89 u16 protocol
; /* ethertype, 0 - multiplexed */
90 u8 svc
; /* 0 - permanent, 1 - switched */
91 u8 state
; /* channel state */
92 u8 drop_sequence
; /* mark sequence for dropping */
93 u32 idle_tmout
; /* sec, before disconnecting */
94 struct sk_buff
*rx_skb
; /* receive socket buffer */
95 cycx_t
*card
; /* -> owner */
96 struct enet_statistics ifstats
; /* interface statistics */
99 /* Function Prototypes */
100 /* WAN link driver entry points. These are called by the WAN router module. */
101 static int update (wan_device_t
*wandev
),
102 new_if (wan_device_t
*wandev
, struct net_device
*dev
,wanif_conf_t
*conf
),
103 del_if (wan_device_t
*wandev
, struct net_device
*dev
);
105 /* Network device interface */
106 static int if_init (struct net_device
*dev
),
107 if_open (struct net_device
*dev
),
108 if_close (struct net_device
*dev
),
109 if_header (struct sk_buff
*skb
, struct net_device
*dev
,
110 u16 type
, void *daddr
, void *saddr
, unsigned len
),
111 if_rebuild_hdr (struct sk_buff
*skb
),
112 if_send (struct sk_buff
*skb
, struct net_device
*dev
);
114 static struct net_device_stats
* if_stats (struct net_device
*dev
);
116 /* Interrupt handlers */
117 static void cyx_isr (cycx_t
*card
),
118 tx_intr (cycx_t
*card
, TX25Cmd
*cmd
),
119 rx_intr (cycx_t
*card
, TX25Cmd
*cmd
),
120 log_intr (cycx_t
*card
, TX25Cmd
*cmd
),
121 stat_intr (cycx_t
*card
, TX25Cmd
*cmd
),
122 connect_confirm_intr (cycx_t
*card
, TX25Cmd
*cmd
),
123 disconnect_confirm_intr (cycx_t
*card
, TX25Cmd
*cmd
),
124 connect_intr (cycx_t
*card
, TX25Cmd
*cmd
),
125 disconnect_intr (cycx_t
*card
, TX25Cmd
*cmd
),
126 spur_intr (cycx_t
*card
, TX25Cmd
*cmd
);
128 /* X.25 firmware interface functions */
129 static int x25_configure (cycx_t
*card
, TX25Config
*conf
),
130 x25_get_stats (cycx_t
*card
),
131 x25_send (cycx_t
*card
, u8 link
, u8 lcn
, u8 bitm
, int len
,void *buf
),
132 x25_connect_response (cycx_t
*card
, x25_channel_t
*chan
),
133 x25_disconnect_response (cycx_t
*card
, u8 link
, u8 lcn
);
135 /* Miscellaneous functions */
136 static int chan_connect (struct net_device
*dev
),
137 chan_send (struct net_device
*dev
, struct sk_buff
*skb
);
139 static void set_chan_state (struct net_device
*dev
, u8 state
),
140 nibble_to_byte (u8
*s
, u8
*d
, u8 len
, u8 nibble
),
141 reset_timer (struct net_device
*dev
),
142 chan_disc (struct net_device
*dev
),
143 chan_timer (unsigned long d
);
145 static u8
bps_to_speed_code (u32 bps
);
146 static u8
log2 (u32 n
);
148 static unsigned dec_to_uint (u8
*str
, int len
);
150 static struct net_device
*get_dev_by_lcn (wan_device_t
*wandev
, s16 lcn
);
151 static struct net_device
*get_dev_by_dte_addr (wan_device_t
*wandev
, char *dte
);
153 #ifdef CYCLOMX_X25_DEBUG
154 static void hex_dump(char *msg
, unsigned char *p
, int len
);
155 static void x25_dump_config(TX25Config
*conf
);
156 static void x25_dump_stats(TX25Stats
*stats
);
157 static void x25_dump_devs(wan_device_t
*wandev
);
158 #define dprintk(format, a...) printk(format, ##a)
160 #define hex_dump(msg, p, len)
161 #define x25_dump_config(conf)
162 #define x25_dump_stats(stats)
163 #define x25_dump_devs(wandev)
164 #define dprintk(format, a...)
166 /* Public Functions */
168 /* X.25 Protocol Initialization routine.
170 * This routine is called by the main CYCLOM X module during setup. At this
171 * point adapter is completely initialized and X.25 firmware is running.
172 * o read firmware version (to make sure it's alive)
173 * o configure adapter
174 * o initialize protocol-specific fields of the adapter data space.
178 int cyx_init (cycx_t
*card
, wandev_conf_t
*conf
)
182 /* Verify configuration ID */
183 if (conf
->config_id
!= WANCONFIG_X25
) {
184 printk(KERN_INFO
"%s: invalid configuration ID %u!\n",
185 card
->devname
, conf
->config_id
);
189 /* Initialize protocol-specific fields */
190 card
->mbox
= card
->hw
.dpmbase
+ X25_MBOX_OFFS
;
191 card
->u
.x
.connection_keys
= 0;
192 card
->u
.x
.lock
= SPIN_LOCK_UNLOCKED
;
194 /* Configure adapter. Here we set resonable defaults, then parse
195 * device configuration structure and set configuration options.
196 * Most configuration options are verified and corrected (if
197 * necessary) since we can't rely on the adapter to do so and don't
198 * want it to fail either. */
199 memset(&cfg
, 0, sizeof(cfg
));
201 cfg
.clock
= conf
->clocking
== WANOPT_EXTERNAL
? 8 : 55;
202 cfg
.speed
= bps_to_speed_code(conf
->bps
);
208 cfg
.flags
= 0x02; /* default = V35 */
209 cfg
.t1
= 10; /* line carrier timeout */
210 cfg
.t2
= 29; /* tx timeout */
211 cfg
.t21
= 180; /* CALL timeout */
212 cfg
.t23
= 180; /* CLEAR timeout */
215 if (!conf
->mtu
|| conf
->mtu
>= 512)
216 card
->wandev
.mtu
= 512;
217 else if (conf
->mtu
>= 256)
218 card
->wandev
.mtu
= 256;
219 else if (conf
->mtu
>= 128)
220 card
->wandev
.mtu
= 128;
222 card
->wandev
.mtu
= 64;
224 cfg
.pktlen
= log2(card
->wandev
.mtu
);
226 if (conf
->station
== WANOPT_DTE
) {
227 cfg
.locaddr
= 3; /* DTE */
228 cfg
.remaddr
= 1; /* DCE */
230 cfg
.locaddr
= 1; /* DCE */
231 cfg
.remaddr
= 3; /* DTE */
234 if (conf
->interface
== WANOPT_RS232
)
235 cfg
.flags
= 0; /* FIXME just reset the 2nd bit */
237 if (conf
->u
.x25
.hi_pvc
) {
238 card
->u
.x
.hi_pvc
= min(conf
->u
.x25
.hi_pvc
, 4095);
239 card
->u
.x
.lo_pvc
= min(conf
->u
.x25
.lo_pvc
, card
->u
.x
.hi_pvc
);
242 if (conf
->u
.x25
.hi_svc
) {
243 card
->u
.x
.hi_svc
= min(conf
->u
.x25
.hi_svc
, 4095);
244 card
->u
.x
.lo_svc
= min(conf
->u
.x25
.lo_svc
, card
->u
.x
.hi_svc
);
247 if (card
->u
.x
.lo_pvc
== 255)
250 cfg
.npvc
= card
->u
.x
.hi_pvc
- card
->u
.x
.lo_pvc
+ 1;
252 cfg
.nvc
= card
->u
.x
.hi_svc
- card
->u
.x
.lo_svc
+ 1 + cfg
.npvc
;
254 if (conf
->u
.x25
.hdlc_window
)
255 cfg
.n2win
= min(conf
->u
.x25
.hdlc_window
, 7);
257 if (conf
->u
.x25
.pkt_window
)
258 cfg
.n3win
= min(conf
->u
.x25
.pkt_window
, 7);
261 cfg
.t1
= min(conf
->u
.x25
.t1
, 30);
264 cfg
.t2
= min(conf
->u
.x25
.t2
, 30);
266 if (conf
->u
.x25
.t11_t21
)
267 cfg
.t21
= min(conf
->u
.x25
.t11_t21
, 30);
269 if (conf
->u
.x25
.t13_t23
)
270 cfg
.t23
= min(conf
->u
.x25
.t13_t23
, 30);
273 cfg
.n2
= min(conf
->u
.x25
.n2
, 30);
275 /* initialize adapter */
276 if (x25_configure(card
, &cfg
))
279 /* Initialize protocol-specific fields of adapter data space */
280 card
->wandev
.bps
= conf
->bps
;
281 card
->wandev
.interface
= conf
->interface
;
282 card
->wandev
.clocking
= conf
->clocking
;
283 card
->wandev
.station
= conf
->station
;
284 card
->isr
= &cyx_isr
;
286 card
->wandev
.update
= &update
;
287 card
->wandev
.new_if
= &new_if
;
288 card
->wandev
.del_if
= &del_if
;
289 card
->wandev
.state
= WAN_DISCONNECTED
;
293 /* WAN Device Driver Entry Points */
294 /* Update device status & statistics. */
295 static int update (wan_device_t
*wandev
)
298 if (!wandev
|| !wandev
->private)
301 if (wandev
->state
== WAN_UNCONFIGURED
)
304 x25_get_stats(wandev
->private);
308 /* Create new logical channel.
309 * This routine is called by the router when ROUTER_IFNEW IOCTL is being
311 * o parse media- and hardware-specific configuration
312 * o make sure that a new channel can be created
313 * o allocate resources, if necessary
314 * o prepare network device structure for registaration.
317 * < 0 failure (channel will not be created) */
318 static int new_if (wan_device_t
*wandev
, struct net_device
*dev
, wanif_conf_t
*conf
)
320 cycx_t
*card
= wandev
->private;
324 if (conf
->name
[0] == '\0' || strlen(conf
->name
) > WAN_IFNAME_SZ
) {
325 printk(KERN_INFO
"%s: invalid interface name!\n",card
->devname
);
329 /* allocate and initialize private data */
330 if ((chan
= kmalloc(sizeof(x25_channel_t
), GFP_KERNEL
)) == NULL
)
333 memset(chan
, 0, sizeof(x25_channel_t
));
334 strcpy(chan
->name
, conf
->name
);
336 chan
->link
= conf
->port
;
337 chan
->protocol
= ETH_P_IP
;
339 /* only used in svc connected thru crossover cable */
340 chan
->local_addr
= NULL
;
342 if (conf
->addr
[0] == '@') { /* SVC */
343 int len
= strlen(conf
->local_addr
);
346 if (len
> WAN_ADDRESS_SZ
) {
347 printk(KERN_ERR
"%s: %s local addr too long!\n",
348 wandev
->name
, chan
->name
);
352 chan
->local_addr
= kmalloc(len
+ 1, GFP_KERNEL
);
354 if (!chan
->local_addr
) {
360 strncpy(chan
->local_addr
, conf
->local_addr
,
365 strncpy(chan
->addr
, &conf
->addr
[1], WAN_ADDRESS_SZ
);
366 init_timer(&chan
->timer
);
367 chan
->timer
.function
= chan_timer
;
368 chan
->timer
.data
= (unsigned long) dev
;
370 /* Set channel timeouts (default if not specified) */
371 chan
->idle_tmout
= conf
->idle_timeout
? conf
->idle_timeout
: 90;
372 } else if (is_digit(conf
->addr
[0])) { /* PVC */
373 s16 lcn
= dec_to_uint(conf
->addr
, 0);
375 if (lcn
>= card
->u
.x
.lo_pvc
&& lcn
<= card
->u
.x
.hi_pvc
)
379 "%s: PVC %u is out of range on interface %s!\n",
380 wandev
->name
, lcn
, chan
->name
);
384 printk(KERN_ERR
"%s: invalid media address on interface %s!\n",
385 wandev
->name
, chan
->name
);
390 if (chan
->local_addr
)
391 kfree(chan
->local_addr
);
397 /* prepare network device data space for registration */
398 dev
->name
= chan
->name
;
399 dev
->init
= &if_init
;
404 /* Delete logical channel. */
405 static int del_if (wan_device_t
*wandev
, struct net_device
*dev
)
408 printk(KERN_ERR
"cycx_x25:del_if:dev == NULL!\n");
413 x25_channel_t
*chan
= dev
->priv
;
416 if (chan
->local_addr
)
417 kfree(chan
->local_addr
);
419 if (chan
->state
== WAN_CONNECTED
)
420 del_timer(&chan
->timer
);
430 /* Network Device Interface */
431 /* Initialize Linux network interface.
433 * This routine is called only once for each interface, during Linux network
434 * interface registration. Returning anything but zero will fail interface
436 static int if_init (struct net_device
*dev
)
438 x25_channel_t
*chan
= dev
->priv
;
439 cycx_t
*card
= chan
->card
;
440 wan_device_t
*wandev
= &card
->wandev
;
442 /* Initialize device driver entry points */
443 dev
->open
= &if_open
;
444 dev
->stop
= &if_close
;
445 dev
->hard_header
= &if_header
;
446 dev
->rebuild_header
= &if_rebuild_hdr
;
447 dev
->hard_start_xmit
= &if_send
;
448 dev
->get_stats
= &if_stats
;
450 /* Initialize media-specific parameters */
451 dev
->mtu
= X25_CHAN_MTU
;
452 dev
->type
= ARPHRD_X25
; /* ARP h/w type */
453 dev
->hard_header_len
= 0; /* media header length */
454 dev
->addr_len
= 0; /* hardware address length */
457 *(u16
*)dev
->dev_addr
= htons(chan
->lcn
);
459 /* Initialize hardware parameters (just for reference) */
460 dev
->irq
= wandev
->irq
;
461 dev
->dma
= wandev
->dma
;
462 dev
->base_addr
= wandev
->ioport
;
463 dev
->mem_start
= (unsigned long)wandev
->maddr
;
464 dev
->mem_end
= (unsigned long)(wandev
->maddr
+ wandev
->msize
- 1);
465 dev
->flags
|= IFF_NOARP
;
467 /* Set transmit buffer queue length */
468 dev
->tx_queue_len
= 10;
470 /* Initialize socket buffers */
471 dev_init_buffers(dev
);
472 set_chan_state(dev
, WAN_DISCONNECTED
);
476 /* Open network interface.
477 * o prevent module from unloading by incrementing use count
478 * o if link is disconnected then initiate connection
480 * Return 0 if O.k. or errno. */
481 static int if_open (struct net_device
*dev
)
483 x25_channel_t
*chan
= dev
->priv
;
484 cycx_t
*card
= chan
->card
;
487 return -EBUSY
; /* only one open is allowed */
497 /* Close network interface.
499 * o if there's no more open channels then disconnect physical link. */
500 static int if_close (struct net_device
*dev
)
502 x25_channel_t
*chan
= dev
->priv
;
503 cycx_t
*card
= chan
->card
;
507 if (chan
->state
== WAN_CONNECTED
|| chan
->state
== WAN_CONNECTING
)
514 /* Build media header.
515 * o encapsulate packet according to encapsulation type.
517 * The trick here is to put packet type (Ethertype) into 'protocol' field of
518 * the socket buffer, so that we don't forget it. If encapsulation fails,
519 * set skb->protocol to 0 and discard packet later.
521 * Return: media header length. */
522 static int if_header (struct sk_buff
*skb
, struct net_device
*dev
,
523 u16 type
, void *daddr
, void *saddr
, unsigned len
)
525 skb
->protocol
= type
;
526 return dev
->hard_header_len
;
529 /* * Re-build media header.
530 * Return: 1 physical address resolved.
531 * 0 physical address not resolved */
532 static int if_rebuild_hdr (struct sk_buff
*skb
)
537 /* Send a packet on a network interface.
538 * o set tbusy flag (marks start of the transmission).
539 * o check link state. If link is not up, then drop the packet.
540 * o check channel status. If it's down then initiate a call.
541 * o pass a packet to corresponding WAN device.
542 * o free socket buffer
544 * Return: 0 complete (socket buffer must be freed)
545 * non-0 packet may be re-transmitted (tbusy must be set)
548 * 1. This routine is called either by the protocol stack or by the "net
549 * bottom half" (with interrupts enabled).
550 * 2. Setting tbusy flag will inhibit further transmit requests from the
551 * protocol stack and can be used for flow control with protocol layer. */
552 static int if_send (struct sk_buff
*skb
, struct net_device
*dev
)
554 x25_channel_t
*chan
= dev
->priv
;
555 cycx_t
*card
= chan
->card
;
558 ++chan
->ifstats
.rx_dropped
;
563 chan
->protocol
= skb
->protocol
;
565 if (card
->wandev
.state
!= WAN_CONNECTED
)
566 ++chan
->ifstats
.tx_dropped
;
567 else if (chan
->svc
&& chan
->protocol
&&
568 chan
->protocol
!= skb
->protocol
) {
570 "%s: unsupported Ethertype 0x%04X on interface %s!\n",
571 card
->devname
, skb
->protocol
, dev
->name
);
572 ++chan
->ifstats
.tx_errors
;
573 } else switch (chan
->state
) {
574 case WAN_DISCONNECTED
:
575 if (chan_connect(dev
)) {
582 dev
->trans_start
= jiffies
;
585 if (chan_send(dev
, skb
)) {
590 ++chan
->ifstats
.tx_dropped
;
591 ++card
->wandev
.stats
.tx_dropped
;
598 /* Get Ethernet-style interface statistics.
599 * Return a pointer to struct net_device_stats */
600 static struct net_device_stats
*if_stats (struct net_device
*dev
)
602 x25_channel_t
*chan
= dev
->priv
;
604 return chan
? &chan
->ifstats
: NULL
;
607 /* Interrupt Handlers */
608 /* X.25 Interrupt Service Routine. */
609 static void cyx_isr (cycx_t
*card
)
615 card
->buff_int_mode_unbusy
= 0;
616 cycx_peek(&card
->hw
, X25_RXMBOX_OFFS
, &cmd
, sizeof(cmd
));
618 switch (cmd
.command
) {
619 case X25_DATA_INDICATION
:
622 case X25_ACK_FROM_VC
:
626 log_intr(card
, &cmd
);
629 stat_intr(card
, &cmd
);
631 case X25_CONNECT_CONFIRM
:
632 connect_confirm_intr(card
, &cmd
);
634 case X25_CONNECT_INDICATION
:
635 connect_intr(card
, &cmd
);
637 case X25_DISCONNECT_INDICATION
:
638 disconnect_intr(card
, &cmd
);
640 case X25_DISCONNECT_CONFIRM
:
641 disconnect_confirm_intr(card
, &cmd
);
644 cyclomx_set_state(card
, WAN_CONNECTED
);
647 cyclomx_set_state(card
, WAN_DISCONNECTED
);
650 spur_intr(card
, &cmd
); /* unwanted interrupt */
653 cycx_poke(&card
->hw
, 0, &z
, sizeof(z
));
654 cycx_poke(&card
->hw
, X25_RXMBOX_OFFS
, &z
, sizeof(z
));
657 if (card
->buff_int_mode_unbusy
)
661 /* Transmit interrupt handler.
662 * o Release socket buffer
663 * o Clear 'tbusy' flag */
664 static void tx_intr (cycx_t
*card
, TX25Cmd
*cmd
)
666 struct net_device
*dev
;
667 wan_device_t
*wandev
= &card
->wandev
;
670 cycx_peek(&card
->hw
, cmd
->buf
, &lcn
, sizeof(lcn
));
672 /* unbusy device and then dev_tint(); */
673 if ((dev
= get_dev_by_lcn (wandev
, lcn
)) != NULL
) {
674 card
->buff_int_mode_unbusy
= 1;
677 printk(KERN_ERR
"%s:ackvc for inexistent lcn %d\n",
681 /* Receive interrupt handler.
682 * This routine handles fragmented IP packets using M-bit according to the
684 * o map ligical channel number to network interface.
685 * o allocate socket buffer or append received packet to the existing one.
686 * o if M-bit is reset (i.e. it's the last packet in a sequence) then
687 * decapsulate packet and pass socket buffer to the protocol stack.
690 * 1. When allocating a socket buffer, if M-bit is set then more data is
691 * comming and we have to allocate buffer for the maximum IP packet size
692 * expected on this channel.
693 * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
694 * socket buffers available) the whole packet sequence must be discarded. */
695 static void rx_intr (cycx_t
*card
, TX25Cmd
*cmd
)
697 wan_device_t
*wandev
= &card
->wandev
;
698 struct net_device
*dev
;
702 int pktlen
= cmd
->len
- 5;
704 cycx_peek(&card
->hw
, cmd
->buf
, &lcn
, sizeof(lcn
));
705 cycx_peek(&card
->hw
, cmd
->buf
+ 4, &bitm
, sizeof(bitm
));
708 if ((dev
= get_dev_by_lcn(wandev
, lcn
)) == NULL
) {
709 /* Invalid channel, discard packet */
710 printk(KERN_INFO
"%s: receiving on orphaned LCN %d!\n",
718 if (chan
->drop_sequence
) {
720 chan
->drop_sequence
= 0;
725 if ((skb
= chan
->rx_skb
) == NULL
) {
726 /* Allocate new socket buffer */
727 int bufsize
= bitm
? dev
->mtu
: pktlen
;
729 if ((skb
= dev_alloc_skb(bufsize
+
730 dev
->hard_header_len
)) == NULL
) {
731 printk(KERN_INFO
"%s: no socket buffers available!\n",
733 chan
->drop_sequence
= 1;
734 ++chan
->ifstats
.rx_dropped
;
739 skb
->protocol
= htons(chan
->protocol
);
743 if (skb_tailroom(skb
) < pktlen
) {
744 /* No room for the packet. Call off the whole thing! */
749 chan
->drop_sequence
= 1;
751 printk(KERN_INFO
"%s: unexpectedly long packet sequence "
752 "on interface %s!\n", card
->devname
, dev
->name
);
753 ++chan
->ifstats
.rx_length_errors
;
757 /* Append packet to the socket buffer */
758 cycx_peek(&card
->hw
, cmd
->buf
+ 5, skb_put(skb
, pktlen
), pktlen
);
761 return; /* more data is coming */
763 dev
->last_rx
= jiffies
; /* timestamp */
764 chan
->rx_skb
= NULL
; /* dequeue packet */
766 skb
->protocol
= htons(ETH_P_IP
);
768 skb
->mac
.raw
= skb
->data
;
770 ++chan
->ifstats
.rx_packets
;
771 chan
->ifstats
.rx_bytes
+= skb
->len
;
774 /* Connect interrupt handler. */
775 static void connect_intr (cycx_t
*card
, TX25Cmd
*cmd
)
777 wan_device_t
*wandev
= &card
->wandev
;
778 struct net_device
*dev
= NULL
;
783 u8 lcn
, sizeloc
, sizerem
;
785 cycx_peek(&card
->hw
, cmd
->buf
, &lcn
, sizeof(lcn
));
786 cycx_peek(&card
->hw
, cmd
->buf
+ 5, &sizeloc
, sizeof(sizeloc
));
787 cycx_peek(&card
->hw
, cmd
->buf
+ 6, d
, cmd
->len
- 6);
789 sizerem
= sizeloc
>> 4;
792 loc
[0] = rem
[0] = '\0';
795 nibble_to_byte(d
, loc
, sizeloc
, 0);
798 nibble_to_byte(d
+ (sizeloc
>> 1), rem
, sizerem
, sizeloc
& 1);
800 dprintk(KERN_INFO
"connect_intr:lcn=%d, local=%s, remote=%s\n",
802 if ((dev
= get_dev_by_dte_addr(wandev
, rem
)) == NULL
) {
803 /* Invalid channel, discard packet */
804 printk(KERN_INFO
"%s: connect not expected: remote %s!\n",
811 x25_connect_response(card
, chan
);
812 set_chan_state(dev
, WAN_CONNECTED
);
815 /* Connect confirm interrupt handler. */
816 static void connect_confirm_intr (cycx_t
*card
, TX25Cmd
*cmd
)
818 wan_device_t
*wandev
= &card
->wandev
;
819 struct net_device
*dev
;
823 cycx_peek(&card
->hw
, cmd
->buf
, &lcn
, sizeof(lcn
));
824 cycx_peek(&card
->hw
, cmd
->buf
+ 1, &key
, sizeof(key
));
825 dprintk(KERN_INFO
"%s: connect_confirm_intr:lcn=%d, key=%d\n",
826 card
->devname
, lcn
, key
);
827 if ((dev
= get_dev_by_lcn(wandev
, -key
)) == NULL
) {
828 /* Invalid channel, discard packet */
829 clear_bit(--key
, (void*)&card
->u
.x
.connection_keys
);
830 printk(KERN_INFO
"%s: connect confirm not expected: lcn %d, "
831 "key=%d!\n", card
->devname
, lcn
, key
);
835 clear_bit(--key
, (void*)&card
->u
.x
.connection_keys
);
838 set_chan_state(dev
, WAN_CONNECTED
);
841 /* Disonnect confirm interrupt handler. */
842 static void disconnect_confirm_intr (cycx_t
*card
, TX25Cmd
*cmd
)
844 wan_device_t
*wandev
= &card
->wandev
;
845 struct net_device
*dev
;
848 cycx_peek(&card
->hw
, cmd
->buf
, &lcn
, sizeof(lcn
));
849 dprintk(KERN_INFO
"%s: disconnect_confirm_intr:lcn=%d\n",
851 if ((dev
= get_dev_by_lcn(wandev
, lcn
)) == NULL
) {
852 /* Invalid channel, discard packet */
853 printk(KERN_INFO
"%s:disconnect confirm not expected!:lcn %d\n",
858 set_chan_state(dev
, WAN_DISCONNECTED
);
861 /* disconnect interrupt handler. */
862 static void disconnect_intr (cycx_t
*card
, TX25Cmd
*cmd
)
864 wan_device_t
*wandev
= &card
->wandev
;
865 struct net_device
*dev
;
868 cycx_peek(&card
->hw
, cmd
->buf
, &lcn
, sizeof(lcn
));
869 dprintk(KERN_INFO
"disconnect_intr:lcn=%d\n", lcn
);
871 if ((dev
= get_dev_by_lcn(wandev
, lcn
)) != NULL
) {
872 x25_channel_t
*chan
= dev
->priv
;
874 x25_disconnect_response(card
, chan
->link
, lcn
);
875 set_chan_state(dev
, WAN_DISCONNECTED
);
877 x25_disconnect_response(card
, 0, lcn
);
880 /* LOG interrupt handler. */
881 static void log_intr (cycx_t
*card
, TX25Cmd
*cmd
)
883 #if CYCLOMX_X25_DEBUG
885 u16 size
, toread
, link
, msg_code
;
888 cycx_peek(&card
->hw
, cmd
->buf
, &msg_code
, sizeof(msg_code
));
889 cycx_peek(&card
->hw
, cmd
->buf
+ 2, &link
, sizeof(link
));
890 cycx_peek(&card
->hw
, cmd
->buf
+ 4, &size
, sizeof(size
));
891 /* at most 20 bytes are available... thanx to Daniela :) */
892 toread
= size
< 20 ? size
: 20;
893 cycx_peek(&card
->hw
, cmd
->buf
+ 10, &bf
, toread
);
894 cycx_peek(&card
->hw
, cmd
->buf
+ 10 + toread
, &code
, 1);
895 cycx_peek(&card
->hw
, cmd
->buf
+ 10 + toread
+ 1, &routine
, 1);
897 printk(KERN_INFO
"cyx_isr: X25_LOG (0x4500) indic.:\n");
898 printk(KERN_INFO
"cmd->buf=0x%X\n", cmd
->buf
);
899 printk(KERN_INFO
"Log message code=0x%X\n", msg_code
);
900 printk(KERN_INFO
"Link=%d\n", link
);
901 printk(KERN_INFO
"log code=0x%X\n", code
);
902 printk(KERN_INFO
"log routine=0x%X\n", routine
);
903 printk(KERN_INFO
"Message size=%d\n", size
);
904 hex_dump("Message", bf
, toread
);
908 /* STATISTIC interrupt handler. */
909 static void stat_intr (cycx_t
*card
, TX25Cmd
*cmd
)
911 cycx_peek(&card
->hw
, cmd
->buf
, &card
->u
.x
.stats
,
912 sizeof(card
->u
.x
.stats
));
913 hex_dump("stat_intr", (unsigned char*)&card
->u
.x
.stats
,
914 sizeof(card
->u
.x
.stats
));
915 x25_dump_stats(&card
->u
.x
.stats
);
916 wake_up_interruptible(&card
->wait_stats
);
919 /* Spurious interrupt handler.
921 * If number of spurious interrupts exceeded some limit, then ??? */
922 static void spur_intr (cycx_t
*card
, TX25Cmd
*cmd
)
924 printk(KERN_INFO
"%s: spurious interrupt (0x%X)!\n",
925 card
->devname
, cmd
->command
);
927 #ifdef CYCLOMX_X25_DEBUG
928 static void hex_dump(char *msg
, unsigned char *p
, int len
)
930 unsigned char hex
[1024],
933 if (len
>= (sizeof(hex
) / 2))
934 len
= (sizeof(hex
) / 2) - 1;
937 sprintf(phex
, "%02x", *p
++);
941 printk(KERN_INFO
"%s: %s\n", msg
, hex
);
944 /* CYCLOM X Firmware-Specific Functions */
945 /* Exec x25 command. */
946 static int x25_exec (cycx_t
*card
, int command
, int link
,
947 void *d1
, int len1
, void *d2
, int len2
)
951 u32 addr
= 0x1200 + 0x2E0 * link
+ 0x1E2;
952 u8 retry
= MAX_CMD_RETRY
;
959 spin_lock_irqsave(&card
->u
.x
.lock
, flags
);
962 cycx_poke(&card
->hw
, X25_MBOX_OFFS
, &c
, sizeof(c
) - sizeof(c
.buf
));
966 cycx_poke(&card
->hw
, addr
, d1
, len1
);
970 u32 addr1
= 0xA00 + 0x400 * link
;
972 cycx_poke(&card
->hw
, addr
+ len1
, d2
, 249);
973 cycx_poke(&card
->hw
, addr1
, ((u8
*) d2
) + 249,
976 cycx_poke(&card
->hw
, addr
+ len1
, d2
, len2
);
980 /* generate interruption, executing command */
981 cycx_intr(&card
->hw
);
983 /* wait till card->mbox == 0 */
985 err
= cycx_exec(card
->mbox
);
986 } while (retry
-- && err
);
988 spin_unlock_irqrestore(&card
->u
.x
.lock
, flags
);
993 /* Configure adapter. */
994 static int x25_configure (cycx_t
*card
, TX25Config
*conf
)
1001 memset (&x25_cmd_conf
, 0, sizeof(x25_cmd_conf
));
1002 x25_cmd_conf
.nlinks
= 2;
1003 x25_cmd_conf
.conf
[0] = *conf
;
1004 /* FIXME: we need to find a way in the wanrouter framework
1005 to configure the second link, for now lets use it
1006 with the same config from the first link, fixing
1007 the interface type to RS232, the speed in 38400 and
1008 the clock to external */
1009 x25_cmd_conf
.conf
[1] = *conf
;
1010 x25_cmd_conf
.conf
[1].link
= 1;
1011 x25_cmd_conf
.conf
[1].speed
= 5; /* 38400 */
1012 x25_cmd_conf
.conf
[1].clock
= 8;
1013 x25_cmd_conf
.conf
[1].flags
= 0; /* default = RS232 */
1015 x25_dump_config(&x25_cmd_conf
.conf
[0]);
1016 x25_dump_config(&x25_cmd_conf
.conf
[1]);
1018 return x25_exec(card
, X25_CONFIG
, 0,
1019 &x25_cmd_conf
, sizeof(x25_cmd_conf
), NULL
, 0);
1022 /* Get protocol statistics. */
1023 static int x25_get_stats (cycx_t
*card
)
1025 /* the firmware expects 20 in the size field!!!
1027 int err
= x25_exec(card
, X25_STATISTIC
, 0, NULL
, 20, NULL
, 0);
1032 interruptible_sleep_on(&card
->wait_stats
);
1034 if (signal_pending(current
))
1037 card
->wandev
.stats
.rx_packets
= card
->u
.x
.stats
.n2_rx_frames
;
1038 card
->wandev
.stats
.rx_over_errors
= card
->u
.x
.stats
.rx_over_errors
;
1039 card
->wandev
.stats
.rx_crc_errors
= card
->u
.x
.stats
.rx_crc_errors
;
1040 card
->wandev
.stats
.rx_length_errors
= 0; /* not available from fw */
1041 card
->wandev
.stats
.rx_frame_errors
= 0; /* not available from fw */
1042 card
->wandev
.stats
.rx_missed_errors
= card
->u
.x
.stats
.rx_aborts
;
1043 card
->wandev
.stats
.rx_dropped
= 0; /* not available from fw */
1044 card
->wandev
.stats
.rx_errors
= 0; /* not available from fw */
1045 card
->wandev
.stats
.tx_packets
= card
->u
.x
.stats
.n2_tx_frames
;
1046 card
->wandev
.stats
.tx_aborted_errors
= card
->u
.x
.stats
.tx_aborts
;
1047 card
->wandev
.stats
.tx_dropped
= 0; /* not available from fw */
1048 card
->wandev
.stats
.collisions
= 0; /* not available from fw */
1049 card
->wandev
.stats
.tx_errors
= 0; /* not available from fw */
1051 x25_dump_devs(&card
->wandev
);
1055 /* return the number of nibbles */
1056 static int byte_to_nibble(u8
*s
, u8
*d
, char *nibble
)
1060 if (*nibble
&& *s
) {
1067 d
[i
] = (*s
- '0') << 4;
1069 d
[i
] |= *(s
+ 1) - '0';
1081 static void nibble_to_byte(u8
*s
, u8
*d
, u8 len
, u8 nibble
)
1084 *d
++ = '0' + (*s
++ & 0x0F);
1089 *d
++ = '0' + (*s
>> 4);
1092 *d
++ = '0' + (*s
& 0x0F);
1102 /* Place X.25 call. */
1103 static int x25_place_call (cycx_t
*card
, x25_channel_t
*chan
)
1109 mylen
= chan
->local_addr
? strlen(chan
->local_addr
) : 0,
1110 remotelen
= strlen(chan
->addr
);
1113 if (card
->u
.x
.connection_keys
== ~0UL) {
1114 printk(KERN_INFO
"%s: too many simultaneous connection "
1115 "requests!\n", card
->devname
);
1119 key
= ffz(card
->u
.x
.connection_keys
);
1120 set_bit(key
, (void*)&card
->u
.x
.connection_keys
);
1122 dprintk(KERN_INFO
"%s:x25_place_call:key=%d\n", card
->devname
, key
);
1123 memset(d
, 0, sizeof(d
));
1124 d
[1] = key
; /* user key */
1128 len
= byte_to_nibble(chan
->addr
, d
+ 6, &nibble
);
1130 if (chan
->local_addr
)
1131 len
+= byte_to_nibble(chan
->local_addr
, d
+ 6 + len
, &nibble
);
1136 d
[5] = mylen
<< 4 | remotelen
;
1137 d
[6 + len
+ 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */
1139 if ((err
= x25_exec(card
, X25_CONNECT_REQUEST
, chan
->link
,
1140 &d
, 7 + len
+ 1, NULL
, 0)) != 0)
1141 clear_bit(--key
, (void*)&card
->u
.x
.connection_keys
);
1144 chan
->protocol
= ETH_P_IP
;
1150 /* Place X.25 CONNECT RESPONSE. */
1151 static int x25_connect_response (cycx_t
*card
, x25_channel_t
*chan
)
1155 memset(d
, 0, sizeof(d
));
1156 d
[0] = d
[3] = chan
->lcn
;
1159 d
[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */
1161 return x25_exec(card
, X25_CONNECT_RESPONSE
, chan
->link
, &d
, 8, NULL
, 0);
1164 /* Place X.25 DISCONNECT RESPONSE. */
1165 static int x25_disconnect_response (cycx_t
*card
, u8 link
, u8 lcn
)
1169 memset(d
, 0, sizeof(d
));
1173 return x25_exec(card
, X25_DISCONNECT_RESPONSE
, link
, &d
, 5, NULL
, 0);
1176 /* Clear X.25 call. */
1177 static int x25_clear_call (cycx_t
*card
, u8 link
, u8 lcn
, u8 cause
, u8 diagn
)
1181 memset(d
, 0, sizeof(d
));
1188 return x25_exec(card
, X25_DISCONNECT_REQUEST
, link
, d
, 7, NULL
, 0);
1191 /* Send X.25 data packet. */
1192 static int x25_send (cycx_t
*card
, u8 link
, u8 lcn
, u8 bitm
, int len
, void *buf
)
1194 u8 d
[] = "?\xFF\x10??";
1199 return x25_exec(card
, X25_DATA_REQUEST
, link
, &d
, 5, buf
, len
);
1203 /* Find network device by its channel number. */
1204 static struct net_device
*get_dev_by_lcn (wan_device_t
*wandev
, s16 lcn
)
1206 struct net_device
*dev
= wandev
->dev
;
1208 for (; dev
; dev
= dev
->slave
)
1209 if (((x25_channel_t
*)dev
->priv
)->lcn
== lcn
)
1214 /* Find network device by its remote dte address. */
1215 static struct net_device
*get_dev_by_dte_addr (wan_device_t
*wandev
, char *dte
)
1217 struct net_device
*dev
= wandev
->dev
;
1219 for (; dev
; dev
= dev
->slave
)
1220 if (!strcmp (((x25_channel_t
*)dev
->priv
)->addr
, dte
))
1225 /* Initiate connection on the logical channel.
1226 * o for PVC we just get channel configuration
1227 * o for SVCs place an X.25 call
1229 * Return: 0 connected
1230 * >0 connection in progress
1232 static int chan_connect (struct net_device
*dev
)
1234 x25_channel_t
*chan
= dev
->priv
;
1235 cycx_t
*card
= chan
->card
;
1239 return -EINVAL
; /* no destination address */
1240 dprintk(KERN_INFO
"%s: placing X.25 call to %s...\n",
1241 card
->devname
, chan
->addr
);
1242 if (x25_place_call(card
, chan
))
1244 set_chan_state(dev
, WAN_CONNECTING
);
1247 set_chan_state(dev
, WAN_CONNECTED
);
1252 /* Disconnect logical channel.
1253 * o if SVC then clear X.25 call */
1254 static void chan_disc (struct net_device
*dev
)
1256 x25_channel_t
*chan
= dev
->priv
;
1259 x25_clear_call(chan
->card
, chan
->link
, chan
->lcn
, 0, 0);
1260 set_chan_state(dev
, WAN_DISCONNECTING
);
1262 set_chan_state(dev
, WAN_DISCONNECTED
);
1265 /* Called by kernel timer */
1266 static void chan_timer (unsigned long d
)
1268 struct net_device
*dev
= (struct net_device
*) d
;
1269 x25_channel_t
*chan
= dev
->priv
;
1271 switch (chan
->state
) {
1276 printk (KERN_ERR
"%s: chan_timer for svc (%s) not "
1278 chan
->card
->devname
, dev
->name
);
1282 /* Set logical channel state. */
1283 static void set_chan_state (struct net_device
*dev
, u8 state
)
1285 x25_channel_t
*chan
= dev
->priv
;
1286 cycx_t
*card
= chan
->card
;
1289 spin_lock_irqsave(&card
->lock
, flags
);
1291 if (chan
->state
!= state
) {
1292 if (chan
->svc
&& chan
->state
== WAN_CONNECTED
)
1293 del_timer(&chan
->timer
);
1297 printk (KERN_INFO
"%s: interface %s "
1299 card
->devname
, dev
->name
);
1300 *(u16
*)dev
->dev_addr
= htons(chan
->lcn
);
1305 case WAN_CONNECTING
:
1306 printk (KERN_INFO
"%s: interface %s "
1308 card
->devname
, dev
->name
);
1311 case WAN_DISCONNECTING
:
1312 printk (KERN_INFO
"%s: interface %s "
1313 "disconnecting...\n",
1314 card
->devname
, dev
->name
);
1317 case WAN_DISCONNECTED
:
1318 printk (KERN_INFO
"%s: interface %s "
1320 card
->devname
, dev
->name
);
1322 *(unsigned short*)dev
->dev_addr
= 0;
1329 chan
->state
= state
;
1332 spin_unlock_irqrestore(&card
->lock
, flags
);
1335 /* Send packet on a logical channel.
1336 * When this function is called, tx_skb field of the channel data space
1337 * points to the transmit socket buffer. When transmission is complete,
1338 * release socket buffer and reset 'tbusy' flag.
1340 * Return: 0 - transmission complete
1344 * 1. If packet length is greater than MTU for this channel, we'll fragment
1345 * the packet into 'complete sequence' using M-bit.
1346 * 2. When transmission is complete, an event notification should be issued
1348 static int chan_send (struct net_device
*dev
, struct sk_buff
*skb
)
1350 x25_channel_t
*chan
= dev
->priv
;
1351 cycx_t
*card
= chan
->card
;
1352 int bitm
= 0; /* final packet */
1353 unsigned len
= skb
->len
;
1355 if (skb
->len
> card
->wandev
.mtu
) {
1356 len
= card
->wandev
.mtu
;
1357 bitm
= 0x10; /* set M-bit (more data) */
1360 if (x25_send(card
, chan
->link
, chan
->lcn
, bitm
, len
, skb
->data
))
1368 ++chan
->ifstats
.tx_packets
;
1369 chan
->ifstats
.tx_bytes
+= len
;
1373 /* Convert line speed in bps to a number used by cyclom 2x code. */
1374 static u8
bps_to_speed_code (u32 bps
)
1376 u8 number
= 0; /* defaults to the lowest (1200) speed ;> */
1378 if (bps
>= 512000) number
= 8;
1379 else if (bps
>= 256000) number
= 7;
1380 else if (bps
>= 64000) number
= 6;
1381 else if (bps
>= 38400) number
= 5;
1382 else if (bps
>= 19200) number
= 4;
1383 else if (bps
>= 9600) number
= 3;
1384 else if (bps
>= 4800) number
= 2;
1385 else if (bps
>= 2400) number
= 1;
1391 static u8
log2 (u32 n
)
1406 /* Convert decimal string to unsigned integer.
1407 * If len != 0 then only 'len' characters of the string are converted. */
1408 static unsigned dec_to_uint (u8
*str
, int len
)
1415 for (; len
&& is_digit(*str
); ++str
, --len
)
1416 val
= (val
* 10) + (*str
- (unsigned)'0');
1421 static void reset_timer(struct net_device
*dev
)
1423 x25_channel_t
*chan
= dev
->priv
;
1428 del_timer(&chan
->timer
);
1429 chan
->timer
.expires
= jiffies
+ chan
->idle_tmout
* HZ
;
1430 add_timer(&chan
->timer
);
1432 #ifdef CYCLOMX_X25_DEBUG
1433 static void x25_dump_config(TX25Config
*conf
)
1435 printk (KERN_INFO
"x25 configuration\n");
1436 printk (KERN_INFO
"-----------------\n");
1437 printk (KERN_INFO
"link number=%d\n", conf
->link
);
1438 printk (KERN_INFO
"line speed=%d\n", conf
->speed
);
1439 printk (KERN_INFO
"clock=%sternal\n", conf
->clock
== 8 ? "Ex" : "In");
1440 printk (KERN_INFO
"# level 2 retransm.=%d\n", conf
->n2
);
1441 printk (KERN_INFO
"level 2 window=%d\n", conf
->n2win
);
1442 printk (KERN_INFO
"level 3 window=%d\n", conf
->n3win
);
1443 printk (KERN_INFO
"# logical channels=%d\n", conf
->nvc
);
1444 printk (KERN_INFO
"level 3 pkt len=%d\n", conf
->pktlen
);
1445 printk (KERN_INFO
"my address=%d\n", conf
->locaddr
);
1446 printk (KERN_INFO
"remote address=%d\n", conf
->remaddr
);
1447 printk (KERN_INFO
"t1=%d seconds\n", conf
->t1
);
1448 printk (KERN_INFO
"t2=%d seconds\n", conf
->t2
);
1449 printk (KERN_INFO
"t21=%d seconds\n", conf
->t21
);
1450 printk (KERN_INFO
"# PVCs=%d\n", conf
->npvc
);
1451 printk (KERN_INFO
"t23=%d seconds\n", conf
->t23
);
1452 printk (KERN_INFO
"flags=0x%x\n", conf
->flags
);
1455 static void x25_dump_stats(TX25Stats
*stats
)
1457 printk (KERN_INFO
"x25 statistics\n");
1458 printk (KERN_INFO
"--------------\n");
1459 printk (KERN_INFO
"rx_crc_errors=%d\n", stats
->rx_crc_errors
);
1460 printk (KERN_INFO
"rx_over_errors=%d\n", stats
->rx_over_errors
);
1461 printk (KERN_INFO
"n2_tx_frames=%d\n", stats
->n2_tx_frames
);
1462 printk (KERN_INFO
"n2_rx_frames=%d\n", stats
->n2_rx_frames
);
1463 printk (KERN_INFO
"tx_timeouts=%d\n", stats
->tx_timeouts
);
1464 printk (KERN_INFO
"rx_timeouts=%d\n", stats
->rx_timeouts
);
1465 printk (KERN_INFO
"n3_tx_packets=%d\n", stats
->n3_tx_packets
);
1466 printk (KERN_INFO
"n3_rx_packets=%d\n", stats
->n3_rx_packets
);
1467 printk (KERN_INFO
"tx_aborts=%d\n", stats
->tx_aborts
);
1468 printk (KERN_INFO
"rx_aborts=%d\n", stats
->rx_aborts
);
1471 static void x25_dump_devs(wan_device_t
*wandev
)
1473 struct net_device
*dev
= wandev
->dev
;
1475 printk (KERN_INFO
"x25 dev states\n");
1476 printk (KERN_INFO
"name: addr: tbusy:\n");
1477 printk (KERN_INFO
"----------------------------\n");
1479 for (; dev
; dev
= dev
->slave
) {
1480 x25_channel_t
*chan
= dev
->priv
;
1482 printk (KERN_INFO
"%-5.5s %-15.15s %ld\n",
1483 chan
->name
, chan
->addr
, dev
->tbusy
);
1487 #endif /* CYCLOMX_X25_DEBUG */