diff options
Diffstat (limited to 'drivers/net/hamradio/mkiss.c')
-rw-r--r-- | drivers/net/hamradio/mkiss.c | 188 |
1 files changed, 151 insertions, 37 deletions
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d9fe64b46f4b..3e9accf137e7 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); |
@@ -352,10 +390,8 @@ static void ax_changedmtu(struct mkiss *ax) | |||
352 | "MTU change cancelled.\n", | 390 | "MTU change cancelled.\n", |
353 | ax->dev->name); | 391 | ax->dev->name); |
354 | dev->mtu = ax->mtu; | 392 | dev->mtu = ax->mtu; |
355 | if (xbuff != NULL) | 393 | kfree(xbuff); |
356 | kfree(xbuff); | 394 | kfree(rbuff); |
357 | if (rbuff != NULL) | ||
358 | kfree(rbuff); | ||
359 | return; | 395 | return; |
360 | } | 396 | } |
361 | 397 | ||
@@ -417,20 +453,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) | |||
417 | p = icp; | 453 | p = icp; |
418 | 454 | ||
419 | spin_lock_bh(&ax->buflock); | 455 | spin_lock_bh(&ax->buflock); |
420 | switch (ax->crcmode) { | 456 | if ((*p & 0x0f) != 0) { |
421 | unsigned short crc; | 457 | /* Configuration Command (kissparms(1). |
458 | * Protocol spec says: never append CRC. | ||
459 | * This fixes a very old bug in the linux | ||
460 | * kiss driver. -- dl9sau */ | ||
461 | switch (*p & 0xff) { | ||
462 | case 0x85: | ||
463 | /* command from userspace especially for us, | ||
464 | * not for delivery to the tnc */ | ||
465 | if (len > 1) { | ||
466 | int cmd = (p[1] & 0xff); | ||
467 | switch(cmd) { | ||
468 | case 3: | ||
469 | ax->crcmode = CRC_MODE_SMACK; | ||
470 | break; | ||
471 | case 2: | ||
472 | ax->crcmode = CRC_MODE_FLEX; | ||
473 | break; | ||
474 | case 1: | ||
475 | ax->crcmode = CRC_MODE_NONE; | ||
476 | break; | ||
477 | case 0: | ||
478 | default: | ||
479 | ax->crcmode = CRC_MODE_SMACK_TEST; | ||
480 | cmd = 0; | ||
481 | } | ||
482 | ax->crcauto = (cmd ? 0 : 1); | ||
483 | printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); | ||
484 | } | ||
485 | spin_unlock_bh(&ax->buflock); | ||
486 | netif_start_queue(dev); | ||
422 | 487 | ||
423 | case CRC_MODE_FLEX: | 488 | return; |
424 | *p |= 0x20; | 489 | default: |
425 | crc = calc_crc_flex(p, len); | 490 | count = kiss_esc(p, (unsigned char *)ax->xbuff, len); |
426 | count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); | 491 | } |
427 | break; | 492 | } else { |
493 | unsigned short crc; | ||
494 | switch (ax->crcmode) { | ||
495 | case CRC_MODE_SMACK_TEST: | ||
496 | ax->crcmode = CRC_MODE_FLEX_TEST; | ||
497 | printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name); | ||
498 | // fall through | ||
499 | case CRC_MODE_SMACK: | ||
500 | *p |= 0x80; | ||
501 | crc = swab16(crc16(0, p, len)); | ||
502 | count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); | ||
503 | break; | ||
504 | case CRC_MODE_FLEX_TEST: | ||
505 | ax->crcmode = CRC_MODE_NONE; | ||
506 | printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name); | ||
507 | // fall through | ||
508 | case CRC_MODE_FLEX: | ||
509 | *p |= 0x20; | ||
510 | crc = calc_crc_flex(p, len); | ||
511 | count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); | ||
512 | break; | ||
513 | |||
514 | default: | ||
515 | count = kiss_esc(p, (unsigned char *)ax->xbuff, len); | ||
516 | } | ||
517 | } | ||
428 | 518 | ||
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); | 519 | set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); |
435 | actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); | 520 | actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); |
436 | ax->stats.tx_packets++; | 521 | ax->stats.tx_packets++; |
@@ -439,8 +524,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) | |||
439 | ax->dev->trans_start = jiffies; | 524 | ax->dev->trans_start = jiffies; |
440 | ax->xleft = count - actual; | 525 | ax->xleft = count - actual; |
441 | ax->xhead = ax->xbuff + actual; | 526 | ax->xhead = ax->xbuff + actual; |
442 | |||
443 | spin_unlock_bh(&ax->buflock); | ||
444 | } | 527 | } |
445 | 528 | ||
446 | /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ | 529 | /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ |
@@ -622,7 +705,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 | 705 | * 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. | 706 | * use a single global rwlock for all ttys in ppp line discipline. |
624 | */ | 707 | */ |
625 | static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; | 708 | static DEFINE_RWLOCK(disc_data_lock); |
626 | 709 | ||
627 | static struct mkiss *mkiss_get(struct tty_struct *tty) | 710 | static struct mkiss *mkiss_get(struct tty_struct *tty) |
628 | { | 711 | { |
@@ -643,6 +726,8 @@ static void mkiss_put(struct mkiss *ax) | |||
643 | up(&ax->dead_sem); | 726 | up(&ax->dead_sem); |
644 | } | 727 | } |
645 | 728 | ||
729 | static int crc_force = 0; /* Can be overridden with insmod */ | ||
730 | |||
646 | static int mkiss_open(struct tty_struct *tty) | 731 | static int mkiss_open(struct tty_struct *tty) |
647 | { | 732 | { |
648 | struct net_device *dev; | 733 | struct net_device *dev; |
@@ -682,6 +767,33 @@ static int mkiss_open(struct tty_struct *tty) | |||
682 | if (register_netdev(dev)) | 767 | if (register_netdev(dev)) |
683 | goto out_free_buffers; | 768 | goto out_free_buffers; |
684 | 769 | ||
770 | /* after register_netdev() - because else printk smashes the kernel */ | ||
771 | switch (crc_force) { | ||
772 | case 3: | ||
773 | ax->crcmode = CRC_MODE_SMACK; | ||
774 | printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n", | ||
775 | ax->dev->name); | ||
776 | break; | ||
777 | case 2: | ||
778 | ax->crcmode = CRC_MODE_FLEX; | ||
779 | printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n", | ||
780 | ax->dev->name); | ||
781 | break; | ||
782 | case 1: | ||
783 | ax->crcmode = CRC_MODE_NONE; | ||
784 | printk(KERN_INFO "mkiss: %s: crc mode disabled.\n", | ||
785 | ax->dev->name); | ||
786 | break; | ||
787 | case 0: | ||
788 | /* fall through */ | ||
789 | default: | ||
790 | crc_force = 0; | ||
791 | printk(KERN_INFO "mkiss: %s: crc mode is auto.\n", | ||
792 | ax->dev->name); | ||
793 | ax->crcmode = CRC_MODE_SMACK_TEST; | ||
794 | } | ||
795 | ax->crcauto = (crc_force ? 0 : 1); | ||
796 | |||
685 | netif_start_queue(dev); | 797 | netif_start_queue(dev); |
686 | 798 | ||
687 | /* Done. We have linked the TTY line to a channel. */ | 799 | /* Done. We have linked the TTY line to a channel. */ |
@@ -765,7 +877,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, | |||
765 | 877 | ||
766 | case SIOCSIFHWADDR: { | 878 | case SIOCSIFHWADDR: { |
767 | char addr[AX25_ADDR_LEN]; | 879 | char addr[AX25_ADDR_LEN]; |
768 | printk(KERN_INFO "In SIOCSIFHWADDR"); | ||
769 | 880 | ||
770 | if (copy_from_user(&addr, | 881 | if (copy_from_user(&addr, |
771 | (void __user *) arg, AX25_ADDR_LEN)) { | 882 | (void __user *) arg, AX25_ADDR_LEN)) { |
@@ -864,6 +975,7 @@ out: | |||
864 | } | 975 | } |
865 | 976 | ||
866 | static struct tty_ldisc ax_ldisc = { | 977 | static struct tty_ldisc ax_ldisc = { |
978 | .owner = THIS_MODULE, | ||
867 | .magic = TTY_LDISC_MAGIC, | 979 | .magic = TTY_LDISC_MAGIC, |
868 | .name = "mkiss", | 980 | .name = "mkiss", |
869 | .open = mkiss_open, | 981 | .open = mkiss_open, |
@@ -904,6 +1016,8 @@ static void __exit mkiss_exit_driver(void) | |||
904 | 1016 | ||
905 | MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); | 1017 | MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); |
906 | MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); | 1018 | MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); |
1019 | MODULE_PARM(crc_force, "i"); | ||
1020 | MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); | ||
907 | MODULE_LICENSE("GPL"); | 1021 | MODULE_LICENSE("GPL"); |
908 | MODULE_ALIAS_LDISC(N_AX25); | 1022 | MODULE_ALIAS_LDISC(N_AX25); |
909 | 1023 | ||