diff options
-rw-r--r-- | drivers/net/hamradio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/hamradio/mkiss.c | 178 |
2 files changed, 148 insertions, 31 deletions
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index de087cd609d9..896aa02000d7 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config MKISS | 1 | config MKISS |
2 | tristate "Serial port KISS driver" | 2 | tristate "Serial port KISS driver" |
3 | depends on AX25 | 3 | depends on AX25 |
4 | select CRC16 | ||
4 | ---help--- | 5 | ---help--- |
5 | KISS is a protocol used for the exchange of data between a computer | 6 | KISS is a protocol used for the exchange of data between a computer |
6 | and a Terminal Node Controller (a small embedded system commonly | 7 | and a Terminal Node Controller (a small embedded system commonly |
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 331a75c8aee2..7961f5b41c4b 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 | ||
154 | static 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. */ |
@@ -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 | ||
731 | static int crc_force = 0; /* Can be overridden with insmod */ | ||
732 | |||
646 | static int mkiss_open(struct tty_struct *tty) | 733 | static 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. */ |
@@ -903,6 +1017,8 @@ static void __exit mkiss_exit_driver(void) | |||
903 | 1017 | ||
904 | MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); | 1018 | MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); |
905 | MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); | 1019 | MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); |
1020 | MODULE_PARM(crc_force, "i"); | ||
1021 | MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); | ||
906 | MODULE_LICENSE("GPL"); | 1022 | MODULE_LICENSE("GPL"); |
907 | MODULE_ALIAS_LDISC(N_AX25); | 1023 | MODULE_ALIAS_LDISC(N_AX25); |
908 | 1024 | ||