summaryrefslogtreecommitdiff
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.c177
1 files changed, 60 insertions, 117 deletions
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 8e01c457015b..5f38a002bd9e 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -1,16 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
* Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
@@ -18,7 +7,7 @@
*/
#include <linux/module.h>
#include <linux/bitops.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/crc16.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -36,12 +25,14 @@
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/jiffies.h>
-#include <linux/compat.h>
+#include <linux/refcount.h>
#include <net/ax25.h>
#define AX_MTU 236
+/* some arch define END as assembly function ending, just undef it */
+#undef END
/* SLIP/KISS protocol characters. */
#define END 0300 /* indicates end of frame */
#define ESC 0333 /* indicates byte stuffing */
@@ -82,8 +73,8 @@ struct mkiss {
#define CRC_MODE_FLEX_TEST 3
#define CRC_MODE_SMACK_TEST 4
- atomic_t refcnt;
- struct semaphore dead_sem;
+ refcount_t refcnt;
+ struct completion dead;
};
/*---------------------------------------------------------------------------*/
@@ -218,7 +209,7 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
c = *s++;
else if (len > 1)
c = crc >> 8;
- else if (len > 0)
+ else
c = crc & 0xff;
len--;
@@ -287,7 +278,7 @@ static void ax_bump(struct mkiss *ax)
*/
*ax->rbuff &= ~0x20;
}
- }
+ }
count = ax->rcount;
@@ -299,7 +290,7 @@ static void ax_bump(struct mkiss *ax)
return;
}
- memcpy(skb_put(skb,count), ax->rbuff, count);
+ skb_put_data(skb, ax->rbuff, count);
skb->protocol = ax25_type_trans(skb, ax->dev);
netif_rx(skb);
ax->dev->stats.rx_packets++;
@@ -355,7 +346,7 @@ static int ax_set_mac_address(struct net_device *dev, void *addr)
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
- memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
+ __dev_addr_set(dev, &sa->sax25_call, AX25_ADDR_LEN);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
@@ -441,7 +432,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
ax_changedmtu(ax);
if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */
- len = ax->mtu;
printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name);
dev->stats.tx_dropped++;
netif_start_queue(dev);
@@ -478,7 +468,8 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
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);
+ printk(KERN_INFO "mkiss: %s: crc mode set to %d\n",
+ ax->dev->name, cmd);
}
spin_unlock_bh(&ax->buflock);
netif_start_queue(dev);
@@ -493,7 +484,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
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
+ fallthrough;
case CRC_MODE_SMACK:
*p |= 0x80;
crc = swab16(crc16(0, p, len));
@@ -502,7 +493,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
case CRC_MODE_FLEX_TEST:
ax->crcmode = CRC_MODE_NONE;
printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
- // fall through
+ fallthrough;
case CRC_MODE_FLEX:
*p |= 0x20;
crc = calc_crc_flex(p, len);
@@ -512,7 +503,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
default:
count = kiss_esc(p, ax->xbuff, len);
}
- }
+ }
spin_unlock_bh(&ax->buflock);
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
@@ -520,7 +511,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
dev->stats.tx_packets++;
dev->stats.tx_bytes += actual;
- ax->dev->trans_start = jiffies;
+ netif_trans_update(ax->dev);
ax->xleft = count - actual;
ax->xhead = ax->xbuff + actual;
}
@@ -530,6 +521,9 @@ static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mkiss *ax = netdev_priv(dev);
+ if (skb->protocol == htons(ETH_P_IP))
+ return ax25_ip_xmit(skb);
+
if (!netif_running(dev)) {
printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);
return NETDEV_TX_BUSY;
@@ -540,7 +534,7 @@ static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev)
* May be we must check transmitter timeout here ?
* 14 Oct 1994 Dmitry Gorodchanin.
*/
- if (time_before(jiffies, dev->trans_start + 20 * HZ)) {
+ if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ)) {
/* 20 sec timeout not reached */
return NETDEV_TX_BUSY;
}
@@ -555,11 +549,9 @@ static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* We were not busy, so we are now... :-) */
- if (skb != NULL) {
- netif_stop_queue(dev);
- ax_encaps(dev, skb->data, skb->len);
- kfree_skb(skb);
- }
+ netif_stop_queue(dev);
+ ax_encaps(dev, skb->data, skb->len);
+ kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -574,32 +566,6 @@ static int ax_open_dev(struct net_device *dev)
return 0;
}
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-
-/* Return the frame type ID */
-static int ax_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned len)
-{
-#ifdef CONFIG_INET
- if (type != ETH_P_AX25)
- return ax25_hard_header(skb, dev, type, daddr, saddr, len);
-#endif
- return 0;
-}
-
-
-static int ax_rebuild_header(struct sk_buff *skb)
-{
-#ifdef CONFIG_INET
- return ax25_rebuild_header(skb);
-#else
- return 0;
-#endif
-}
-
-#endif /* CONFIG_{AX25,AX25_MODULE} */
-
/* Open the low-level part of the AX25 channel. Easy! */
static int ax_open(struct net_device *dev)
{
@@ -663,11 +629,6 @@ static int ax_close(struct net_device *dev)
return 0;
}
-static const struct header_ops ax_header_ops = {
- .create = ax_header,
- .rebuild = ax_rebuild_header,
-};
-
static const struct net_device_ops ax_netdev_ops = {
.ndo_open = ax_open_dev,
.ndo_stop = ax_close,
@@ -679,16 +640,16 @@ static void ax_setup(struct net_device *dev)
{
/* Finish setting up the DEVICE info. */
dev->mtu = AX_MTU;
- dev->hard_header_len = 0;
- dev->addr_len = 0;
+ dev->hard_header_len = AX25_MAX_HEADER_LEN;
+ dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
- dev->header_ops = &ax_header_ops;
+ dev->header_ops = &ax25_header_ops;
dev->netdev_ops = &ax_netdev_ops;
memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
+ dev_addr_set(dev, (u8 *)&ax25_defaddr);
dev->flags = IFF_BROADCAST | IFF_MULTICAST;
}
@@ -710,7 +671,7 @@ static struct mkiss *mkiss_get(struct tty_struct *tty)
read_lock(&disc_data_lock);
ax = tty->disc_data;
if (ax)
- atomic_inc(&ax->refcnt);
+ refcount_inc(&ax->refcnt);
read_unlock(&disc_data_lock);
return ax;
@@ -718,8 +679,8 @@ static struct mkiss *mkiss_get(struct tty_struct *tty)
static void mkiss_put(struct mkiss *ax)
{
- if (atomic_dec_and_test(&ax->refcnt))
- up(&ax->dead_sem);
+ if (refcount_dec_and_test(&ax->refcnt))
+ complete(&ax->dead);
}
static int crc_force = 0; /* Can be overridden with insmod */
@@ -735,7 +696,8 @@ static int mkiss_open(struct tty_struct *tty)
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
- dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
+ dev = alloc_netdev(sizeof(struct mkiss), "ax%d", NET_NAME_UNKNOWN,
+ ax_setup);
if (!dev) {
err = -ENOMEM;
goto out;
@@ -745,8 +707,8 @@ static int mkiss_open(struct tty_struct *tty)
ax->dev = dev;
spin_lock_init(&ax->buflock);
- atomic_set(&ax->refcnt, 1);
- sema_init(&ax->dead_sem, 0);
+ refcount_set(&ax->refcnt, 1);
+ init_completion(&ax->dead);
ax->tty = tty;
tty->disc_data = ax;
@@ -758,11 +720,12 @@ static int mkiss_open(struct tty_struct *tty)
dev->type = ARPHRD_AX25;
/* Perform the low-level AX25 initialization. */
- if ((err = ax_open(ax->dev))) {
+ err = ax_open(ax->dev);
+ if (err)
goto out_free_netdev;
- }
- if (register_netdev(dev))
+ err = register_netdev(dev);
+ if (err)
goto out_free_buffers;
/* after register_netdev() - because else printk smashes the kernel */
@@ -783,7 +746,6 @@ static int mkiss_open(struct tty_struct *tty)
ax->dev->name);
break;
case 0:
- /* fall through */
default:
crc_force = 0;
printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
@@ -812,10 +774,10 @@ static void mkiss_close(struct tty_struct *tty)
{
struct mkiss *ax;
- write_lock_bh(&disc_data_lock);
+ write_lock_irq(&disc_data_lock);
ax = tty->disc_data;
tty->disc_data = NULL;
- write_unlock_bh(&disc_data_lock);
+ write_unlock_irq(&disc_data_lock);
if (!ax)
return;
@@ -824,21 +786,28 @@ static void mkiss_close(struct tty_struct *tty)
* We have now ensured that nobody can start using ap from now on, but
* we have to wait for all existing users to finish.
*/
- if (!atomic_dec_and_test(&ax->refcnt))
- down(&ax->dead_sem);
+ if (!refcount_dec_and_test(&ax->refcnt))
+ wait_for_completion(&ax->dead);
+ /*
+ * Halt the transmit queue so that a new transmit cannot scribble
+ * on our buffers
+ */
+ netif_stop_queue(ax->dev);
unregister_netdev(ax->dev);
- /* Free all AX25 frame buffers. */
+ /* Free all AX25 frame buffers after unreg. */
kfree(ax->rbuff);
kfree(ax->xbuff);
ax->tty = NULL;
+
+ free_netdev(ax->dev);
}
/* Perform I/O control on an active ax25 channel. */
-static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
{
struct mkiss *ax = mkiss_get(tty);
struct net_device *dev;
@@ -850,7 +819,7 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
dev = ax->dev;
switch (cmd) {
- case SIOCGIFNAME:
+ case SIOCGIFNAME:
err = copy_to_user((void __user *) arg, ax->dev->name,
strlen(ax->dev->name) + 1) ? -EFAULT : 0;
break;
@@ -884,7 +853,7 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
}
netif_tx_lock_bh(dev);
- memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
+ __dev_addr_set(dev, addr, AX25_ADDR_LEN);
netif_tx_unlock_bh(dev);
err = 0;
@@ -899,31 +868,14 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
return err;
}
-#ifdef CONFIG_COMPAT
-static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case SIOCGIFNAME:
- case SIOCGIFENCAP:
- case SIOCSIFENCAP:
- case SIOCSIFHWADDR:
- return mkiss_ioctl(tty, file, cmd,
- (unsigned long)compat_ptr(arg));
- }
-
- return -ENOIOCTLCMD;
-}
-#endif
-
/*
* Handle the 'receiver data ready' interrupt.
* This function is called by the 'tty_io' module in the kernel when
* a block of data has been received, which can now be decapsulated
* and sent on to the AX.25 layer for further processing.
*/
-static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static void mkiss_receive_buf(struct tty_struct *tty, const u8 *cp,
+ const u8 *fp, size_t count)
{
struct mkiss *ax = mkiss_get(tty);
@@ -985,14 +937,11 @@ out:
static struct tty_ldisc_ops ax_ldisc = {
.owner = THIS_MODULE,
- .magic = TTY_LDISC_MAGIC,
+ .num = N_AX25,
.name = "mkiss",
.open = mkiss_open,
.close = mkiss_close,
.ioctl = mkiss_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = mkiss_compat_ioctl,
-#endif
.receive_buf = mkiss_receive_buf,
.write_wakeup = mkiss_write_wakeup
};
@@ -1008,22 +957,16 @@ static int __init mkiss_init_driver(void)
printk(banner);
- status = tty_register_ldisc(N_AX25, &ax_ldisc);
+ status = tty_register_ldisc(&ax_ldisc);
if (status != 0)
printk(msg_regfail, status);
return status;
}
-static const char msg_unregfail[] = KERN_ERR \
- "mkiss: can't unregister line discipline (err = %d)\n";
-
static void __exit mkiss_exit_driver(void)
{
- int ret;
-
- if ((ret = tty_unregister_ldisc(N_AX25)))
- printk(msg_unregfail, ret);
+ tty_unregister_ldisc(&ax_ldisc);
}
MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");