blob: b59c65b9645be21df12bb24c0fd7c2cd99799043 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * 6pack.c This module implements the 6pack protocol for kernel-based
3 * devices like TTY. It interfaces between a raw TTY and the
4 * kernel's AX.25 protocol layers.
5 *
6 * Authors: Andreas Könsgen <ajk@iehk.rwth-aachen.de>
7 * Ralf Baechle DL5RB <ralf@linux-mips.org>
8 *
9 * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
10 *
11 * Laurence Culhane, <loz@holmes.demon.co.uk>
12 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
13 */
14
15#include <linux/config.h>
16#include <linux/module.h>
17#include <asm/system.h>
18#include <asm/uaccess.h>
19#include <linux/bitops.h>
20#include <linux/string.h>
21#include <linux/mm.h>
22#include <linux/interrupt.h>
23#include <linux/in.h>
24#include <linux/tty.h>
25#include <linux/errno.h>
26#include <linux/netdevice.h>
27#include <linux/timer.h>
28#include <net/ax25.h>
29#include <linux/etherdevice.h>
30#include <linux/skbuff.h>
31#include <linux/rtnetlink.h>
32#include <linux/spinlock.h>
33#include <linux/if_arp.h>
34#include <linux/init.h>
35#include <linux/ip.h>
36#include <linux/tcp.h>
37#include <asm/semaphore.h>
38#include <asm/atomic.h>
39
40#define SIXPACK_VERSION "Revision: 0.3.0"
41
42/* sixpack priority commands */
43#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */
44#define SIXP_TX_URUN 0x48 /* transmit overrun */
45#define SIXP_RX_ORUN 0x50 /* receive overrun */
46#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */
47
48#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */
49
50/* masks to get certain bits out of the status bytes sent by the TNC */
51
52#define SIXP_CMD_MASK 0xC0
53#define SIXP_CHN_MASK 0x07
54#define SIXP_PRIO_CMD_MASK 0x80
55#define SIXP_STD_CMD_MASK 0x40
56#define SIXP_PRIO_DATA_MASK 0x38
57#define SIXP_TX_MASK 0x20
58#define SIXP_RX_MASK 0x10
59#define SIXP_RX_DCD_MASK 0x18
60#define SIXP_LEDS_ON 0x78
61#define SIXP_LEDS_OFF 0x60
62#define SIXP_CON 0x08
63#define SIXP_STA 0x10
64
65#define SIXP_FOUND_TNC 0xe9
66#define SIXP_CON_ON 0x68
67#define SIXP_DCD_MASK 0x08
68#define SIXP_DAMA_OFF 0
69
70/* default level 2 parameters */
71#define SIXP_TXDELAY (HZ/4) /* in 1 s */
72#define SIXP_PERSIST 50 /* in 256ths */
73#define SIXP_SLOTTIME (HZ/10) /* in 1 s */
74#define SIXP_INIT_RESYNC_TIMEOUT (3*HZ/2) /* in 1 s */
75#define SIXP_RESYNC_TIMEOUT 5*HZ /* in 1 s */
76
77/* 6pack configuration. */
78#define SIXP_NRUNIT 31 /* MAX number of 6pack channels */
79#define SIXP_MTU 256 /* Default MTU */
80
81enum sixpack_flags {
82 SIXPF_ERROR, /* Parity, etc. error */
83};
84
85struct sixpack {
86 /* Various fields. */
87 struct tty_struct *tty; /* ptr to TTY structure */
88 struct net_device *dev; /* easy for intr handling */
89
90 /* These are pointers to the malloc()ed frame buffers. */
91 unsigned char *rbuff; /* receiver buffer */
92 int rcount; /* received chars counter */
93 unsigned char *xbuff; /* transmitter buffer */
94 unsigned char *xhead; /* next byte to XMIT */
95 int xleft; /* bytes left in XMIT queue */
96
97 unsigned char raw_buf[4];
98 unsigned char cooked_buf[400];
99
100 unsigned int rx_count;
101 unsigned int rx_count_cooked;
102
103 /* 6pack interface statistics. */
104 struct net_device_stats stats;
105
106 int mtu; /* Our mtu (to spot changes!) */
107 int buffsize; /* Max buffers sizes */
108
109 unsigned long flags; /* Flag values/ mode etc */
110 unsigned char mode; /* 6pack mode */
111
112 /* 6pack stuff */
113 unsigned char tx_delay;
114 unsigned char persistence;
115 unsigned char slottime;
116 unsigned char duplex;
117 unsigned char led_state;
118 unsigned char status;
119 unsigned char status1;
120 unsigned char status2;
121 unsigned char tx_enable;
122 unsigned char tnc_state;
123
124 struct timer_list tx_t;
125 struct timer_list resync_t;
126 atomic_t refcnt;
127 struct semaphore dead_sem;
128 spinlock_t lock;
129};
130
131#define AX25_6PACK_HEADER_LEN 0
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static void sixpack_decode(struct sixpack *, unsigned char[], int);
134static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
135
136/*
Ralf Baechle DL5RBc0438172005-08-10 10:03:20 -0700137 * Perform the persistence/slottime algorithm for CSMA access. If the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 * persistence check was successful, write the data to the serial driver.
139 * Note that in case of DAMA operation, the data is not sent here.
140 */
141
142static void sp_xmit_on_air(unsigned long channel)
143{
144 struct sixpack *sp = (struct sixpack *) channel;
Ralf Baechle DL5RBc0438172005-08-10 10:03:20 -0700145 int actual, when = sp->slottime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 static unsigned char random;
147
148 random = random * 17 + 41;
149
150 if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
151 sp->led_state = 0x70;
152 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
153 sp->tx_enable = 1;
154 actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
155 sp->xleft -= actual;
156 sp->xhead += actual;
157 sp->led_state = 0x60;
158 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
159 sp->status2 = 0;
160 } else
Ralf Baechle DL5RBc0438172005-08-10 10:03:20 -0700161 mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}
163
164/* ----> 6pack timer interrupt handler and friends. <---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
167static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
168{
169 unsigned char *msg, *p = icp;
170 int actual, count;
171
172 if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
173 msg = "oversized transmit packet!";
174 goto out_drop;
175 }
176
177 if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
178 msg = "oversized transmit packet!";
179 goto out_drop;
180 }
181
182 if (p[0] > 5) {
183 msg = "invalid KISS command";
184 goto out_drop;
185 }
186
187 if ((p[0] != 0) && (len > 2)) {
188 msg = "KISS control packet too long";
189 goto out_drop;
190 }
191
192 if ((p[0] == 0) && (len < 15)) {
193 msg = "bad AX.25 packet to transmit";
194 goto out_drop;
195 }
196
197 count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);
198 set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
199
200 switch (p[0]) {
201 case 1: sp->tx_delay = p[1];
202 return;
203 case 2: sp->persistence = p[1];
204 return;
205 case 3: sp->slottime = p[1];
206 return;
207 case 4: /* ignored */
208 return;
209 case 5: sp->duplex = p[1];
210 return;
211 }
212
213 if (p[0] != 0)
214 return;
215
216 /*
217 * In case of fullduplex or DAMA operation, we don't take care about the
218 * state of the DCD or of any timers, as the determination of the
219 * correct time to send is the job of the AX.25 layer. We send
220 * immediately after data has arrived.
221 */
222 if (sp->duplex == 1) {
223 sp->led_state = 0x70;
224 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
225 sp->tx_enable = 1;
226 actual = sp->tty->driver->write(sp->tty, sp->xbuff, count);
227 sp->xleft = count - actual;
228 sp->xhead = sp->xbuff + actual;
229 sp->led_state = 0x60;
230 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
231 } else {
232 sp->xleft = count;
233 sp->xhead = sp->xbuff;
234 sp->status2 = count;
Ralf Baechle DL5RBc0438172005-08-10 10:03:20 -0700235 sp_xmit_on_air((unsigned long)sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 }
237
238 return;
239
240out_drop:
241 sp->stats.tx_dropped++;
242 netif_start_queue(sp->dev);
243 if (net_ratelimit())
244 printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
245}
246
247/* Encapsulate an IP datagram and kick it into a TTY queue. */
248
249static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
250{
251 struct sixpack *sp = netdev_priv(dev);
252
253 spin_lock_bh(&sp->lock);
254 /* We were not busy, so we are now... :-) */
255 netif_stop_queue(dev);
256 sp->stats.tx_bytes += skb->len;
257 sp_encaps(sp, skb->data, skb->len);
258 spin_unlock_bh(&sp->lock);
259
260 dev_kfree_skb(skb);
261
262 return 0;
263}
264
265static int sp_open_dev(struct net_device *dev)
266{
267 struct sixpack *sp = netdev_priv(dev);
268
269 if (sp->tty == NULL)
270 return -ENODEV;
271 return 0;
272}
273
274/* Close the low-level part of the 6pack channel. */
275static int sp_close(struct net_device *dev)
276{
277 struct sixpack *sp = netdev_priv(dev);
278
279 spin_lock_bh(&sp->lock);
280 if (sp->tty) {
281 /* TTY discipline is running. */
282 clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
283 }
284 netif_stop_queue(dev);
285 spin_unlock_bh(&sp->lock);
286
287 return 0;
288}
289
290/* Return the frame type ID */
291static int sp_header(struct sk_buff *skb, struct net_device *dev,
292 unsigned short type, void *daddr, void *saddr, unsigned len)
293{
294#ifdef CONFIG_INET
295 if (type != htons(ETH_P_AX25))
296 return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
297#endif
298 return 0;
299}
300
301static struct net_device_stats *sp_get_stats(struct net_device *dev)
302{
303 struct sixpack *sp = netdev_priv(dev);
304 return &sp->stats;
305}
306
307static int sp_set_mac_address(struct net_device *dev, void *addr)
308{
309 struct sockaddr_ax25 *sa = addr;
310
311 if (sa->sax25_family != AF_AX25)
312 return -EINVAL;
313
314 if (!sa->sax25_ndigis)
315 return -EINVAL;
316
317 spin_lock_irq(&dev->xmit_lock);
318 memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
319 spin_unlock_irq(&dev->xmit_lock);
320
321 return 0;
322}
323
324static int sp_rebuild_header(struct sk_buff *skb)
325{
326#ifdef CONFIG_INET
327 return ax25_rebuild_header(skb);
328#else
329 return 0;
330#endif
331}
332
333static void sp_setup(struct net_device *dev)
334{
335 static char ax25_bcast[AX25_ADDR_LEN] =
336 {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
337 static char ax25_test[AX25_ADDR_LEN] =
338 {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
339
340 /* Finish setting up the DEVICE info. */
341 dev->mtu = SIXP_MTU;
342 dev->hard_start_xmit = sp_xmit;
343 dev->open = sp_open_dev;
344 dev->destructor = free_netdev;
345 dev->stop = sp_close;
346 dev->hard_header = sp_header;
347 dev->get_stats = sp_get_stats;
348 dev->set_mac_address = sp_set_mac_address;
349 dev->hard_header_len = AX25_MAX_HEADER_LEN;
350 dev->addr_len = AX25_ADDR_LEN;
351 dev->type = ARPHRD_AX25;
352 dev->tx_queue_len = 10;
353 dev->rebuild_header = sp_rebuild_header;
354 dev->tx_timeout = NULL;
355
356 /* Only activated in AX.25 mode */
357 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
358 memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
359
360 SET_MODULE_OWNER(dev);
361
362 dev->flags = 0;
363}
364
365/* Send one completely decapsulated IP datagram to the IP layer. */
366
367/*
368 * This is the routine that sends the received data to the kernel AX.25.
369 * 'cmd' is the KISS command. For AX.25 data, it is zero.
370 */
371
372static void sp_bump(struct sixpack *sp, char cmd)
373{
374 struct sk_buff *skb;
375 int count;
376 unsigned char *ptr;
377
378 count = sp->rcount + 1;
379
380 sp->stats.rx_bytes += count;
381
382 if ((skb = dev_alloc_skb(count)) == NULL)
383 goto out_mem;
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 ptr = skb_put(skb, count);
386 *ptr++ = cmd; /* KISS command */
387
388 memcpy(ptr, sp->cooked_buf + 1, count);
Arnaldo Carvalho de Melo56cb5152005-04-24 18:53:06 -0700389 skb->protocol = ax25_type_trans(skb, sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 netif_rx(skb);
391 sp->dev->last_rx = jiffies;
392 sp->stats.rx_packets++;
393
394 return;
395
396out_mem:
397 sp->stats.rx_dropped++;
398}
399
400
401/* ----------------------------------------------------------------------- */
402
403/*
404 * We have a potential race on dereferencing tty->disc_data, because the tty
405 * layer provides no locking at all - thus one cpu could be running
406 * sixpack_receive_buf while another calls sixpack_close, which zeroes
407 * tty->disc_data and frees the memory that sixpack_receive_buf is using. The
408 * best way to fix this is to use a rwlock in the tty struct, but for now we
409 * use a single global rwlock for all ttys in ppp line discipline.
410 */
411static DEFINE_RWLOCK(disc_data_lock);
412
413static struct sixpack *sp_get(struct tty_struct *tty)
414{
415 struct sixpack *sp;
416
417 read_lock(&disc_data_lock);
418 sp = tty->disc_data;
419 if (sp)
420 atomic_inc(&sp->refcnt);
421 read_unlock(&disc_data_lock);
422
423 return sp;
424}
425
426static void sp_put(struct sixpack *sp)
427{
428 if (atomic_dec_and_test(&sp->refcnt))
429 up(&sp->dead_sem);
430}
431
432/*
433 * Called by the TTY driver when there's room for more data. If we have
434 * more packets to send, we send them here.
435 */
436static void sixpack_write_wakeup(struct tty_struct *tty)
437{
438 struct sixpack *sp = sp_get(tty);
439 int actual;
440
441 if (!sp)
442 return;
443 if (sp->xleft <= 0) {
444 /* Now serial buffer is almost free & we can start
445 * transmission of another packet */
446 sp->stats.tx_packets++;
447 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
448 sp->tx_enable = 0;
449 netif_wake_queue(sp->dev);
450 goto out;
451 }
452
453 if (sp->tx_enable) {
454 actual = tty->driver->write(tty, sp->xhead, sp->xleft);
455 sp->xleft -= actual;
456 sp->xhead += actual;
457 }
458
459out:
460 sp_put(sp);
461}
462
463/* ----------------------------------------------------------------------- */
464
465static int sixpack_receive_room(struct tty_struct *tty)
466{
467 return 65536; /* We can handle an infinite amount of data. :-) */
468}
469
470/*
471 * Handle the 'receiver data ready' interrupt.
472 * This function is called by the 'tty_io' module in the kernel when
473 * a block of 6pack data has been received, which can now be decapsulated
474 * and sent on to some IP layer for further processing.
475 */
476static void sixpack_receive_buf(struct tty_struct *tty,
477 const unsigned char *cp, char *fp, int count)
478{
479 struct sixpack *sp;
480 unsigned char buf[512];
481 int count1;
482
483 if (!count)
484 return;
485
486 sp = sp_get(tty);
487 if (!sp)
488 return;
489
490 memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
491
492 /* Read the characters out of the buffer */
493
494 count1 = count;
495 while (count) {
496 count--;
497 if (fp && *fp++) {
498 if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
499 sp->stats.rx_errors++;
500 continue;
501 }
502 }
503 sixpack_decode(sp, buf, count1);
504
505 sp_put(sp);
506 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
507 && tty->driver->unthrottle)
508 tty->driver->unthrottle(tty);
509}
510
511/*
512 * Try to resync the TNC. Called by the resync timer defined in
513 * decode_prio_command
514 */
515
516#define TNC_UNINITIALIZED 0
517#define TNC_UNSYNC_STARTUP 1
518#define TNC_UNSYNCED 2
519#define TNC_IN_SYNC 3
520
521static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
522{
523 char *msg;
524
525 switch (new_tnc_state) {
526 default: /* gcc oh piece-o-crap ... */
527 case TNC_UNSYNC_STARTUP:
528 msg = "Synchronizing with TNC";
529 break;
530 case TNC_UNSYNCED:
531 msg = "Lost synchronization with TNC\n";
532 break;
533 case TNC_IN_SYNC:
534 msg = "Found TNC";
535 break;
536 }
537
538 sp->tnc_state = new_tnc_state;
539 printk(KERN_INFO "%s: %s\n", sp->dev->name, msg);
540}
541
542static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
543{
544 int old_tnc_state = sp->tnc_state;
545
546 if (old_tnc_state != new_tnc_state)
547 __tnc_set_sync_state(sp, new_tnc_state);
548}
549
550static void resync_tnc(unsigned long channel)
551{
552 struct sixpack *sp = (struct sixpack *) channel;
553 static char resync_cmd = 0xe8;
554
555 /* clear any data that might have been received */
556
557 sp->rx_count = 0;
558 sp->rx_count_cooked = 0;
559
560 /* reset state machine */
561
562 sp->status = 1;
563 sp->status1 = 1;
564 sp->status2 = 0;
565
566 /* resync the TNC */
567
568 sp->led_state = 0x60;
569 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
570 sp->tty->driver->write(sp->tty, &resync_cmd, 1);
571
572
573 /* Start resync timer again -- the TNC might be still absent */
574
575 del_timer(&sp->resync_t);
576 sp->resync_t.data = (unsigned long) sp;
577 sp->resync_t.function = resync_tnc;
578 sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
579 add_timer(&sp->resync_t);
580}
581
582static inline int tnc_init(struct sixpack *sp)
583{
584 unsigned char inbyte = 0xe8;
585
586 tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
587
588 sp->tty->driver->write(sp->tty, &inbyte, 1);
589
590 del_timer(&sp->resync_t);
591 sp->resync_t.data = (unsigned long) sp;
592 sp->resync_t.function = resync_tnc;
593 sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
594 add_timer(&sp->resync_t);
595
596 return 0;
597}
598
599/*
600 * Open the high-level part of the 6pack channel.
601 * This function is called by the TTY module when the
602 * 6pack line discipline is called for. Because we are
603 * sure the tty line exists, we only have to link it to
604 * a free 6pcack channel...
605 */
606static int sixpack_open(struct tty_struct *tty)
607{
608 char *rbuff = NULL, *xbuff = NULL;
609 struct net_device *dev;
610 struct sixpack *sp;
611 unsigned long len;
612 int err = 0;
613
614 if (!capable(CAP_NET_ADMIN))
615 return -EPERM;
616
617 dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
618 if (!dev) {
619 err = -ENOMEM;
620 goto out;
621 }
622
623 sp = netdev_priv(dev);
624 sp->dev = dev;
625
626 spin_lock_init(&sp->lock);
627 atomic_set(&sp->refcnt, 1);
628 init_MUTEX_LOCKED(&sp->dead_sem);
629
630 /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */
631
632 len = dev->mtu * 2;
633
634 rbuff = kmalloc(len + 4, GFP_KERNEL);
635 xbuff = kmalloc(len + 4, GFP_KERNEL);
636
637 if (rbuff == NULL || xbuff == NULL) {
638 err = -ENOBUFS;
639 goto out_free;
640 }
641
642 spin_lock_bh(&sp->lock);
643
644 sp->tty = tty;
645
646 sp->rbuff = rbuff;
647 sp->xbuff = xbuff;
648
649 sp->mtu = AX25_MTU + 73;
650 sp->buffsize = len;
651 sp->rcount = 0;
652 sp->rx_count = 0;
653 sp->rx_count_cooked = 0;
654 sp->xleft = 0;
655
656 sp->flags = 0; /* Clear ESCAPE & ERROR flags */
657
658 sp->duplex = 0;
659 sp->tx_delay = SIXP_TXDELAY;
660 sp->persistence = SIXP_PERSIST;
661 sp->slottime = SIXP_SLOTTIME;
662 sp->led_state = 0x60;
663 sp->status = 1;
664 sp->status1 = 1;
665 sp->status2 = 0;
666 sp->tx_enable = 0;
667
668 netif_start_queue(dev);
669
670 init_timer(&sp->tx_t);
Ralf Baechle84a2ea12005-08-25 19:38:30 +0100671 sp->tx_t.function = sp_xmit_on_air;
672 sp->tx_t.data = (unsigned long) sp;
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 init_timer(&sp->resync_t);
675
676 spin_unlock_bh(&sp->lock);
677
678 /* Done. We have linked the TTY line to a channel. */
679 tty->disc_data = sp;
680
681 /* Now we're ready to register. */
682 if (register_netdev(dev))
683 goto out_free;
684
685 tnc_init(sp);
686
687 return 0;
688
689out_free:
690 kfree(xbuff);
691 kfree(rbuff);
692
693 if (dev)
694 free_netdev(dev);
695
696out:
697 return err;
698}
699
700
701/*
702 * Close down a 6pack channel.
703 * This means flushing out any pending queues, and then restoring the
704 * TTY line discipline to what it was before it got hooked to 6pack
705 * (which usually is TTY again).
706 */
707static void sixpack_close(struct tty_struct *tty)
708{
709 struct sixpack *sp;
710
711 write_lock(&disc_data_lock);
712 sp = tty->disc_data;
713 tty->disc_data = NULL;
714 write_unlock(&disc_data_lock);
715 if (sp == 0)
716 return;
717
718 /*
719 * We have now ensured that nobody can start using ap from now on, but
720 * we have to wait for all existing users to finish.
721 */
722 if (!atomic_dec_and_test(&sp->refcnt))
723 down(&sp->dead_sem);
724
725 unregister_netdev(sp->dev);
726
727 del_timer(&sp->tx_t);
728 del_timer(&sp->resync_t);
729
730 /* Free all 6pack frame buffers. */
731 kfree(sp->rbuff);
732 kfree(sp->xbuff);
733}
734
735/* Perform I/O control on an active 6pack channel. */
736static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
737 unsigned int cmd, unsigned long arg)
738{
739 struct sixpack *sp = sp_get(tty);
740 struct net_device *dev = sp->dev;
741 unsigned int tmp, err;
742
743 if (!sp)
744 return -ENXIO;
745
746 switch(cmd) {
747 case SIOCGIFNAME:
748 err = copy_to_user((void __user *) arg, dev->name,
749 strlen(dev->name) + 1) ? -EFAULT : 0;
750 break;
751
752 case SIOCGIFENCAP:
753 err = put_user(0, (int __user *) arg);
754 break;
755
756 case SIOCSIFENCAP:
757 if (get_user(tmp, (int __user *) arg)) {
758 err = -EFAULT;
759 break;
760 }
761
762 sp->mode = tmp;
763 dev->addr_len = AX25_ADDR_LEN;
764 dev->hard_header_len = AX25_KISS_HEADER_LEN +
765 AX25_MAX_HEADER_LEN + 3;
766 dev->type = ARPHRD_AX25;
767
768 err = 0;
769 break;
770
771 case SIOCSIFHWADDR: {
772 char addr[AX25_ADDR_LEN];
773
774 if (copy_from_user(&addr,
775 (void __user *) arg, AX25_ADDR_LEN)) {
776 err = -EFAULT;
777 break;
778 }
779
780 spin_lock_irq(&dev->xmit_lock);
781 memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
782 spin_unlock_irq(&dev->xmit_lock);
783
784 err = 0;
785 break;
786 }
787
788 /* Allow stty to read, but not set, the serial port */
789 case TCGETS:
790 case TCGETA:
791 err = n_tty_ioctl(tty, (struct file *) file, cmd, arg);
792 break;
793
794 default:
795 err = -ENOIOCTLCMD;
796 }
797
798 sp_put(sp);
799
800 return err;
801}
802
803static struct tty_ldisc sp_ldisc = {
804 .owner = THIS_MODULE,
805 .magic = TTY_LDISC_MAGIC,
806 .name = "6pack",
807 .open = sixpack_open,
808 .close = sixpack_close,
809 .ioctl = sixpack_ioctl,
810 .receive_buf = sixpack_receive_buf,
811 .receive_room = sixpack_receive_room,
812 .write_wakeup = sixpack_write_wakeup,
813};
814
815/* Initialize 6pack control device -- register 6pack line discipline */
816
817static char msg_banner[] __initdata = KERN_INFO \
818 "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
819static char msg_regfail[] __initdata = KERN_ERR \
820 "6pack: can't register line discipline (err = %d)\n";
821
822static int __init sixpack_init_driver(void)
823{
824 int status;
825
826 printk(msg_banner);
827
828 /* Register the provided line protocol discipline */
829 if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)
830 printk(msg_regfail, status);
831
832 return status;
833}
834
835static const char msg_unregfail[] __exitdata = KERN_ERR \
836 "6pack: can't unregister line discipline (err = %d)\n";
837
838static void __exit sixpack_exit_driver(void)
839{
840 int ret;
841
Alexey Dobriyan64ccd712005-06-23 00:10:33 -0700842 if ((ret = tty_unregister_ldisc(N_6PACK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 printk(msg_unregfail, ret);
844}
845
846/* encode an AX.25 packet into 6pack */
847
848static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
849 int length, unsigned char tx_delay)
850{
851 int count = 0;
852 unsigned char checksum = 0, buf[400];
853 int raw_count = 0;
854
855 tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK;
856 tx_buf_raw[raw_count++] = SIXP_SEOF;
857
858 buf[0] = tx_delay;
859 for (count = 1; count < length; count++)
860 buf[count] = tx_buf[count];
861
862 for (count = 0; count < length; count++)
863 checksum += buf[count];
864 buf[length] = (unsigned char) 0xff - checksum;
865
866 for (count = 0; count <= length; count++) {
867 if ((count % 3) == 0) {
868 tx_buf_raw[raw_count++] = (buf[count] & 0x3f);
869 tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30);
870 } else if ((count % 3) == 1) {
871 tx_buf_raw[raw_count++] |= (buf[count] & 0x0f);
872 tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c);
873 } else {
874 tx_buf_raw[raw_count++] |= (buf[count] & 0x03);
875 tx_buf_raw[raw_count++] = (buf[count] >> 2);
876 }
877 }
878 if ((length % 3) != 2)
879 raw_count++;
880 tx_buf_raw[raw_count++] = SIXP_SEOF;
881 return raw_count;
882}
883
884/* decode 4 sixpack-encoded bytes into 3 data bytes */
885
886static void decode_data(struct sixpack *sp, unsigned char inbyte)
887{
888 unsigned char *buf;
889
890 if (sp->rx_count != 3) {
891 sp->raw_buf[sp->rx_count++] = inbyte;
892
893 return;
894 }
895
896 buf = sp->raw_buf;
897 sp->cooked_buf[sp->rx_count_cooked++] =
898 buf[0] | ((buf[1] << 2) & 0xc0);
899 sp->cooked_buf[sp->rx_count_cooked++] =
900 (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
901 sp->cooked_buf[sp->rx_count_cooked++] =
902 (buf[2] & 0x03) | (inbyte << 2);
903 sp->rx_count = 0;
904}
905
906/* identify and execute a 6pack priority command byte */
907
908static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
909{
910 unsigned char channel;
911 int actual;
912
913 channel = cmd & SIXP_CHN_MASK;
914 if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */
915
916 /* RX and DCD flags can only be set in the same prio command,
917 if the DCD flag has been set without the RX flag in the previous
918 prio command. If DCD has not been set before, something in the
919 transmission has gone wrong. In this case, RX and DCD are
920 cleared in order to prevent the decode_data routine from
921 reading further data that might be corrupt. */
922
923 if (((sp->status & SIXP_DCD_MASK) == 0) &&
924 ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) {
925 if (sp->status != 1)
926 printk(KERN_DEBUG "6pack: protocol violation\n");
927 else
928 sp->status = 0;
929 cmd &= !SIXP_RX_DCD_MASK;
930 }
931 sp->status = cmd & SIXP_PRIO_DATA_MASK;
932 } else { /* output watchdog char if idle */
933 if ((sp->status2 != 0) && (sp->duplex == 1)) {
934 sp->led_state = 0x70;
935 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
936 sp->tx_enable = 1;
937 actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
938 sp->xleft -= actual;
939 sp->xhead += actual;
940 sp->led_state = 0x60;
941 sp->status2 = 0;
942
943 }
944 }
945
946 /* needed to trigger the TNC watchdog */
947 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
948
949 /* if the state byte has been received, the TNC is present,
950 so the resync timer can be reset. */
951
952 if (sp->tnc_state == TNC_IN_SYNC) {
953 del_timer(&sp->resync_t);
954 sp->resync_t.data = (unsigned long) sp;
955 sp->resync_t.function = resync_tnc;
956 sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT;
957 add_timer(&sp->resync_t);
958 }
959
960 sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
961}
962
963/* identify and execute a standard 6pack command byte */
964
965static void decode_std_command(struct sixpack *sp, unsigned char cmd)
966{
967 unsigned char checksum = 0, rest = 0, channel;
968 short i;
969
970 channel = cmd & SIXP_CHN_MASK;
971 switch (cmd & SIXP_CMD_MASK) { /* normal command */
972 case SIXP_SEOF:
973 if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
974 if ((sp->status & SIXP_RX_DCD_MASK) ==
975 SIXP_RX_DCD_MASK) {
976 sp->led_state = 0x68;
977 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
978 }
979 } else {
980 sp->led_state = 0x60;
981 /* fill trailing bytes with zeroes */
982 sp->tty->driver->write(sp->tty, &sp->led_state, 1);
983 rest = sp->rx_count;
984 if (rest != 0)
985 for (i = rest; i <= 3; i++)
986 decode_data(sp, 0);
987 if (rest == 2)
988 sp->rx_count_cooked -= 2;
989 else if (rest == 3)
990 sp->rx_count_cooked -= 1;
991 for (i = 0; i < sp->rx_count_cooked; i++)
992 checksum += sp->cooked_buf[i];
993 if (checksum != SIXP_CHKSUM) {
994 printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
995 } else {
996 sp->rcount = sp->rx_count_cooked-2;
997 sp_bump(sp, 0);
998 }
999 sp->rx_count_cooked = 0;
1000 }
1001 break;
1002 case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
1003 break;
1004 case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
1005 break;
1006 case SIXP_RX_BUF_OVL:
1007 printk(KERN_DEBUG "6pack: RX buffer overflow\n");
1008 }
1009}
1010
1011/* decode a 6pack packet */
1012
1013static void
1014sixpack_decode(struct sixpack *sp, unsigned char *pre_rbuff, int count)
1015{
1016 unsigned char inbyte;
1017 int count1;
1018
1019 for (count1 = 0; count1 < count; count1++) {
1020 inbyte = pre_rbuff[count1];
1021 if (inbyte == SIXP_FOUND_TNC) {
1022 tnc_set_sync_state(sp, TNC_IN_SYNC);
1023 del_timer(&sp->resync_t);
1024 }
1025 if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
1026 decode_prio_command(sp, inbyte);
1027 else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
1028 decode_std_command(sp, inbyte);
1029 else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
1030 decode_data(sp, inbyte);
1031 }
1032}
1033
1034MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>");
1035MODULE_DESCRIPTION("6pack driver for AX.25");
1036MODULE_LICENSE("GPL");
1037MODULE_ALIAS_LDISC(N_6PACK);
1038
1039module_init(sixpack_init_driver);
1040module_exit(sixpack_exit_driver);