blob: cf9e15fd8d9106ad31ae2bb303459ac5883b4d79 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2* cycx_x25.c Cyclom 2X WAN Link Driver. X.25 module.
3*
4* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5*
6* Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo
7*
8* Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
9*
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.
14* ============================================================================
15* 2001/01/12 acme use dev_kfree_skb_irq on interrupt context
16* 2000/04/02 acme dprintk, cycx_debug
17* fixed the bug introduced in get_dev_by_lcn and
18* get_dev_by_dte_addr by the anonymous hacker
19* that converted this driver to softnet
20* 2000/01/08 acme cleanup
21* 1999/10/27 acme use ARPHRD_HWX25 so that the X.25 stack know
22* that we have a X.25 stack implemented in
23* firmware onboard
24* 1999/10/18 acme support for X.25 sockets in if_send,
25* beware: socket(AF_X25...) IS WORK IN PROGRESS,
26* TCP/IP over X.25 via wanrouter not affected,
27* working.
28* 1999/10/09 acme chan_disc renamed to chan_disconnect,
29* began adding support for X.25 sockets:
30* conf->protocol in new_if
31* 1999/10/05 acme fixed return E... to return -E...
32* 1999/08/10 acme serialized access to the card thru a spinlock
33* in x25_exec
34* 1999/08/09 acme removed per channel spinlocks
35* removed references to enable_tx_int
36* 1999/05/28 acme fixed nibble_to_byte, ackvc now properly treated
37* if_send simplified
38* 1999/05/25 acme fixed t1, t2, t21 & t23 configuration
39* use spinlocks instead of cli/sti in some points
40* 1999/05/24 acme finished the x25_get_stat function
41* 1999/05/23 acme dev->type = ARPHRD_X25 (tcpdump only works,
42* AFAIT, with ARPHRD_ETHER). This seems to be
43* needed to use socket(AF_X25)...
44* Now the config file must specify a peer media
45* address for svc channels over a crossover cable.
46* Removed hold_timeout from x25_channel_t,
47* not used.
48* A little enhancement in the DEBUG processing
49* 1999/05/22 acme go to DISCONNECTED in disconnect_confirm_intr,
50* instead of chan_disc.
51* 1999/05/16 marcelo fixed timer initialization in SVCs
52* 1999/01/05 acme x25_configure now get (most of) all
53* parameters...
54* 1999/01/05 acme pktlen now (correctly) uses log2 (value
55* configured)
56* 1999/01/03 acme judicious use of data types (u8, u16, u32, etc)
57* 1999/01/03 acme cyx_isr: reset dpmbase to acknowledge
58* indication (interrupt from cyclom 2x)
59* 1999/01/02 acme cyx_isr: first hackings...
60* 1999/01/0203 acme when initializing an array don't give less
61* elements than declared...
62* example: char send_cmd[6] = "?\xFF\x10";
63* you'll gonna lose a couple hours, 'cause your
64* brain won't admit that there's an error in the
65* above declaration... the side effect is that
66* memset is put into the unresolved symbols
67* instead of using the inline memset functions...
68* 1999/01/02 acme began chan_connect, chan_send, x25_send
69* 1998/12/31 acme x25_configure
70* this code can be compiled as non module
71* 1998/12/27 acme code cleanup
72* IPX code wiped out! let's decrease code
73* complexity for now, remember: I'm learning! :)
74* bps_to_speed_code OK
75* 1998/12/26 acme Minimal debug code cleanup
76* 1998/08/08 acme Initial version.
77*/
78
79#define CYCLOMX_X25_DEBUG 1
80
Tobias Klauser8e18d1f2005-09-10 14:45:00 -070081#include <linux/ctype.h> /* isdigit() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070082#include <linux/errno.h> /* return codes */
83#include <linux/if_arp.h> /* ARPHRD_HWX25 */
84#include <linux/kernel.h> /* printk(), and other useful stuff */
85#include <linux/module.h>
86#include <linux/string.h> /* inline memset(), etc. */
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040087#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/slab.h> /* kmalloc(), kfree() */
89#include <linux/stddef.h> /* offsetof(), etc. */
90#include <linux/wanrouter.h> /* WAN router definitions */
91
92#include <asm/byteorder.h> /* htons(), etc. */
93
94#include <linux/cyclomx.h> /* Cyclom 2X common user API definitions */
95#include <linux/cycx_x25.h> /* X.25 firmware API definitions */
96
97#include <net/x25device.h>
98
99/* Defines & Macros */
100#define CYCX_X25_MAX_CMD_RETRY 5
101#define CYCX_X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */
102
103/* Data Structures */
104/* This is an extension of the 'struct net_device' we create for each network
105 interface to keep the rest of X.25 channel-specific data. */
106struct cycx_x25_channel {
107 /* This member must be first. */
108 struct net_device *slave; /* WAN slave */
109
110 char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
111 char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
112 char *local_addr; /* local media address, ASCIIZ -
113 svc thru crossover cable */
114 s16 lcn; /* logical channel number/conn.req.key*/
115 u8 link;
116 struct timer_list timer; /* timer used for svc channel disc. */
117 u16 protocol; /* ethertype, 0 - multiplexed */
118 u8 svc; /* 0 - permanent, 1 - switched */
119 u8 state; /* channel state */
120 u8 drop_sequence; /* mark sequence for dropping */
121 u32 idle_tmout; /* sec, before disconnecting */
122 struct sk_buff *rx_skb; /* receive socket buffer */
123 struct cycx_device *card; /* -> owner */
124 struct net_device_stats ifstats;/* interface statistics */
125};
126
127/* Function Prototypes */
128/* WAN link driver entry points. These are called by the WAN router module. */
129static int cycx_wan_update(struct wan_device *wandev),
130 cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
131 wanif_conf_t *conf),
132 cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
133
134/* Network device interface */
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700135static int cycx_netdevice_init(struct net_device *dev);
136static int cycx_netdevice_open(struct net_device *dev);
137static int cycx_netdevice_stop(struct net_device *dev);
138static int cycx_netdevice_hard_header(struct sk_buff *skb,
139 struct net_device *dev, u16 type,
140 const void *daddr, const void *saddr,
141 unsigned len);
142static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
Stephen Hemmingerd71a6742009-08-31 19:50:47 +0000143static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
144 struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146static struct net_device_stats *
147 cycx_netdevice_get_stats(struct net_device *dev);
148
149/* Interrupt handlers */
150static void cycx_x25_irq_handler(struct cycx_device *card),
151 cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
152 cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
153 cycx_x25_irq_log(struct cycx_device *card,
154 struct cycx_x25_cmd *cmd),
155 cycx_x25_irq_stat(struct cycx_device *card,
156 struct cycx_x25_cmd *cmd),
157 cycx_x25_irq_connect_confirm(struct cycx_device *card,
158 struct cycx_x25_cmd *cmd),
159 cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
160 struct cycx_x25_cmd *cmd),
161 cycx_x25_irq_connect(struct cycx_device *card,
162 struct cycx_x25_cmd *cmd),
163 cycx_x25_irq_disconnect(struct cycx_device *card,
164 struct cycx_x25_cmd *cmd),
165 cycx_x25_irq_spurious(struct cycx_device *card,
166 struct cycx_x25_cmd *cmd);
167
168/* X.25 firmware interface functions */
169static int cycx_x25_configure(struct cycx_device *card,
170 struct cycx_x25_config *conf),
171 cycx_x25_get_stats(struct cycx_device *card),
172 cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
173 int len, void *buf),
174 cycx_x25_connect_response(struct cycx_device *card,
175 struct cycx_x25_channel *chan),
176 cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
177 u8 lcn);
178
179/* channel functions */
180static int cycx_x25_chan_connect(struct net_device *dev),
181 cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb);
182
183static void cycx_x25_chan_disconnect(struct net_device *dev),
184 cycx_x25_chan_send_event(struct net_device *dev, u8 event);
185
186/* Miscellaneous functions */
187static void cycx_x25_set_chan_state(struct net_device *dev, u8 state),
188 cycx_x25_chan_timer(unsigned long d);
189
190static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble),
191 reset_timer(struct net_device *dev);
192
193static u8 bps_to_speed_code(u32 bps);
194static u8 cycx_log2(u32 n);
195
196static unsigned dec_to_uint(u8 *str, int len);
197
198static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
199 s16 lcn);
200static struct net_device *
201 cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte);
202
Wang Chen7be60652008-11-20 04:26:21 -0800203static void cycx_x25_chan_setup(struct net_device *dev);
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205#ifdef CYCLOMX_X25_DEBUG
206static void hex_dump(char *msg, unsigned char *p, int len);
207static void cycx_x25_dump_config(struct cycx_x25_config *conf);
208static void cycx_x25_dump_stats(struct cycx_x25_stats *stats);
209static void cycx_x25_dump_devs(struct wan_device *wandev);
210#else
211#define hex_dump(msg, p, len)
212#define cycx_x25_dump_config(conf)
213#define cycx_x25_dump_stats(stats)
214#define cycx_x25_dump_devs(wandev)
215#endif
216/* Public Functions */
217
218/* X.25 Protocol Initialization routine.
219 *
220 * This routine is called by the main Cyclom 2X module during setup. At this
221 * point adapter is completely initialized and X.25 firmware is running.
222 * o configure adapter
223 * o initialize protocol-specific fields of the adapter data space.
224 *
225 * Return: 0 o.k.
226 * < 0 failure. */
227int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf)
228{
229 struct cycx_x25_config cfg;
230
231 /* Verify configuration ID */
232 if (conf->config_id != WANCONFIG_X25) {
233 printk(KERN_INFO "%s: invalid configuration ID %u!\n",
234 card->devname, conf->config_id);
235 return -EINVAL;
236 }
237
238 /* Initialize protocol-specific fields */
239 card->mbox = card->hw.dpmbase + X25_MBOX_OFFS;
240 card->u.x.connection_keys = 0;
241 spin_lock_init(&card->u.x.lock);
242
243 /* Configure adapter. Here we set reasonable defaults, then parse
244 * device configuration structure and set configuration options.
245 * Most configuration options are verified and corrected (if
246 * necessary) since we can't rely on the adapter to do so and don't
247 * want it to fail either. */
248 memset(&cfg, 0, sizeof(cfg));
249 cfg.link = 0;
250 cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55;
251 cfg.speed = bps_to_speed_code(conf->bps);
252 cfg.n3win = 7;
253 cfg.n2win = 2;
254 cfg.n2 = 5;
255 cfg.nvc = 1;
256 cfg.npvc = 1;
257 cfg.flags = 0x02; /* default = V35 */
258 cfg.t1 = 10; /* line carrier timeout */
259 cfg.t2 = 29; /* tx timeout */
260 cfg.t21 = 180; /* CALL timeout */
261 cfg.t23 = 180; /* CLEAR timeout */
262
263 /* adjust MTU */
264 if (!conf->mtu || conf->mtu >= 512)
265 card->wandev.mtu = 512;
266 else if (conf->mtu >= 256)
267 card->wandev.mtu = 256;
268 else if (conf->mtu >= 128)
269 card->wandev.mtu = 128;
270 else
271 card->wandev.mtu = 64;
272
273 cfg.pktlen = cycx_log2(card->wandev.mtu);
274
275 if (conf->station == WANOPT_DTE) {
276 cfg.locaddr = 3; /* DTE */
277 cfg.remaddr = 1; /* DCE */
278 } else {
279 cfg.locaddr = 1; /* DCE */
280 cfg.remaddr = 3; /* DTE */
281 }
282
283 if (conf->interface == WANOPT_RS232)
284 cfg.flags = 0; /* FIXME just reset the 2nd bit */
285
286 if (conf->u.x25.hi_pvc) {
287 card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, 4095);
288 card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc);
289 }
290
291 if (conf->u.x25.hi_svc) {
292 card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, 4095);
293 card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc);
294 }
295
296 if (card->u.x.lo_pvc == 255)
297 cfg.npvc = 0;
298 else
299 cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1;
300
301 cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc;
302
303 if (conf->u.x25.hdlc_window)
304 cfg.n2win = min_t(unsigned int, conf->u.x25.hdlc_window, 7);
305
306 if (conf->u.x25.pkt_window)
307 cfg.n3win = min_t(unsigned int, conf->u.x25.pkt_window, 7);
308
309 if (conf->u.x25.t1)
310 cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30);
311
312 if (conf->u.x25.t2)
313 cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 30);
314
315 if (conf->u.x25.t11_t21)
316 cfg.t21 = min_t(unsigned int, conf->u.x25.t11_t21, 30);
317
318 if (conf->u.x25.t13_t23)
319 cfg.t23 = min_t(unsigned int, conf->u.x25.t13_t23, 30);
320
321 if (conf->u.x25.n2)
322 cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30);
323
324 /* initialize adapter */
325 if (cycx_x25_configure(card, &cfg))
326 return -EIO;
327
328 /* Initialize protocol-specific fields of adapter data space */
329 card->wandev.bps = conf->bps;
330 card->wandev.interface = conf->interface;
331 card->wandev.clocking = conf->clocking;
332 card->wandev.station = conf->station;
333 card->isr = cycx_x25_irq_handler;
334 card->exec = NULL;
335 card->wandev.update = cycx_wan_update;
336 card->wandev.new_if = cycx_wan_new_if;
337 card->wandev.del_if = cycx_wan_del_if;
338 card->wandev.state = WAN_DISCONNECTED;
339
340 return 0;
341}
342
343/* WAN Device Driver Entry Points */
344/* Update device status & statistics. */
345static int cycx_wan_update(struct wan_device *wandev)
346{
347 /* sanity checks */
348 if (!wandev || !wandev->private)
349 return -EFAULT;
350
351 if (wandev->state == WAN_UNCONFIGURED)
352 return -ENODEV;
353
354 cycx_x25_get_stats(wandev->private);
355
356 return 0;
357}
358
359/* Create new logical channel.
360 * This routine is called by the router when ROUTER_IFNEW IOCTL is being
361 * handled.
362 * o parse media- and hardware-specific configuration
363 * o make sure that a new channel can be created
364 * o allocate resources, if necessary
365 * o prepare network device structure for registration.
366 *
367 * Return: 0 o.k.
368 * < 0 failure (channel will not be created) */
369static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
370 wanif_conf_t *conf)
371{
372 struct cycx_device *card = wandev->private;
373 struct cycx_x25_channel *chan;
374 int err = 0;
375
376 if (!conf->name[0] || strlen(conf->name) > WAN_IFNAME_SZ) {
377 printk(KERN_INFO "%s: invalid interface name!\n",
378 card->devname);
379 return -EINVAL;
380 }
381
Wang Chen7be60652008-11-20 04:26:21 -0800382 dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name,
383 cycx_x25_chan_setup);
384 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return -ENOMEM;
386
Wang Chen7be60652008-11-20 04:26:21 -0800387 chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 strcpy(chan->name, conf->name);
389 chan->card = card;
390 chan->link = conf->port;
391 chan->protocol = conf->protocol ? ETH_P_X25 : ETH_P_IP;
392 chan->rx_skb = NULL;
393 /* only used in svc connected thru crossover cable */
394 chan->local_addr = NULL;
395
396 if (conf->addr[0] == '@') { /* SVC */
397 int len = strlen(conf->local_addr);
398
399 if (len) {
400 if (len > WAN_ADDRESS_SZ) {
401 printk(KERN_ERR "%s: %s local addr too long!\n",
402 wandev->name, chan->name);
Wang Chen7be60652008-11-20 04:26:21 -0800403 err = -EINVAL;
404 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 } else {
406 chan->local_addr = kmalloc(len + 1, GFP_KERNEL);
407
408 if (!chan->local_addr) {
Wang Chen7be60652008-11-20 04:26:21 -0800409 err = -ENOMEM;
410 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 }
412 }
413
414 strncpy(chan->local_addr, conf->local_addr,
415 WAN_ADDRESS_SZ);
416 }
417
418 chan->svc = 1;
419 strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
420 init_timer(&chan->timer);
421 chan->timer.function = cycx_x25_chan_timer;
422 chan->timer.data = (unsigned long)dev;
423
424 /* Set channel timeouts (default if not specified) */
425 chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
Tobias Klauser8e18d1f2005-09-10 14:45:00 -0700426 } else if (isdigit(conf->addr[0])) { /* PVC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 s16 lcn = dec_to_uint(conf->addr, 0);
428
429 if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
430 chan->lcn = lcn;
431 else {
432 printk(KERN_ERR
433 "%s: PVC %u is out of range on interface %s!\n",
434 wandev->name, lcn, chan->name);
435 err = -EINVAL;
Wang Chen7be60652008-11-20 04:26:21 -0800436 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
438 } else {
439 printk(KERN_ERR "%s: invalid media address on interface %s!\n",
440 wandev->name, chan->name);
441 err = -EINVAL;
Wang Chen7be60652008-11-20 04:26:21 -0800442 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 }
444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return 0;
Wang Chen7be60652008-11-20 04:26:21 -0800446
447error:
448 free_netdev(dev);
449 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
452/* Delete logical channel. */
453static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
454{
Wang Chen7be60652008-11-20 04:26:21 -0800455 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Wang Chen7be60652008-11-20 04:26:21 -0800457 if (chan->svc) {
458 kfree(chan->local_addr);
459 if (chan->state == WAN_CONNECTED)
460 del_timer(&chan->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462
463 return 0;
464}
465
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467/* Network Device Interface */
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700468
469static const struct header_ops cycx_header_ops = {
470 .create = cycx_netdevice_hard_header,
471 .rebuild = cycx_netdevice_rebuild_header,
472};
473
Stephen Hemmingerd9b06c42009-03-20 19:36:16 +0000474static const struct net_device_ops cycx_netdev_ops = {
475 .ndo_init = cycx_netdevice_init,
476 .ndo_open = cycx_netdevice_open,
477 .ndo_stop = cycx_netdevice_stop,
478 .ndo_start_xmit = cycx_netdevice_hard_start_xmit,
479 .ndo_get_stats = cycx_netdevice_get_stats,
480};
481
482static void cycx_x25_chan_setup(struct net_device *dev)
483{
484 /* Initialize device driver entry points */
485 dev->netdev_ops = &cycx_netdev_ops;
486 dev->header_ops = &cycx_header_ops;
487
488 /* Initialize media-specific parameters */
489 dev->mtu = CYCX_X25_CHAN_MTU;
490 dev->type = ARPHRD_HWX25; /* ARP h/w type */
491 dev->hard_header_len = 0; /* media header length */
492 dev->addr_len = 0; /* hardware address length */
493}
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495/* Initialize Linux network interface.
496 *
497 * This routine is called only once for each interface, during Linux network
498 * interface registration. Returning anything but zero will fail interface
499 * registration. */
500static int cycx_netdevice_init(struct net_device *dev)
501{
Wang Chen7be60652008-11-20 04:26:21 -0800502 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 struct cycx_device *card = chan->card;
504 struct wan_device *wandev = &card->wandev;
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (!chan->svc)
Al Viro7fd71e52007-12-22 17:27:24 +0000507 *(__be16*)dev->dev_addr = htons(chan->lcn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 /* Initialize hardware parameters (just for reference) */
510 dev->irq = wandev->irq;
511 dev->dma = wandev->dma;
512 dev->base_addr = wandev->ioport;
513 dev->mem_start = (unsigned long)wandev->maddr;
514 dev->mem_end = (unsigned long)(wandev->maddr +
515 wandev->msize - 1);
516 dev->flags |= IFF_NOARP;
517
518 /* Set transmit buffer queue length */
519 dev->tx_queue_len = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 /* Initialize socket buffers */
522 cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
523
524 return 0;
525}
526
527/* Open network interface.
528 * o prevent module from unloading by incrementing use count
529 * o if link is disconnected then initiate connection
530 *
531 * Return 0 if O.k. or errno. */
532static int cycx_netdevice_open(struct net_device *dev)
533{
534 if (netif_running(dev))
535 return -EBUSY; /* only one open is allowed */
536
537 netif_start_queue(dev);
538 return 0;
539}
540
541/* Close network interface.
542 * o reset flags.
543 * o if there's no more open channels then disconnect physical link. */
544static int cycx_netdevice_stop(struct net_device *dev)
545{
Wang Chen7be60652008-11-20 04:26:21 -0800546 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 netif_stop_queue(dev);
549
550 if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
551 cycx_x25_chan_disconnect(dev);
552
553 return 0;
554}
555
556/* Build media header.
557 * o encapsulate packet according to encapsulation type.
558 *
559 * The trick here is to put packet type (Ethertype) into 'protocol' field of
560 * the socket buffer, so that we don't forget it. If encapsulation fails,
561 * set skb->protocol to 0 and discard packet later.
562 *
563 * Return: media header length. */
564static int cycx_netdevice_hard_header(struct sk_buff *skb,
565 struct net_device *dev, u16 type,
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700566 const void *daddr, const void *saddr,
567 unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Al Viro7fd71e52007-12-22 17:27:24 +0000569 skb->protocol = htons(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 return dev->hard_header_len;
572}
573
574/* * Re-build media header.
575 * Return: 1 physical address resolved.
576 * 0 physical address not resolved */
577static int cycx_netdevice_rebuild_header(struct sk_buff *skb)
578{
579 return 1;
580}
581
582/* Send a packet on a network interface.
583 * o set busy flag (marks start of the transmission).
584 * o check link state. If link is not up, then drop the packet.
585 * o check channel status. If it's down then initiate a call.
586 * o pass a packet to corresponding WAN device.
587 * o free socket buffer
588 *
589 * Return: 0 complete (socket buffer must be freed)
590 * non-0 packet may be re-transmitted (tbusy must be set)
591 *
592 * Notes:
593 * 1. This routine is called either by the protocol stack or by the "net
594 * bottom half" (with interrupts enabled).
595 * 2. Setting tbusy flag will inhibit further transmit requests from the
596 * protocol stack and can be used for flow control with protocol layer. */
Stephen Hemmingerd71a6742009-08-31 19:50:47 +0000597static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
598 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
Wang Chen7be60652008-11-20 04:26:21 -0800600 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 struct cycx_device *card = chan->card;
602
603 if (!chan->svc)
Al Viro7fd71e52007-12-22 17:27:24 +0000604 chan->protocol = ntohs(skb->protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
606 if (card->wandev.state != WAN_CONNECTED)
607 ++chan->ifstats.tx_dropped;
608 else if (chan->svc && chan->protocol &&
Al Viro7fd71e52007-12-22 17:27:24 +0000609 chan->protocol != ntohs(skb->protocol)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 printk(KERN_INFO
611 "%s: unsupported Ethertype 0x%04X on interface %s!\n",
Al Viro7fd71e52007-12-22 17:27:24 +0000612 card->devname, ntohs(skb->protocol), dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 ++chan->ifstats.tx_errors;
614 } else if (chan->protocol == ETH_P_IP) {
615 switch (chan->state) {
616 case WAN_DISCONNECTED:
617 if (cycx_x25_chan_connect(dev)) {
618 netif_stop_queue(dev);
Patrick McHardy47f88c92009-06-12 04:37:34 +0000619 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 }
621 /* fall thru */
622 case WAN_CONNECTED:
623 reset_timer(dev);
624 dev->trans_start = jiffies;
625 netif_stop_queue(dev);
626
627 if (cycx_x25_chan_send(dev, skb))
Patrick McHardy47f88c92009-06-12 04:37:34 +0000628 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 break;
631 default:
632 ++chan->ifstats.tx_dropped;
633 ++card->wandev.stats.tx_dropped;
634 }
635 } else { /* chan->protocol == ETH_P_X25 */
636 switch (skb->data[0]) {
andrew hendry5d747312010-04-19 13:30:13 +0000637 case X25_IFACE_DATA:
638 break;
639 case X25_IFACE_CONNECT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 cycx_x25_chan_connect(dev);
641 goto free_packet;
andrew hendry5d747312010-04-19 13:30:13 +0000642 case X25_IFACE_DISCONNECT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 cycx_x25_chan_disconnect(dev);
644 goto free_packet;
645 default:
646 printk(KERN_INFO
647 "%s: unknown %d x25-iface request on %s!\n",
648 card->devname, skb->data[0], dev->name);
649 ++chan->ifstats.tx_errors;
650 goto free_packet;
651 }
652
653 skb_pull(skb, 1); /* Remove control byte */
654 reset_timer(dev);
655 dev->trans_start = jiffies;
656 netif_stop_queue(dev);
657
658 if (cycx_x25_chan_send(dev, skb)) {
659 /* prepare for future retransmissions */
660 skb_push(skb, 1);
Patrick McHardy47f88c92009-06-12 04:37:34 +0000661 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
663 }
664
665free_packet:
666 dev_kfree_skb(skb);
667
Patrick McHardy6ed10652009-06-23 06:03:08 +0000668 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
671/* Get Ethernet-style interface statistics.
672 * Return a pointer to struct net_device_stats */
673static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev)
674{
Wang Chen7be60652008-11-20 04:26:21 -0800675 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677 return chan ? &chan->ifstats : NULL;
678}
679
680/* Interrupt Handlers */
681/* X.25 Interrupt Service Routine. */
682static void cycx_x25_irq_handler(struct cycx_device *card)
683{
684 struct cycx_x25_cmd cmd;
685 u16 z = 0;
686
687 card->in_isr = 1;
688 card->buff_int_mode_unbusy = 0;
689 cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));
690
691 switch (cmd.command) {
692 case X25_DATA_INDICATION:
693 cycx_x25_irq_rx(card, &cmd);
694 break;
695 case X25_ACK_FROM_VC:
696 cycx_x25_irq_tx(card, &cmd);
697 break;
698 case X25_LOG:
699 cycx_x25_irq_log(card, &cmd);
700 break;
701 case X25_STATISTIC:
702 cycx_x25_irq_stat(card, &cmd);
703 break;
704 case X25_CONNECT_CONFIRM:
705 cycx_x25_irq_connect_confirm(card, &cmd);
706 break;
707 case X25_CONNECT_INDICATION:
708 cycx_x25_irq_connect(card, &cmd);
709 break;
710 case X25_DISCONNECT_INDICATION:
711 cycx_x25_irq_disconnect(card, &cmd);
712 break;
713 case X25_DISCONNECT_CONFIRM:
714 cycx_x25_irq_disconnect_confirm(card, &cmd);
715 break;
716 case X25_LINE_ON:
717 cycx_set_state(card, WAN_CONNECTED);
718 break;
719 case X25_LINE_OFF:
720 cycx_set_state(card, WAN_DISCONNECTED);
721 break;
722 default:
723 cycx_x25_irq_spurious(card, &cmd);
724 break;
725 }
726
727 cycx_poke(&card->hw, 0, &z, sizeof(z));
728 cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
729 card->in_isr = 0;
730}
731
732/* Transmit interrupt handler.
733 * o Release socket buffer
734 * o Clear 'tbusy' flag */
735static void cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
736{
737 struct net_device *dev;
738 struct wan_device *wandev = &card->wandev;
739 u8 lcn;
740
741 cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
742
743 /* unbusy device and then dev_tint(); */
744 dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
745 if (dev) {
746 card->buff_int_mode_unbusy = 1;
747 netif_wake_queue(dev);
748 } else
749 printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n",
750 card->devname, lcn);
751}
752
753/* Receive interrupt handler.
754 * This routine handles fragmented IP packets using M-bit according to the
755 * RFC1356.
756 * o map logical channel number to network interface.
757 * o allocate socket buffer or append received packet to the existing one.
758 * o if M-bit is reset (i.e. it's the last packet in a sequence) then
759 * decapsulate packet and pass socket buffer to the protocol stack.
760 *
761 * Notes:
762 * 1. When allocating a socket buffer, if M-bit is set then more data is
763 * coming and we have to allocate buffer for the maximum IP packet size
764 * expected on this channel.
765 * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
766 * socket buffers available) the whole packet sequence must be discarded. */
767static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
768{
769 struct wan_device *wandev = &card->wandev;
770 struct net_device *dev;
771 struct cycx_x25_channel *chan;
772 struct sk_buff *skb;
773 u8 bitm, lcn;
774 int pktlen = cmd->len - 5;
775
776 cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
777 cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));
778 bitm &= 0x10;
779
780 dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
781 if (!dev) {
782 /* Invalid channel, discard packet */
783 printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
784 card->devname, lcn);
785 return;
786 }
787
Wang Chen7be60652008-11-20 04:26:21 -0800788 chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 reset_timer(dev);
790
791 if (chan->drop_sequence) {
792 if (!bitm)
793 chan->drop_sequence = 0;
794 else
795 return;
796 }
797
798 if ((skb = chan->rx_skb) == NULL) {
799 /* Allocate new socket buffer */
800 int bufsize = bitm ? dev->mtu : pktlen;
801
802 if ((skb = dev_alloc_skb((chan->protocol == ETH_P_X25 ? 1 : 0) +
803 bufsize +
804 dev->hard_header_len)) == NULL) {
805 printk(KERN_INFO "%s: no socket buffers available!\n",
806 card->devname);
807 chan->drop_sequence = 1;
808 ++chan->ifstats.rx_dropped;
809 return;
810 }
811
812 if (chan->protocol == ETH_P_X25) /* X.25 socket layer control */
813 /* 0 = data packet (dev_alloc_skb zeroed skb->data) */
814 skb_put(skb, 1);
815
816 skb->dev = dev;
817 skb->protocol = htons(chan->protocol);
818 chan->rx_skb = skb;
819 }
820
821 if (skb_tailroom(skb) < pktlen) {
822 /* No room for the packet. Call off the whole thing! */
823 dev_kfree_skb_irq(skb);
824 chan->rx_skb = NULL;
825
826 if (bitm)
827 chan->drop_sequence = 1;
828
829 printk(KERN_INFO "%s: unexpectedly long packet sequence "
830 "on interface %s!\n", card->devname, dev->name);
831 ++chan->ifstats.rx_length_errors;
832 return;
833 }
834
835 /* Append packet to the socket buffer */
836 cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen);
837
838 if (bitm)
839 return; /* more data is coming */
840
841 chan->rx_skb = NULL; /* dequeue packet */
842
843 ++chan->ifstats.rx_packets;
844 chan->ifstats.rx_bytes += pktlen;
845
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -0700846 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 netif_rx(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
850/* Connect interrupt handler. */
851static void cycx_x25_irq_connect(struct cycx_device *card,
852 struct cycx_x25_cmd *cmd)
853{
854 struct wan_device *wandev = &card->wandev;
855 struct net_device *dev = NULL;
856 struct cycx_x25_channel *chan;
857 u8 d[32],
858 loc[24],
859 rem[24];
860 u8 lcn, sizeloc, sizerem;
861
862 cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
863 cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc));
864 cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6);
865
866 sizerem = sizeloc >> 4;
867 sizeloc &= 0x0F;
868
869 loc[0] = rem[0] = '\0';
870
871 if (sizeloc)
872 nibble_to_byte(d, loc, sizeloc, 0);
873
874 if (sizerem)
875 nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
876
877 dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n",
Harvey Harrisonb39d66a2008-08-20 16:52:04 -0700878 __func__, lcn, loc, rem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 dev = cycx_x25_get_dev_by_dte_addr(wandev, rem);
881 if (!dev) {
882 /* Invalid channel, discard packet */
883 printk(KERN_INFO "%s: connect not expected: remote %s!\n",
884 card->devname, rem);
885 return;
886 }
887
Wang Chen7be60652008-11-20 04:26:21 -0800888 chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 chan->lcn = lcn;
890 cycx_x25_connect_response(card, chan);
891 cycx_x25_set_chan_state(dev, WAN_CONNECTED);
892}
893
894/* Connect confirm interrupt handler. */
895static void cycx_x25_irq_connect_confirm(struct cycx_device *card,
896 struct cycx_x25_cmd *cmd)
897{
898 struct wan_device *wandev = &card->wandev;
899 struct net_device *dev;
900 struct cycx_x25_channel *chan;
901 u8 lcn, key;
902
903 cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
904 cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
905 dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n",
Harvey Harrisonb39d66a2008-08-20 16:52:04 -0700906 card->devname, __func__, lcn, key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 dev = cycx_x25_get_dev_by_lcn(wandev, -key);
909 if (!dev) {
910 /* Invalid channel, discard packet */
911 clear_bit(--key, (void*)&card->u.x.connection_keys);
912 printk(KERN_INFO "%s: connect confirm not expected: lcn %d, "
913 "key=%d!\n", card->devname, lcn, key);
914 return;
915 }
916
917 clear_bit(--key, (void*)&card->u.x.connection_keys);
Wang Chen7be60652008-11-20 04:26:21 -0800918 chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 chan->lcn = lcn;
920 cycx_x25_set_chan_state(dev, WAN_CONNECTED);
921}
922
923/* Disconnect confirm interrupt handler. */
924static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
925 struct cycx_x25_cmd *cmd)
926{
927 struct wan_device *wandev = &card->wandev;
928 struct net_device *dev;
929 u8 lcn;
930
931 cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
932 dprintk(1, KERN_INFO "%s: %s:lcn=%d\n",
Harvey Harrisonb39d66a2008-08-20 16:52:04 -0700933 card->devname, __func__, lcn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
935 if (!dev) {
936 /* Invalid channel, discard packet */
937 printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n",
938 card->devname, lcn);
939 return;
940 }
941
942 cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
943}
944
945/* disconnect interrupt handler. */
946static void cycx_x25_irq_disconnect(struct cycx_device *card,
947 struct cycx_x25_cmd *cmd)
948{
949 struct wan_device *wandev = &card->wandev;
950 struct net_device *dev;
951 u8 lcn;
952
953 cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
Harvey Harrisonb39d66a2008-08-20 16:52:04 -0700954 dprintk(1, KERN_INFO "%s:lcn=%d\n", __func__, lcn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
957 if (dev) {
Wang Chen7be60652008-11-20 04:26:21 -0800958 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 cycx_x25_disconnect_response(card, chan->link, lcn);
961 cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
962 } else
963 cycx_x25_disconnect_response(card, 0, lcn);
964}
965
966/* LOG interrupt handler. */
967static void cycx_x25_irq_log(struct cycx_device *card, struct cycx_x25_cmd *cmd)
968{
969#if CYCLOMX_X25_DEBUG
970 char bf[20];
971 u16 size, toread, link, msg_code;
972 u8 code, routine;
973
974 cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
975 cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
976 cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
977 /* at most 20 bytes are available... thanks to Daniela :) */
978 toread = size < 20 ? size : 20;
979 cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
980 cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
981 cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);
982
983 printk(KERN_INFO "cycx_x25_irq_handler: X25_LOG (0x4500) indic.:\n");
984 printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf);
985 printk(KERN_INFO "Log message code=0x%X\n", msg_code);
986 printk(KERN_INFO "Link=%d\n", link);
987 printk(KERN_INFO "log code=0x%X\n", code);
988 printk(KERN_INFO "log routine=0x%X\n", routine);
989 printk(KERN_INFO "Message size=%d\n", size);
990 hex_dump("Message", bf, toread);
991#endif
992}
993
994/* STATISTIC interrupt handler. */
995static void cycx_x25_irq_stat(struct cycx_device *card,
996 struct cycx_x25_cmd *cmd)
997{
998 cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,
999 sizeof(card->u.x.stats));
1000 hex_dump("cycx_x25_irq_stat", (unsigned char*)&card->u.x.stats,
1001 sizeof(card->u.x.stats));
1002 cycx_x25_dump_stats(&card->u.x.stats);
1003 wake_up_interruptible(&card->wait_stats);
1004}
1005
1006/* Spurious interrupt handler.
1007 * o print a warning
1008 * If number of spurious interrupts exceeded some limit, then ??? */
1009static void cycx_x25_irq_spurious(struct cycx_device *card,
1010 struct cycx_x25_cmd *cmd)
1011{
1012 printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n",
1013 card->devname, cmd->command);
1014}
1015#ifdef CYCLOMX_X25_DEBUG
1016static void hex_dump(char *msg, unsigned char *p, int len)
1017{
1018 unsigned char hex[1024],
1019 * phex = hex;
1020
1021 if (len >= (sizeof(hex) / 2))
1022 len = (sizeof(hex) / 2) - 1;
1023
1024 while (len--) {
1025 sprintf(phex, "%02x", *p++);
1026 phex += 2;
1027 }
1028
1029 printk(KERN_INFO "%s: %s\n", msg, hex);
1030}
1031#endif
1032
1033/* Cyclom 2X Firmware-Specific Functions */
1034/* Exec X.25 command. */
1035static int x25_exec(struct cycx_device *card, int command, int link,
1036 void *d1, int len1, void *d2, int len2)
1037{
1038 struct cycx_x25_cmd c;
1039 unsigned long flags;
1040 u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;
1041 u8 retry = CYCX_X25_MAX_CMD_RETRY;
1042 int err = 0;
1043
1044 c.command = command;
1045 c.link = link;
1046 c.len = len1 + len2;
1047
1048 spin_lock_irqsave(&card->u.x.lock, flags);
1049
1050 /* write command */
1051 cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
1052
1053 /* write X.25 data */
1054 if (d1) {
1055 cycx_poke(&card->hw, addr, d1, len1);
1056
1057 if (d2) {
1058 if (len2 > 254) {
1059 u32 addr1 = 0xA00 + 0x400 * link;
1060
1061 cycx_poke(&card->hw, addr + len1, d2, 249);
1062 cycx_poke(&card->hw, addr1, ((u8*)d2) + 249,
1063 len2 - 249);
1064 } else
1065 cycx_poke(&card->hw, addr + len1, d2, len2);
1066 }
1067 }
1068
1069 /* generate interruption, executing command */
1070 cycx_intr(&card->hw);
1071
1072 /* wait till card->mbox == 0 */
1073 do {
1074 err = cycx_exec(card->mbox);
1075 } while (retry-- && err);
1076
1077 spin_unlock_irqrestore(&card->u.x.lock, flags);
1078
1079 return err;
1080}
1081
1082/* Configure adapter. */
1083static int cycx_x25_configure(struct cycx_device *card,
1084 struct cycx_x25_config *conf)
1085{
1086 struct {
1087 u16 nlinks;
1088 struct cycx_x25_config conf[2];
1089 } x25_cmd_conf;
1090
1091 memset(&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
1092 x25_cmd_conf.nlinks = 2;
1093 x25_cmd_conf.conf[0] = *conf;
1094 /* FIXME: we need to find a way in the wanrouter framework
1095 to configure the second link, for now lets use it
1096 with the same config from the first link, fixing
1097 the interface type to RS232, the speed in 38400 and
1098 the clock to external */
1099 x25_cmd_conf.conf[1] = *conf;
1100 x25_cmd_conf.conf[1].link = 1;
1101 x25_cmd_conf.conf[1].speed = 5; /* 38400 */
1102 x25_cmd_conf.conf[1].clock = 8;
1103 x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */
1104
1105 cycx_x25_dump_config(&x25_cmd_conf.conf[0]);
1106 cycx_x25_dump_config(&x25_cmd_conf.conf[1]);
1107
1108 return x25_exec(card, X25_CONFIG, 0,
1109 &x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);
1110}
1111
1112/* Get protocol statistics. */
1113static int cycx_x25_get_stats(struct cycx_device *card)
1114{
1115 /* the firmware expects 20 in the size field!!!
1116 thanks to Daniela */
1117 int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
1118
1119 if (err)
1120 return err;
1121
1122 interruptible_sleep_on(&card->wait_stats);
1123
1124 if (signal_pending(current))
1125 return -EINTR;
1126
1127 card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames;
1128 card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors;
1129 card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors;
1130 card->wandev.stats.rx_length_errors = 0; /* not available from fw */
1131 card->wandev.stats.rx_frame_errors = 0; /* not available from fw */
1132 card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts;
1133 card->wandev.stats.rx_dropped = 0; /* not available from fw */
1134 card->wandev.stats.rx_errors = 0; /* not available from fw */
1135 card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames;
1136 card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts;
1137 card->wandev.stats.tx_dropped = 0; /* not available from fw */
1138 card->wandev.stats.collisions = 0; /* not available from fw */
1139 card->wandev.stats.tx_errors = 0; /* not available from fw */
1140
1141 cycx_x25_dump_devs(&card->wandev);
1142
1143 return 0;
1144}
1145
1146/* return the number of nibbles */
1147static int byte_to_nibble(u8 *s, u8 *d, char *nibble)
1148{
1149 int i = 0;
1150
1151 if (*nibble && *s) {
1152 d[i] |= *s++ - '0';
1153 *nibble = 0;
1154 ++i;
1155 }
1156
1157 while (*s) {
1158 d[i] = (*s - '0') << 4;
1159 if (*(s + 1))
1160 d[i] |= *(s + 1) - '0';
1161 else {
1162 *nibble = 1;
1163 break;
1164 }
1165 ++i;
1166 s += 2;
1167 }
1168
1169 return i;
1170}
1171
1172static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble)
1173{
1174 if (nibble) {
1175 *d++ = '0' + (*s++ & 0x0F);
1176 --len;
1177 }
1178
1179 while (len) {
1180 *d++ = '0' + (*s >> 4);
1181
1182 if (--len) {
1183 *d++ = '0' + (*s & 0x0F);
1184 --len;
1185 } else break;
1186
1187 ++s;
1188 }
1189
1190 *d = '\0';
1191}
1192
1193/* Place X.25 call. */
1194static int x25_place_call(struct cycx_device *card,
1195 struct cycx_x25_channel *chan)
1196{
1197 int err = 0,
1198 len;
1199 char d[64],
1200 nibble = 0,
1201 mylen = chan->local_addr ? strlen(chan->local_addr) : 0,
1202 remotelen = strlen(chan->addr);
1203 u8 key;
1204
1205 if (card->u.x.connection_keys == ~0U) {
1206 printk(KERN_INFO "%s: too many simultaneous connection "
1207 "requests!\n", card->devname);
1208 return -EAGAIN;
1209 }
1210
1211 key = ffz(card->u.x.connection_keys);
1212 set_bit(key, (void*)&card->u.x.connection_keys);
1213 ++key;
1214 dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
1215 memset(d, 0, sizeof(d));
1216 d[1] = key; /* user key */
1217 d[2] = 0x10;
1218 d[4] = 0x0B;
1219
1220 len = byte_to_nibble(chan->addr, d + 6, &nibble);
1221
1222 if (chan->local_addr)
1223 len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble);
1224
1225 if (nibble)
1226 ++len;
1227
1228 d[5] = mylen << 4 | remotelen;
1229 d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */
1230
1231 if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
1232 &d, 7 + len + 1, NULL, 0)) != 0)
1233 clear_bit(--key, (void*)&card->u.x.connection_keys);
1234 else
1235 chan->lcn = -key;
1236
1237 return err;
1238}
1239
1240/* Place X.25 CONNECT RESPONSE. */
1241static int cycx_x25_connect_response(struct cycx_device *card,
1242 struct cycx_x25_channel *chan)
1243{
1244 u8 d[8];
1245
1246 memset(d, 0, sizeof(d));
1247 d[0] = d[3] = chan->lcn;
1248 d[2] = 0x10;
1249 d[4] = 0x0F;
1250 d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */
1251
1252 return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
1253}
1254
1255/* Place X.25 DISCONNECT RESPONSE. */
1256static int cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
1257 u8 lcn)
1258{
1259 char d[5];
1260
1261 memset(d, 0, sizeof(d));
1262 d[0] = d[3] = lcn;
1263 d[2] = 0x10;
1264 d[4] = 0x17;
1265
1266 return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
1267}
1268
1269/* Clear X.25 call. */
1270static int x25_clear_call(struct cycx_device *card, u8 link, u8 lcn, u8 cause,
1271 u8 diagn)
1272{
1273 u8 d[7];
1274
1275 memset(d, 0, sizeof(d));
1276 d[0] = d[3] = lcn;
1277 d[2] = 0x10;
1278 d[4] = 0x13;
1279 d[5] = cause;
1280 d[6] = diagn;
1281
1282 return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);
1283}
1284
1285/* Send X.25 data packet. */
1286static int cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
1287 int len, void *buf)
1288{
1289 u8 d[] = "?\xFF\x10??";
1290
1291 d[0] = d[3] = lcn;
1292 d[4] = bitm;
1293
1294 return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);
1295}
1296
1297/* Miscellaneous */
1298/* Find network device by its channel number. */
1299static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
1300 s16 lcn)
1301{
1302 struct net_device *dev = wandev->dev;
1303 struct cycx_x25_channel *chan;
1304
1305 while (dev) {
Wang Chen7be60652008-11-20 04:26:21 -08001306 chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
1308 if (chan->lcn == lcn)
1309 break;
1310 dev = chan->slave;
1311 }
1312 return dev;
1313}
1314
1315/* Find network device by its remote dte address. */
1316static struct net_device *
1317 cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte)
1318{
1319 struct net_device *dev = wandev->dev;
1320 struct cycx_x25_channel *chan;
1321
1322 while (dev) {
Wang Chen7be60652008-11-20 04:26:21 -08001323 chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 if (!strcmp(chan->addr, dte))
1326 break;
1327 dev = chan->slave;
1328 }
1329 return dev;
1330}
1331
1332/* Initiate connection on the logical channel.
1333 * o for PVC we just get channel configuration
1334 * o for SVCs place an X.25 call
1335 *
1336 * Return: 0 connected
1337 * >0 connection in progress
1338 * <0 failure */
1339static int cycx_x25_chan_connect(struct net_device *dev)
1340{
Wang Chen7be60652008-11-20 04:26:21 -08001341 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 struct cycx_device *card = chan->card;
1343
1344 if (chan->svc) {
1345 if (!chan->addr[0])
1346 return -EINVAL; /* no destination address */
1347
1348 dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
1349 card->devname, chan->addr);
1350
1351 if (x25_place_call(card, chan))
1352 return -EIO;
1353
1354 cycx_x25_set_chan_state(dev, WAN_CONNECTING);
1355 return 1;
1356 } else
1357 cycx_x25_set_chan_state(dev, WAN_CONNECTED);
1358
1359 return 0;
1360}
1361
1362/* Disconnect logical channel.
1363 * o if SVC then clear X.25 call */
1364static void cycx_x25_chan_disconnect(struct net_device *dev)
1365{
Wang Chen7be60652008-11-20 04:26:21 -08001366 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 if (chan->svc) {
1369 x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
1370 cycx_x25_set_chan_state(dev, WAN_DISCONNECTING);
1371 } else
1372 cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
1373}
1374
1375/* Called by kernel timer */
1376static void cycx_x25_chan_timer(unsigned long d)
1377{
1378 struct net_device *dev = (struct net_device *)d;
Wang Chen7be60652008-11-20 04:26:21 -08001379 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
1381 if (chan->state == WAN_CONNECTED)
1382 cycx_x25_chan_disconnect(dev);
1383 else
1384 printk(KERN_ERR "%s: %s for svc (%s) not connected!\n",
Harvey Harrisonb39d66a2008-08-20 16:52:04 -07001385 chan->card->devname, __func__, dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
1387
1388/* Set logical channel state. */
1389static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
1390{
Wang Chen7be60652008-11-20 04:26:21 -08001391 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 struct cycx_device *card = chan->card;
1393 unsigned long flags;
1394 char *string_state = NULL;
1395
1396 spin_lock_irqsave(&card->lock, flags);
1397
1398 if (chan->state != state) {
1399 if (chan->svc && chan->state == WAN_CONNECTED)
1400 del_timer(&chan->timer);
1401
1402 switch (state) {
1403 case WAN_CONNECTED:
1404 string_state = "connected!";
Al Viro7fd71e52007-12-22 17:27:24 +00001405 *(__be16*)dev->dev_addr = htons(chan->lcn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 netif_wake_queue(dev);
1407 reset_timer(dev);
1408
1409 if (chan->protocol == ETH_P_X25)
andrew hendry5d747312010-04-19 13:30:13 +00001410 cycx_x25_chan_send_event(dev,
1411 X25_IFACE_CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 break;
1414 case WAN_CONNECTING:
1415 string_state = "connecting...";
1416 break;
1417 case WAN_DISCONNECTING:
1418 string_state = "disconnecting...";
1419 break;
1420 case WAN_DISCONNECTED:
1421 string_state = "disconnected!";
1422
1423 if (chan->svc) {
1424 *(unsigned short*)dev->dev_addr = 0;
1425 chan->lcn = 0;
1426 }
1427
1428 if (chan->protocol == ETH_P_X25)
andrew hendry5d747312010-04-19 13:30:13 +00001429 cycx_x25_chan_send_event(dev,
1430 X25_IFACE_DISCONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432 netif_wake_queue(dev);
1433 break;
1434 }
1435
1436 printk(KERN_INFO "%s: interface %s %s\n", card->devname,
1437 dev->name, string_state);
1438 chan->state = state;
1439 }
1440
1441 spin_unlock_irqrestore(&card->lock, flags);
1442}
1443
1444/* Send packet on a logical channel.
1445 * When this function is called, tx_skb field of the channel data space
1446 * points to the transmit socket buffer. When transmission is complete,
1447 * release socket buffer and reset 'tbusy' flag.
1448 *
1449 * Return: 0 - transmission complete
1450 * 1 - busy
1451 *
1452 * Notes:
1453 * 1. If packet length is greater than MTU for this channel, we'll fragment
1454 * the packet into 'complete sequence' using M-bit.
1455 * 2. When transmission is complete, an event notification should be issued
1456 * to the router. */
1457static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb)
1458{
Wang Chen7be60652008-11-20 04:26:21 -08001459 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 struct cycx_device *card = chan->card;
1461 int bitm = 0; /* final packet */
1462 unsigned len = skb->len;
1463
1464 if (skb->len > card->wandev.mtu) {
1465 len = card->wandev.mtu;
1466 bitm = 0x10; /* set M-bit (more data) */
1467 }
1468
1469 if (cycx_x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
1470 return 1;
1471
1472 if (bitm) {
1473 skb_pull(skb, len);
1474 return 1;
1475 }
1476
1477 ++chan->ifstats.tx_packets;
1478 chan->ifstats.tx_bytes += len;
1479
1480 return 0;
1481}
1482
1483/* Send event (connection, disconnection, etc) to X.25 socket layer */
1484
1485static void cycx_x25_chan_send_event(struct net_device *dev, u8 event)
1486{
1487 struct sk_buff *skb;
1488 unsigned char *ptr;
1489
1490 if ((skb = dev_alloc_skb(1)) == NULL) {
Harvey Harrisonb39d66a2008-08-20 16:52:04 -07001491 printk(KERN_ERR "%s: out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 return;
1493 }
1494
1495 ptr = skb_put(skb, 1);
1496 *ptr = event;
1497
1498 skb->protocol = x25_type_trans(skb, dev);
1499 netif_rx(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500}
1501
1502/* Convert line speed in bps to a number used by cyclom 2x code. */
1503static u8 bps_to_speed_code(u32 bps)
1504{
1505 u8 number = 0; /* defaults to the lowest (1200) speed ;> */
1506
1507 if (bps >= 512000) number = 8;
1508 else if (bps >= 256000) number = 7;
1509 else if (bps >= 64000) number = 6;
1510 else if (bps >= 38400) number = 5;
1511 else if (bps >= 19200) number = 4;
1512 else if (bps >= 9600) number = 3;
1513 else if (bps >= 4800) number = 2;
1514 else if (bps >= 2400) number = 1;
1515
1516 return number;
1517}
1518
1519/* log base 2 */
1520static u8 cycx_log2(u32 n)
1521{
1522 u8 log = 0;
1523
1524 if (!n)
1525 return 0;
1526
1527 while (n > 1) {
1528 n >>= 1;
1529 ++log;
1530 }
1531
1532 return log;
1533}
1534
1535/* Convert decimal string to unsigned integer.
1536 * If len != 0 then only 'len' characters of the string are converted. */
1537static unsigned dec_to_uint(u8 *str, int len)
1538{
1539 unsigned val = 0;
1540
1541 if (!len)
1542 len = strlen(str);
1543
Tobias Klauser8e18d1f2005-09-10 14:45:00 -07001544 for (; len && isdigit(*str); ++str, --len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 val = (val * 10) + (*str - (unsigned) '0');
1546
1547 return val;
1548}
1549
1550static void reset_timer(struct net_device *dev)
1551{
Wang Chen7be60652008-11-20 04:26:21 -08001552 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554 if (chan->svc)
1555 mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
1556}
1557#ifdef CYCLOMX_X25_DEBUG
1558static void cycx_x25_dump_config(struct cycx_x25_config *conf)
1559{
1560 printk(KERN_INFO "X.25 configuration\n");
1561 printk(KERN_INFO "-----------------\n");
1562 printk(KERN_INFO "link number=%d\n", conf->link);
1563 printk(KERN_INFO "line speed=%d\n", conf->speed);
1564 printk(KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
1565 printk(KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
1566 printk(KERN_INFO "level 2 window=%d\n", conf->n2win);
1567 printk(KERN_INFO "level 3 window=%d\n", conf->n3win);
1568 printk(KERN_INFO "# logical channels=%d\n", conf->nvc);
1569 printk(KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
1570 printk(KERN_INFO "my address=%d\n", conf->locaddr);
1571 printk(KERN_INFO "remote address=%d\n", conf->remaddr);
1572 printk(KERN_INFO "t1=%d seconds\n", conf->t1);
1573 printk(KERN_INFO "t2=%d seconds\n", conf->t2);
1574 printk(KERN_INFO "t21=%d seconds\n", conf->t21);
1575 printk(KERN_INFO "# PVCs=%d\n", conf->npvc);
1576 printk(KERN_INFO "t23=%d seconds\n", conf->t23);
1577 printk(KERN_INFO "flags=0x%x\n", conf->flags);
1578}
1579
1580static void cycx_x25_dump_stats(struct cycx_x25_stats *stats)
1581{
1582 printk(KERN_INFO "X.25 statistics\n");
1583 printk(KERN_INFO "--------------\n");
1584 printk(KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
1585 printk(KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
1586 printk(KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
1587 printk(KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
1588 printk(KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
1589 printk(KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
1590 printk(KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
1591 printk(KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
1592 printk(KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
1593 printk(KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
1594}
1595
1596static void cycx_x25_dump_devs(struct wan_device *wandev)
1597{
1598 struct net_device *dev = wandev->dev;
1599
1600 printk(KERN_INFO "X.25 dev states\n");
1601 printk(KERN_INFO "name: addr: txoff: protocol:\n");
1602 printk(KERN_INFO "---------------------------------------\n");
1603
1604 while(dev) {
Wang Chen7be60652008-11-20 04:26:21 -08001605 struct cycx_x25_channel *chan = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n",
1608 chan->name, chan->addr, netif_queue_stopped(dev),
1609 chan->protocol == ETH_P_IP ? "IP" : "X25");
1610 dev = chan->slave;
1611 }
1612}
1613
1614#endif /* CYCLOMX_X25_DEBUG */
1615/* End */