aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hamradio/mkiss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/hamradio/mkiss.c')
-rw-r--r--drivers/net/hamradio/mkiss.c182
1 files changed, 149 insertions, 33 deletions
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d9fe64b46f4b..85d6dc005be0 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -14,13 +14,14 @@
14 * 14 *
15 * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl> 15 * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
16 * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org> 16 * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
17 * Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
17 */ 18 */
18
19#include <linux/config.h> 19#include <linux/config.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <asm/system.h> 21#include <asm/system.h>
22#include <linux/bitops.h> 22#include <linux/bitops.h>
23#include <asm/uaccess.h> 23#include <asm/uaccess.h>
24#include <linux/crc16.h>
24#include <linux/string.h> 25#include <linux/string.h>
25#include <linux/mm.h> 26#include <linux/mm.h>
26#include <linux/interrupt.h> 27#include <linux/interrupt.h>
@@ -39,11 +40,6 @@
39 40
40#include <net/ax25.h> 41#include <net/ax25.h>
41 42
42#ifdef CONFIG_INET
43#include <linux/ip.h>
44#include <linux/tcp.h>
45#endif
46
47#define AX_MTU 236 43#define AX_MTU 236
48 44
49/* SLIP/KISS protocol characters. */ 45/* SLIP/KISS protocol characters. */
@@ -80,9 +76,13 @@ struct mkiss {
80 76
81 int mode; 77 int mode;
82 int crcmode; /* MW: for FlexNet, SMACK etc. */ 78 int crcmode; /* MW: for FlexNet, SMACK etc. */
83#define CRC_MODE_NONE 0 79 int crcauto; /* CRC auto mode */
84#define CRC_MODE_FLEX 1 80
85#define CRC_MODE_SMACK 2 81#define CRC_MODE_NONE 0
82#define CRC_MODE_FLEX 1
83#define CRC_MODE_SMACK 2
84#define CRC_MODE_FLEX_TEST 3
85#define CRC_MODE_SMACK_TEST 4
86 86
87 atomic_t refcnt; 87 atomic_t refcnt;
88 struct semaphore dead_sem; 88 struct semaphore dead_sem;
@@ -151,6 +151,21 @@ static int check_crc_flex(unsigned char *cp, int size)
151 return 0; 151 return 0;
152} 152}
153 153
154static int check_crc_16(unsigned char *cp, int size)
155{
156 unsigned short crc = 0x0000;
157
158 if (size < 3)
159 return -1;
160
161 crc = crc16(0, cp, size);
162
163 if (crc != 0x0000)
164 return -1;
165
166 return 0;
167}
168
154/* 169/*
155 * Standard encapsulation 170 * Standard encapsulation
156 */ 171 */
@@ -237,19 +252,42 @@ static void ax_bump(struct mkiss *ax)
237 252
238 spin_lock_bh(&ax->buflock); 253 spin_lock_bh(&ax->buflock);
239 if (ax->rbuff[0] > 0x0f) { 254 if (ax->rbuff[0] > 0x0f) {
240 if (ax->rbuff[0] & 0x20) { 255 if (ax->rbuff[0] & 0x80) {
241 ax->crcmode = CRC_MODE_FLEX; 256 if (check_crc_16(ax->rbuff, ax->rcount) < 0) {
257 ax->stats.rx_errors++;
258 spin_unlock_bh(&ax->buflock);
259
260 return;
261 }
262 if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) {
263 printk(KERN_INFO
264 "mkiss: %s: Switchting to crc-smack\n",
265 ax->dev->name);
266 ax->crcmode = CRC_MODE_SMACK;
267 }
268 ax->rcount -= 2;
269 *ax->rbuff &= ~0x80;
270 } else if (ax->rbuff[0] & 0x20) {
242 if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { 271 if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
243 ax->stats.rx_errors++; 272 ax->stats.rx_errors++;
273 spin_unlock_bh(&ax->buflock);
244 return; 274 return;
245 } 275 }
276 if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
277 printk(KERN_INFO
278 "mkiss: %s: Switchting to crc-flexnet\n",
279 ax->dev->name);
280 ax->crcmode = CRC_MODE_FLEX;
281 }
246 ax->rcount -= 2; 282 ax->rcount -= 2;
247 /* dl9sau bugfix: the trailling two bytes flexnet crc 283
248 * will not be passed to the kernel. thus we have 284 /*
249 * to correct the kissparm signature, because it 285 * dl9sau bugfix: the trailling two bytes flexnet crc
250 * indicates a crc but there's none 286 * will not be passed to the kernel. thus we have to
287 * correct the kissparm signature, because it indicates
288 * a crc but there's none
251 */ 289 */
252 *ax->rbuff &= ~0x20; 290 *ax->rbuff &= ~0x20;
253 } 291 }
254 } 292 }
255 spin_unlock_bh(&ax->buflock); 293 spin_unlock_bh(&ax->buflock);
@@ -417,20 +455,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
417 p = icp; 455 p = icp;
418 456
419 spin_lock_bh(&ax->buflock); 457 spin_lock_bh(&ax->buflock);
420 switch (ax->crcmode) { 458 if ((*p & 0x0f) != 0) {
421 unsigned short crc; 459 /* Configuration Command (kissparms(1).
460 * Protocol spec says: never append CRC.
461 * This fixes a very old bug in the linux
462 * kiss driver. -- dl9sau */
463 switch (*p & 0xff) {
464 case 0x85:
465 /* command from userspace especially for us,
466 * not for delivery to the tnc */
467 if (len > 1) {
468 int cmd = (p[1] & 0xff);
469 switch(cmd) {
470 case 3:
471 ax->crcmode = CRC_MODE_SMACK;
472 break;
473 case 2:
474 ax->crcmode = CRC_MODE_FLEX;
475 break;
476 case 1:
477 ax->crcmode = CRC_MODE_NONE;
478 break;
479 case 0:
480 default:
481 ax->crcmode = CRC_MODE_SMACK_TEST;
482 cmd = 0;
483 }
484 ax->crcauto = (cmd ? 0 : 1);
485 printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd);
486 }
487 spin_unlock_bh(&ax->buflock);
488 netif_start_queue(dev);
422 489
423 case CRC_MODE_FLEX: 490 return;
424 *p |= 0x20; 491 default:
425 crc = calc_crc_flex(p, len); 492 count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
426 count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); 493 }
427 break; 494 } else {
495 unsigned short crc;
496 switch (ax->crcmode) {
497 case CRC_MODE_SMACK_TEST:
498 ax->crcmode = CRC_MODE_FLEX_TEST;
499 printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name);
500 // fall through
501 case CRC_MODE_SMACK:
502 *p |= 0x80;
503 crc = swab16(crc16(0, p, len));
504 count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
505 break;
506 case CRC_MODE_FLEX_TEST:
507 ax->crcmode = CRC_MODE_NONE;
508 printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
509 // fall through
510 case CRC_MODE_FLEX:
511 *p |= 0x20;
512 crc = calc_crc_flex(p, len);
513 count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
514 break;
515
516 default:
517 count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
518 }
519 }
428 520
429 default:
430 count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
431 break;
432 }
433
434 set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); 521 set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
435 actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); 522 actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
436 ax->stats.tx_packets++; 523 ax->stats.tx_packets++;
@@ -439,8 +526,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
439 ax->dev->trans_start = jiffies; 526 ax->dev->trans_start = jiffies;
440 ax->xleft = count - actual; 527 ax->xleft = count - actual;
441 ax->xhead = ax->xbuff + actual; 528 ax->xhead = ax->xbuff + actual;
442
443 spin_unlock_bh(&ax->buflock);
444} 529}
445 530
446/* Encapsulate an AX.25 packet and kick it into a TTY queue. */ 531/* Encapsulate an AX.25 packet and kick it into a TTY queue. */
@@ -622,7 +707,7 @@ static void ax_setup(struct net_device *dev)
622 * best way to fix this is to use a rwlock in the tty struct, but for now we 707 * best way to fix this is to use a rwlock in the tty struct, but for now we
623 * use a single global rwlock for all ttys in ppp line discipline. 708 * use a single global rwlock for all ttys in ppp line discipline.
624 */ 709 */
625static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; 710static DEFINE_RWLOCK(disc_data_lock);
626 711
627static struct mkiss *mkiss_get(struct tty_struct *tty) 712static struct mkiss *mkiss_get(struct tty_struct *tty)
628{ 713{
@@ -643,6 +728,8 @@ static void mkiss_put(struct mkiss *ax)
643 up(&ax->dead_sem); 728 up(&ax->dead_sem);
644} 729}
645 730
731static int crc_force = 0; /* Can be overridden with insmod */
732
646static int mkiss_open(struct tty_struct *tty) 733static int mkiss_open(struct tty_struct *tty)
647{ 734{
648 struct net_device *dev; 735 struct net_device *dev;
@@ -682,6 +769,33 @@ static int mkiss_open(struct tty_struct *tty)
682 if (register_netdev(dev)) 769 if (register_netdev(dev))
683 goto out_free_buffers; 770 goto out_free_buffers;
684 771
772 /* after register_netdev() - because else printk smashes the kernel */
773 switch (crc_force) {
774 case 3:
775 ax->crcmode = CRC_MODE_SMACK;
776 printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n",
777 ax->dev->name);
778 break;
779 case 2:
780 ax->crcmode = CRC_MODE_FLEX;
781 printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n",
782 ax->dev->name);
783 break;
784 case 1:
785 ax->crcmode = CRC_MODE_NONE;
786 printk(KERN_INFO "mkiss: %s: crc mode disabled.\n",
787 ax->dev->name);
788 break;
789 case 0:
790 /* fall through */
791 default:
792 crc_force = 0;
793 printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
794 ax->dev->name);
795 ax->crcmode = CRC_MODE_SMACK_TEST;
796 }
797 ax->crcauto = (crc_force ? 0 : 1);
798
685 netif_start_queue(dev); 799 netif_start_queue(dev);
686 800
687 /* Done. We have linked the TTY line to a channel. */ 801 /* Done. We have linked the TTY line to a channel. */
@@ -765,7 +879,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
765 879
766 case SIOCSIFHWADDR: { 880 case SIOCSIFHWADDR: {
767 char addr[AX25_ADDR_LEN]; 881 char addr[AX25_ADDR_LEN];
768printk(KERN_INFO "In SIOCSIFHWADDR");
769 882
770 if (copy_from_user(&addr, 883 if (copy_from_user(&addr,
771 (void __user *) arg, AX25_ADDR_LEN)) { 884 (void __user *) arg, AX25_ADDR_LEN)) {
@@ -864,6 +977,7 @@ out:
864} 977}
865 978
866static struct tty_ldisc ax_ldisc = { 979static struct tty_ldisc ax_ldisc = {
980 .owner = THIS_MODULE,
867 .magic = TTY_LDISC_MAGIC, 981 .magic = TTY_LDISC_MAGIC,
868 .name = "mkiss", 982 .name = "mkiss",
869 .open = mkiss_open, 983 .open = mkiss_open,
@@ -904,6 +1018,8 @@ static void __exit mkiss_exit_driver(void)
904 1018
905MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); 1019MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
906MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); 1020MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
1021MODULE_PARM(crc_force, "i");
1022MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]");
907MODULE_LICENSE("GPL"); 1023MODULE_LICENSE("GPL");
908MODULE_ALIAS_LDISC(N_AX25); 1024MODULE_ALIAS_LDISC(N_AX25);
909 1025