[PATCH] SMACK support for mkiss
SMACK (Stuttgart Modified Amateurradio CRC KISS) is a KISS variant that uses CRC16 checksums to secure data transfers between the modem and host. It's also used to communicate over a pty to applications such as Wampes. Patches for Linux 2.4 by Thomas Osterried DL9SAU, upgraded to the latest mkiss 2.6 mkiss driver by me. Signed-off-by: Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de> Signed-off-by: Ralf Baechle DL5RB <ralf@linux-mips.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
bc0a743860
commit
5793f4be23
2 changed files with 149 additions and 32 deletions
|
@ -1,6 +1,7 @@
|
||||||
config MKISS
|
config MKISS
|
||||||
tristate "Serial port KISS driver"
|
tristate "Serial port KISS driver"
|
||||||
depends on AX25
|
depends on AX25
|
||||||
|
select CRC16
|
||||||
---help---
|
---help---
|
||||||
KISS is a protocol used for the exchange of data between a computer
|
KISS is a protocol used for the exchange of data between a computer
|
||||||
and a Terminal Node Controller (a small embedded system commonly
|
and a Terminal Node Controller (a small embedded system commonly
|
||||||
|
|
|
@ -14,13 +14,14 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
|
* Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
|
||||||
* Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
|
* Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
|
||||||
|
* Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/crc16.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
@ -39,11 +40,6 @@
|
||||||
|
|
||||||
#include <net/ax25.h>
|
#include <net/ax25.h>
|
||||||
|
|
||||||
#ifdef CONFIG_INET
|
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/tcp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define AX_MTU 236
|
#define AX_MTU 236
|
||||||
|
|
||||||
/* SLIP/KISS protocol characters. */
|
/* SLIP/KISS protocol characters. */
|
||||||
|
@ -80,9 +76,13 @@ struct mkiss {
|
||||||
|
|
||||||
int mode;
|
int mode;
|
||||||
int crcmode; /* MW: for FlexNet, SMACK etc. */
|
int crcmode; /* MW: for FlexNet, SMACK etc. */
|
||||||
#define CRC_MODE_NONE 0
|
int crcauto; /* CRC auto mode */
|
||||||
#define CRC_MODE_FLEX 1
|
|
||||||
#define CRC_MODE_SMACK 2
|
#define CRC_MODE_NONE 0
|
||||||
|
#define CRC_MODE_FLEX 1
|
||||||
|
#define CRC_MODE_SMACK 2
|
||||||
|
#define CRC_MODE_FLEX_TEST 3
|
||||||
|
#define CRC_MODE_SMACK_TEST 4
|
||||||
|
|
||||||
atomic_t refcnt;
|
atomic_t refcnt;
|
||||||
struct semaphore dead_sem;
|
struct semaphore dead_sem;
|
||||||
|
@ -151,6 +151,21 @@ static int check_crc_flex(unsigned char *cp, int size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_crc_16(unsigned char *cp, int size)
|
||||||
|
{
|
||||||
|
unsigned short crc = 0x0000;
|
||||||
|
|
||||||
|
if (size < 3)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
crc = crc16(0, cp, size);
|
||||||
|
|
||||||
|
if (crc != 0x0000)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Standard encapsulation
|
* Standard encapsulation
|
||||||
*/
|
*/
|
||||||
|
@ -237,19 +252,42 @@ static void ax_bump(struct mkiss *ax)
|
||||||
|
|
||||||
spin_lock_bh(&ax->buflock);
|
spin_lock_bh(&ax->buflock);
|
||||||
if (ax->rbuff[0] > 0x0f) {
|
if (ax->rbuff[0] > 0x0f) {
|
||||||
if (ax->rbuff[0] & 0x20) {
|
if (ax->rbuff[0] & 0x80) {
|
||||||
ax->crcmode = CRC_MODE_FLEX;
|
if (check_crc_16(ax->rbuff, ax->rcount) < 0) {
|
||||||
if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
|
ax->stats.rx_errors++;
|
||||||
ax->stats.rx_errors++;
|
spin_unlock_bh(&ax->buflock);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) {
|
||||||
|
printk(KERN_INFO
|
||||||
|
"mkiss: %s: Switchting to crc-smack\n",
|
||||||
|
ax->dev->name);
|
||||||
|
ax->crcmode = CRC_MODE_SMACK;
|
||||||
|
}
|
||||||
ax->rcount -= 2;
|
ax->rcount -= 2;
|
||||||
/* dl9sau bugfix: the trailling two bytes flexnet crc
|
*ax->rbuff &= ~0x80;
|
||||||
* will not be passed to the kernel. thus we have
|
} else if (ax->rbuff[0] & 0x20) {
|
||||||
* to correct the kissparm signature, because it
|
if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
|
||||||
* indicates a crc but there's none
|
ax->stats.rx_errors++;
|
||||||
|
spin_unlock_bh(&ax->buflock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
|
||||||
|
printk(KERN_INFO
|
||||||
|
"mkiss: %s: Switchting to crc-flexnet\n",
|
||||||
|
ax->dev->name);
|
||||||
|
ax->crcmode = CRC_MODE_FLEX;
|
||||||
|
}
|
||||||
|
ax->rcount -= 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dl9sau bugfix: the trailling two bytes flexnet crc
|
||||||
|
* will not be passed to the kernel. thus we have to
|
||||||
|
* correct the kissparm signature, because it indicates
|
||||||
|
* a crc but there's none
|
||||||
*/
|
*/
|
||||||
*ax->rbuff &= ~0x20;
|
*ax->rbuff &= ~0x20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&ax->buflock);
|
spin_unlock_bh(&ax->buflock);
|
||||||
|
@ -417,20 +455,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
|
||||||
p = icp;
|
p = icp;
|
||||||
|
|
||||||
spin_lock_bh(&ax->buflock);
|
spin_lock_bh(&ax->buflock);
|
||||||
switch (ax->crcmode) {
|
if ((*p & 0x0f) != 0) {
|
||||||
unsigned short crc;
|
/* Configuration Command (kissparms(1).
|
||||||
|
* Protocol spec says: never append CRC.
|
||||||
|
* This fixes a very old bug in the linux
|
||||||
|
* kiss driver. -- dl9sau */
|
||||||
|
switch (*p & 0xff) {
|
||||||
|
case 0x85:
|
||||||
|
/* command from userspace especially for us,
|
||||||
|
* not for delivery to the tnc */
|
||||||
|
if (len > 1) {
|
||||||
|
int cmd = (p[1] & 0xff);
|
||||||
|
switch(cmd) {
|
||||||
|
case 3:
|
||||||
|
ax->crcmode = CRC_MODE_SMACK;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ax->crcmode = CRC_MODE_FLEX;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ax->crcmode = CRC_MODE_NONE;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
ax->crcmode = CRC_MODE_SMACK_TEST;
|
||||||
|
cmd = 0;
|
||||||
|
}
|
||||||
|
ax->crcauto = (cmd ? 0 : 1);
|
||||||
|
printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&ax->buflock);
|
||||||
|
netif_start_queue(dev);
|
||||||
|
|
||||||
case CRC_MODE_FLEX:
|
return;
|
||||||
*p |= 0x20;
|
default:
|
||||||
crc = calc_crc_flex(p, len);
|
count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
|
||||||
count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
|
}
|
||||||
break;
|
} else {
|
||||||
|
unsigned short crc;
|
||||||
|
switch (ax->crcmode) {
|
||||||
|
case CRC_MODE_SMACK_TEST:
|
||||||
|
ax->crcmode = CRC_MODE_FLEX_TEST;
|
||||||
|
printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name);
|
||||||
|
// fall through
|
||||||
|
case CRC_MODE_SMACK:
|
||||||
|
*p |= 0x80;
|
||||||
|
crc = swab16(crc16(0, p, len));
|
||||||
|
count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
|
||||||
|
break;
|
||||||
|
case CRC_MODE_FLEX_TEST:
|
||||||
|
ax->crcmode = CRC_MODE_NONE;
|
||||||
|
printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
|
||||||
|
// fall through
|
||||||
|
case CRC_MODE_FLEX:
|
||||||
|
*p |= 0x20;
|
||||||
|
crc = calc_crc_flex(p, len);
|
||||||
|
count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
|
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
|
||||||
actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
|
actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
|
||||||
ax->stats.tx_packets++;
|
ax->stats.tx_packets++;
|
||||||
|
@ -439,8 +526,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
|
||||||
ax->dev->trans_start = jiffies;
|
ax->dev->trans_start = jiffies;
|
||||||
ax->xleft = count - actual;
|
ax->xleft = count - actual;
|
||||||
ax->xhead = ax->xbuff + actual;
|
ax->xhead = ax->xbuff + actual;
|
||||||
|
|
||||||
spin_unlock_bh(&ax->buflock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encapsulate an AX.25 packet and kick it into a TTY queue. */
|
/* Encapsulate an AX.25 packet and kick it into a TTY queue. */
|
||||||
|
@ -643,6 +728,8 @@ static void mkiss_put(struct mkiss *ax)
|
||||||
up(&ax->dead_sem);
|
up(&ax->dead_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int crc_force = 0; /* Can be overridden with insmod */
|
||||||
|
|
||||||
static int mkiss_open(struct tty_struct *tty)
|
static int mkiss_open(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
@ -682,6 +769,33 @@ static int mkiss_open(struct tty_struct *tty)
|
||||||
if (register_netdev(dev))
|
if (register_netdev(dev))
|
||||||
goto out_free_buffers;
|
goto out_free_buffers;
|
||||||
|
|
||||||
|
/* after register_netdev() - because else printk smashes the kernel */
|
||||||
|
switch (crc_force) {
|
||||||
|
case 3:
|
||||||
|
ax->crcmode = CRC_MODE_SMACK;
|
||||||
|
printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n",
|
||||||
|
ax->dev->name);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ax->crcmode = CRC_MODE_FLEX;
|
||||||
|
printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n",
|
||||||
|
ax->dev->name);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ax->crcmode = CRC_MODE_NONE;
|
||||||
|
printk(KERN_INFO "mkiss: %s: crc mode disabled.\n",
|
||||||
|
ax->dev->name);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
crc_force = 0;
|
||||||
|
printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
|
||||||
|
ax->dev->name);
|
||||||
|
ax->crcmode = CRC_MODE_SMACK_TEST;
|
||||||
|
}
|
||||||
|
ax->crcauto = (crc_force ? 0 : 1);
|
||||||
|
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
|
|
||||||
/* Done. We have linked the TTY line to a channel. */
|
/* Done. We have linked the TTY line to a channel. */
|
||||||
|
@ -903,6 +1017,8 @@ static void __exit mkiss_exit_driver(void)
|
||||||
|
|
||||||
MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
|
MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
|
||||||
MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
|
MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
|
||||||
|
MODULE_PARM(crc_force, "i");
|
||||||
|
MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS_LDISC(N_AX25);
|
MODULE_ALIAS_LDISC(N_AX25);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue