From: Ralf Baechle DL5RB <ralf@linux-mips.org>
To: linux-hams@vger.kernel.org
Subject: Another 6pack patch
Date: Tue, 2 Nov 2004 21:31:07 +0100 [thread overview]
Message-ID: <20041102203107.GA25455@linux-mips.org> (raw)
Below another 6pack patch which I've got sitting in my repository for a
while already. I've got one positive report about it so far but would
like to give a little more testing before sending this upstream. The
patch does:
o Update my callsign
o Cleanup the internal for synchronization with a 6pack TNC a little bit
so it won't result in heaps and piles of messages in syslogs as it used
to do.
o Does paranoia checks for the maximum allowable packet size on transmit.
There was a slight chance this might have resulted in a crash in just
the right configuration.
o Verifies the address family for the SIOCSIFHWADDR network interface
ioctl.
o Tries to do proper locking so nothing will access dev->dev_addr in
midflight while changing the layer 2 address.
o Uses an intermediate buffer for the SIOCSIFHWADDR ioctl so an error in
copy_from_user can't result in a half-modified MAC address.
o Swaps the arguments of decode_prio_command, decode_std_command and
decode_data such that for consistency the struct sixpack pointer will be
the first argument like everywhere else.
73 de DL5RB op Ralf
--
Loc. JN47BS / CQ 14 / ITU 28 / DOK A21
--- drivers/net/hamradio/6pack.c 2004-10-25 17:07:35.000000000 +0200
+++ drivers/net/hamradio/6pack.c 2004-11-02 19:51:04.738359534 +0100
@@ -4,7 +4,7 @@
* kernel's AX.25 protocol layers.
*
* Authors: Andreas Könsgen <ajk@iehk.rwth-aachen.de>
- * Ralf Baechle DO1GRB <ralf@linux-mips.org>
+ * Ralf Baechle DL5RB <ralf@linux-mips.org>
*
* Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
*
@@ -119,11 +119,10 @@
unsigned char status1;
unsigned char status2;
unsigned char tx_enable;
- unsigned char tnc_ok;
+ unsigned char tnc_state;
struct timer_list tx_t;
struct timer_list resync_t;
-
atomic_t refcnt;
struct semaphore dead_sem;
spinlock_t lock;
@@ -134,7 +133,6 @@
static void sp_start_tx_timer(struct sixpack *);
static void sixpack_decode(struct sixpack *, unsigned char[], int);
static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
-static int sixpack_init(struct net_device *dev);
/*
* perform the persistence/slottime algorithm for CSMA access. If the
@@ -187,6 +185,11 @@
goto out_drop;
}
+ if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
+ msg = "oversized transmit packet!";
+ goto out_drop;
+ }
+
if (p[0] > 5) {
msg = "invalid KISS command";
goto out_drop;
@@ -249,8 +252,8 @@
out_drop:
sp->stats.tx_dropped++;
netif_start_queue(sp->dev);
- printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
- return;
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
}
/* Encapsulate an IP datagram and kick it into a TTY queue. */
@@ -313,10 +316,20 @@
return &sp->stats;
}
-static int sp_set_dev_mac_address(struct net_device *dev, void *addr)
+static int sp_set_mac_address(struct net_device *dev, void *addr)
{
- struct sockaddr *sa = addr;
- memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
+ struct sockaddr_ax25 *sa = addr;
+
+ if (sa->sax25_family != AF_AX25)
+ return -EINVAL;
+
+ if (!sa->sax25_ndigis)
+ return -EINVAL;
+
+ spin_lock_irq(&dev->xmit_lock);
+ memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
+ spin_unlock_irq(&dev->xmit_lock);
+
return 0;
}
@@ -337,7 +350,6 @@
{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
/* Finish setting up the DEVICE info. */
- dev->init = sixpack_init;
dev->mtu = SIXP_MTU;
dev->hard_start_xmit = sp_xmit;
dev->open = sp_open_dev;
@@ -345,7 +357,7 @@
dev->stop = sp_close;
dev->hard_header = sp_header;
dev->get_stats = sp_get_stats;
- dev->set_mac_address = sp_set_dev_mac_address;
+ dev->set_mac_address = sp_set_mac_address;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25;
@@ -359,51 +371,9 @@
SET_MODULE_OWNER(dev);
- /* New-style flags. */
dev->flags = 0;
}
-/* Find a free 6pack channel, and link in this `tty' line. */
-static inline struct sixpack *sp_alloc(void)
-{
- struct sixpack *sp = NULL;
- struct net_device *dev = NULL;
-
- dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
- if (!dev)
- return NULL;
-
- sp = netdev_priv(dev);
- sp->dev = dev;
-
- spin_lock_init(&sp->lock);
-
- if (register_netdev(dev))
- goto out_free;
-
- return sp;
-
-out_free:
- printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n");
-
- free_netdev(dev);
-
- return NULL;
-}
-
-/* Free a 6pack channel. */
-static inline void sp_free(struct sixpack *sp)
-{
- void * tmp;
-
- /* Free all 6pack frame buffers. */
- if ((tmp = xchg(&sp->rbuff, NULL)) != NULL)
- kfree(tmp);
- if ((tmp = xchg(&sp->xbuff, NULL)) != NULL)
- kfree(tmp);
-}
-
-
/* Send one completely decapsulated IP datagram to the IP layer. */
/*
@@ -482,6 +452,8 @@
struct sixpack *sp = sp_get(tty);
int actual;
+ if (!sp)
+ return;
if (sp->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
@@ -492,7 +464,7 @@
goto out;
}
- if (sp->tx_enable == 1) {
+ if (sp->tx_enable) {
actual = tty->driver->write(tty, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
@@ -504,80 +476,6 @@
/* ----------------------------------------------------------------------- */
-/* Open the low-level part of the 6pack channel. */
-static int sp_open(struct net_device *dev)
-{
- struct sixpack *sp = netdev_priv(dev);
- char *rbuff, *xbuff = NULL;
- int err = -ENOBUFS;
- unsigned long len;
-
- /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */
-
- len = dev->mtu * 2;
-
- rbuff = kmalloc(len + 4, GFP_KERNEL);
- if (rbuff == NULL)
- goto err_exit;
-
- xbuff = kmalloc(len + 4, GFP_KERNEL);
- if (xbuff == NULL)
- goto err_exit;
-
- spin_lock_bh(&sp->lock);
-
- if (sp->tty == NULL)
- return -ENODEV;
-
- /*
- * Allocate the 6pack frame buffers:
- *
- * rbuff Receive buffer.
- * xbuff Transmit buffer.
- */
-
- rbuff = xchg(&sp->rbuff, rbuff);
- xbuff = xchg(&sp->xbuff, xbuff);
-
- sp->mtu = AX25_MTU + 73;
- sp->buffsize = len;
- sp->rcount = 0;
- sp->rx_count = 0;
- sp->rx_count_cooked = 0;
- sp->xleft = 0;
-
- sp->flags = 0; /* Clear ESCAPE & ERROR flags */
-
- sp->duplex = 0;
- sp->tx_delay = SIXP_TXDELAY;
- sp->persistence = SIXP_PERSIST;
- sp->slottime = SIXP_SLOTTIME;
- sp->led_state = 0x60;
- sp->status = 1;
- sp->status1 = 1;
- sp->status2 = 0;
- sp->tnc_ok = 0;
- sp->tx_enable = 0;
-
- netif_start_queue(dev);
-
- init_timer(&sp->tx_t);
- init_timer(&sp->resync_t);
-
- spin_unlock_bh(&sp->lock);
-
- err = 0;
-
-err_exit:
- if (xbuff)
- kfree(xbuff);
- if (rbuff)
- kfree(rbuff);
-
- return err;
-}
-
-
static int sixpack_receive_room(struct tty_struct *tty)
{
return 65536; /* We can handle an infinite amount of data. :-) */
@@ -629,14 +527,45 @@
* decode_prio_command
*/
+#define TNC_UNINITIALIZED 0
+#define TNC_UNSYNC_STARTUP 1
+#define TNC_UNSYNCED 2
+#define TNC_IN_SYNC 3
+
+static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
+{
+ char *msg;
+
+ switch (new_tnc_state) {
+ default: /* gcc oh piece-o-crap ... */
+ case TNC_UNSYNC_STARTUP:
+ msg = "Synchronizing with TNC";
+ break;
+ case TNC_UNSYNCED:
+ msg = "Lost synchronization with TNC\n";
+ break;
+ case TNC_IN_SYNC:
+ msg = "Found TNC";
+ break;
+ }
+
+ sp->tnc_state = new_tnc_state;
+ printk(KERN_INFO "%s: %s\n", sp->dev->name, msg);
+}
+
+static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
+{
+ int old_tnc_state = sp->tnc_state;
+
+ if (old_tnc_state != new_tnc_state)
+ __tnc_set_sync_state(sp, new_tnc_state);
+}
+
static void resync_tnc(unsigned long channel)
{
struct sixpack *sp = (struct sixpack *) channel;
- struct net_device *dev = sp->dev;
static char resync_cmd = 0xe8;
- printk(KERN_INFO "%s: resyncing TNC\n", dev->name);
-
/* clear any data that might have been received */
sp->rx_count = 0;
@@ -647,7 +576,6 @@
sp->status = 1;
sp->status1 = 1;
sp->status2 = 0;
- sp->tnc_ok = 0;
/* resync the TNC */
@@ -659,9 +587,9 @@
/* Start resync timer again -- the TNC might be still absent */
del_timer(&sp->resync_t);
- sp->resync_t.data = (unsigned long) sp;
- sp->resync_t.function = resync_tnc;
- sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
+ sp->resync_t.data = (unsigned long) sp;
+ sp->resync_t.function = resync_tnc;
+ sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
add_timer(&sp->resync_t);
}
@@ -669,6 +597,8 @@
{
unsigned char inbyte = 0xe8;
+ tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
+
sp->tty->driver->write(sp->tty, &inbyte, 1);
del_timer(&sp->resync_t);
@@ -689,31 +619,91 @@
*/
static int sixpack_open(struct tty_struct *tty)
{
+ char *rbuff = NULL, *xbuff = NULL;
+ struct net_device *dev;
struct sixpack *sp;
+ unsigned long len;
int err = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- sp = sp_alloc();
- if (!sp) {
+ dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
+ if (!dev) {
err = -ENOMEM;
goto out;
}
- sp->tty = tty;
+ sp = netdev_priv(dev);
+ sp->dev = dev;
+
+ spin_lock_init(&sp->lock);
atomic_set(&sp->refcnt, 1);
init_MUTEX_LOCKED(&sp->dead_sem);
- /* Perform the low-level 6pack initialization. */
- if ((err = sp_open(sp->dev)))
- goto out;
+ /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */
+
+ len = dev->mtu * 2;
+
+ rbuff = kmalloc(len + 4, GFP_KERNEL);
+ xbuff = kmalloc(len + 4, GFP_KERNEL);
+
+ if (rbuff == NULL || xbuff == NULL) {
+ err = -ENOBUFS;
+ goto out_free;
+ }
+
+ spin_lock_bh(&sp->lock);
+
+ sp->tty = tty;
+
+ sp->rbuff = rbuff;
+ sp->xbuff = xbuff;
+
+ sp->mtu = AX25_MTU + 73;
+ sp->buffsize = len;
+ sp->rcount = 0;
+ sp->rx_count = 0;
+ sp->rx_count_cooked = 0;
+ sp->xleft = 0;
+
+ sp->flags = 0; /* Clear ESCAPE & ERROR flags */
+
+ sp->duplex = 0;
+ sp->tx_delay = SIXP_TXDELAY;
+ sp->persistence = SIXP_PERSIST;
+ sp->slottime = SIXP_SLOTTIME;
+ sp->led_state = 0x60;
+ sp->status = 1;
+ sp->status1 = 1;
+ sp->status2 = 0;
+ sp->tx_enable = 0;
+
+ netif_start_queue(dev);
+
+ init_timer(&sp->tx_t);
+ init_timer(&sp->resync_t);
+
+ spin_unlock_bh(&sp->lock);
/* Done. We have linked the TTY line to a channel. */
tty->disc_data = sp;
+ /* Now we're ready to register. */
+ if (register_netdev(dev))
+ goto out_free;
+
tnc_init(sp);
+ return 0;
+
+out_free:
+ kfree(xbuff);
+ kfree(rbuff);
+
+ if (dev)
+ free_netdev(dev);
+
out:
return err;
}
@@ -727,7 +717,7 @@
*/
static void sixpack_close(struct tty_struct *tty)
{
- struct sixpack *sp = (struct sixpack *) tty->disc_data;
+ struct sixpack *sp;
write_lock(&disc_data_lock);
sp = tty->disc_data;
@@ -743,16 +733,14 @@
if (!atomic_dec_and_test(&sp->refcnt))
down(&sp->dead_sem);
+ unregister_netdev(sp->dev);
+
del_timer(&sp->tx_t);
del_timer(&sp->resync_t);
- sp_free(sp);
- unregister_netdev(sp->dev);
-}
-
-static int sp_set_mac_address(struct net_device *dev, void __user *addr)
-{
- return copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN) ? -EFAULT : 0;
+ /* Free all 6pack frame buffers. */
+ kfree(sp->rbuff);
+ kfree(sp->xbuff);
}
/* Perform I/O control on an active 6pack channel. */
@@ -760,6 +748,7 @@
unsigned int cmd, unsigned long arg)
{
struct sixpack *sp = sp_get(tty);
+ struct net_device *dev = sp->dev;
unsigned int tmp, err;
if (!sp)
@@ -767,8 +756,8 @@
switch(cmd) {
case SIOCGIFNAME:
- err = copy_to_user((void __user *) arg, sp->dev->name,
- strlen(sp->dev->name) + 1) ? -EFAULT : 0;
+ err = copy_to_user((void *) arg, dev->name,
+ strlen(dev->name) + 1) ? -EFAULT : 0;
break;
case SIOCGIFENCAP:
@@ -782,16 +771,30 @@
}
sp->mode = tmp;
- sp->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */
- sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
- sp->dev->type = ARPHRD_AX25;
+ dev->addr_len = AX25_ADDR_LEN;
+ dev->hard_header_len = AX25_KISS_HEADER_LEN +
+ AX25_MAX_HEADER_LEN + 3;
+ dev->type = ARPHRD_AX25;
err = 0;
break;
- case SIOCSIFHWADDR:
- err = sp_set_mac_address(sp->dev, (void __user *) arg);
+ case SIOCSIFHWADDR: {
+ char addr[AX25_ADDR_LEN];
+
+ if (copy_from_user(&addr,
+ (void __user *) arg, AX25_ADDR_LEN)) {
+ err = -EFAULT;
+ break;
+ }
+
+ spin_lock_irq(&dev->xmit_lock);
+ memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
+ spin_unlock_irq(&dev->xmit_lock);
+
+ err = 0;
break;
+ }
/* Allow stty to read, but not set, the serial port */
case TCGETS:
@@ -800,7 +803,7 @@
break;
default:
- return -ENOIOCTLCMD;
+ err = -ENOIOCTLCMD;
}
sp_put(sp);
@@ -808,7 +811,6 @@
return err;
}
-/* Fill in our line protocol discipline */
static struct tty_ldisc sp_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
@@ -823,8 +825,10 @@
/* Initialize 6pack control device -- register 6pack line discipline */
-static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
-static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n";
+static char msg_banner[] __initdata = KERN_INFO \
+ "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
+static char msg_regfail[] __initdata = KERN_ERR \
+ "6pack: can't register line discipline (err = %d)\n";
static int __init sixpack_init_driver(void)
{
@@ -839,7 +843,8 @@
return status;
}
-static const char msg_unregfail[] __exitdata = KERN_ERR "6pack: can't unregister line discipline (err = %d)\n";
+static const char msg_unregfail[] __exitdata = KERN_ERR \
+ "6pack: can't unregister line discipline (err = %d)\n";
static void __exit sixpack_exit_driver(void)
{
@@ -849,22 +854,6 @@
printk(msg_unregfail, ret);
}
-/* Initialize the 6pack driver. Called by DDI. */
-static int sixpack_init(struct net_device *dev)
-{
- struct sixpack *sp = netdev_priv(dev);
-
- if (sp == NULL) /* Allocation failed ?? */
- return -ENODEV;
-
- /* Set up the "6pack Control Block". (And clear statistics) */
-
- memset(sp, 0, sizeof (struct sixpack));
- sp->dev = dev;
-
- return 0;
-}
-
/* encode an AX.25 packet into 6pack */
static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
@@ -905,7 +894,7 @@
/* decode 4 sixpack-encoded bytes into 3 data bytes */
-static void decode_data(unsigned char inbyte, struct sixpack *sp)
+static void decode_data(struct sixpack *sp, unsigned char inbyte)
{
unsigned char *buf;
@@ -927,7 +916,7 @@
/* identify and execute a 6pack priority command byte */
-static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
+static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
{
unsigned char channel;
int actual;
@@ -971,11 +960,11 @@
/* if the state byte has been received, the TNC is present,
so the resync timer can be reset. */
- if (sp->tnc_ok == 1) {
+ if (sp->tnc_state == TNC_IN_SYNC) {
del_timer(&sp->resync_t);
- sp->resync_t.data = (unsigned long) sp;
- sp->resync_t.function = resync_tnc;
- sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT;
+ sp->resync_t.data = (unsigned long) sp;
+ sp->resync_t.function = resync_tnc;
+ sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT;
add_timer(&sp->resync_t);
}
@@ -984,7 +973,7 @@
/* identify and execute a standard 6pack command byte */
-static void decode_std_command(unsigned char cmd, struct sixpack *sp)
+static void decode_std_command(struct sixpack *sp, unsigned char cmd)
{
unsigned char checksum = 0, rest = 0, channel;
short i;
@@ -1005,7 +994,7 @@
rest = sp->rx_count;
if (rest != 0)
for (i = rest; i <= 3; i++)
- decode_data(0, sp);
+ decode_data(sp, 0);
if (rest == 2)
sp->rx_count_cooked -= 2;
else if (rest == 3)
@@ -1033,7 +1022,7 @@
/* decode a 6pack packet */
static void
-sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count)
+sixpack_decode(struct sixpack *sp, unsigned char *pre_rbuff, int count)
{
unsigned char inbyte;
int count1;
@@ -1041,16 +1030,15 @@
for (count1 = 0; count1 < count; count1++) {
inbyte = pre_rbuff[count1];
if (inbyte == SIXP_FOUND_TNC) {
- printk(KERN_INFO "6pack: TNC found.\n");
- sp->tnc_ok = 1;
+ tnc_set_sync_state(sp, TNC_IN_SYNC);
del_timer(&sp->resync_t);
}
if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
- decode_prio_command(inbyte, sp);
+ decode_prio_command(sp, inbyte);
else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
- decode_std_command(inbyte, sp);
+ decode_std_command(sp, inbyte);
else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
- decode_data(inbyte, sp);
+ decode_data(sp, inbyte);
}
}
-
To unsubscribe from this list: send the line "unsubscribe linux-hams" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next reply other threads:[~2004-11-02 20:31 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-02 20:31 Ralf Baechle DL5RB [this message]
2004-11-03 4:43 ` AX.25 cb lookup patch Ralf Baechle DL5RB
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20041102203107.GA25455@linux-mips.org \
--to=ralf@linux-mips.org \
--cc=linux-hams@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.