summaryrefslogtreecommitdiffstats
path: root/drivers/net/slip.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/slip.c')
-rw-r--r--drivers/net/slip.c1717
1 files changed, 924 insertions, 793 deletions
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 6d80df49a..8b1bc9476 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -3,7 +3,7 @@
* devices like TTY. It interfaces between a raw TTY, and the
* kernel's INET protocol layers (via DDI).
*
- * Version: @(#)slip.c 0.7.6 05/25/93
+ * Version: @(#)slip.c 0.8.3 12/24/94
*
* Authors: Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -25,117 +25,92 @@
* Alan Cox : Default to 192.168.0.0 (RFC 1597)
* A.N.Kuznetsov : dev_tint() recursion fix.
* Dmitry Gorodchanin : SLIP memory leaks
- * Alan Cox : Oops - fix AX.25 buffer lengths
+ * Dmitry Gorodchanin : Code cleanup. Reduce tty driver
+ * buffering from 4096 to 256 bytes.
+ * Improving SLIP response time.
+ * CONFIG_SLIP_MODE_SLIP6.
+ * ifconfig sl? up & down now works correctly.
+ * Modularization.
+ * Alan Cox : Oops - fix AX.25 buffer lengths
+ * Dmitry Gorodchanin : Even more cleanups. Preserve CSLIP
+ * statistics. Include CSLIP code only
+ * if it really needed.
+ * Alan Cox : Free slhc buffers in the right place.
+ *
*
*
* FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
* CONFIG_INET defined.
+ * I hope now it is fixed ;)
*/
-
-#include <asm/segment.h>
-#include <asm/system.h>
+#define SL_CHECK_TRANSMIT
#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+/* Undef this, if you don't need 6bit encapsulation code in the driver */
+#define CONFIG_SLIP_MODE_SLIP6
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
#include <linux/interrupt.h>
+#include <linux/in.h>
#include <linux/tty.h>
#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/in.h>
-#include <linux/inet.h>
#include <linux/netdevice.h>
#ifdef CONFIG_AX25
-#include "ax25.h"
+#include <linux/timer.h>
+#include <net/ax25.h>
#endif
#include <linux/etherdevice.h>
-#ifdef CONFIG_INET
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
-#endif
#include <linux/skbuff.h>
#include <linux/if_arp.h>
-#include "sock.h"
#include "slip.h"
#ifdef CONFIG_INET
+#include <linux/ip.h>
+#include <linux/tcp.h>
#include "slhc.h"
#endif
-#define SLIP_VERSION "0.7.5-NET3.014-NEWTTY"
+#ifdef MODULE
+#define SLIP_VERSION "0.8.3-NET3.019-NEWTTY-MODULAR"
+#else
+#define SLIP_VERSION "0.8.3-NET3.019-NEWTTY"
+#endif
static struct slip sl_ctrl[SL_NRUNIT];
static struct tty_ldisc sl_ldisc;
static int already = 0;
-/* Initialize a SLIP control block for use. */
-static void
-sl_initialize(struct slip *sl, struct device *dev)
-{
- sl->magic = SLIP_MAGIC;
- sl->inuse = 0;
- sl->sending = 0;
- sl->escape = 0;
- sl->flags = 0;
-#ifdef SL_ADAPTIVE
- sl->mode = SL_MODE_ADAPTIVE; /* automatic CSLIP recognition */
-#else
-#ifdef SL_COMPRESSED
- sl->mode = SL_MODE_CSLIP | SL_MODE_ADAPTIVE; /* Default */
-#else
- sl->mode = SL_MODE_SLIP; /* Default for non compressors */
+static int slip_esc(unsigned char *p, unsigned char *d, int len);
+static void slip_unesc(struct slip *sl, unsigned char c);
+#ifdef CONFIG_SLIP_MODE_SLIP6
+static int slip_esc6(unsigned char *p, unsigned char *d, int len);
+static void slip_unesc6(struct slip *sl, unsigned char c);
#endif
-#endif
-
- sl->line = dev->base_addr;
- sl->tty = NULL;
- sl->dev = dev;
- sl->slcomp = NULL;
-
- /* Clear all pointers. */
- sl->rbuff = NULL;
- sl->xbuff = NULL;
- sl->cbuff = NULL;
-
- sl->rhead = NULL;
- sl->rend = NULL;
- dev->rmem_end = (unsigned long) NULL;
- dev->rmem_start = (unsigned long) NULL;
- dev->mem_end = (unsigned long) NULL;
- dev->mem_start = (unsigned long) NULL;
- dev->type = ARPHRD_SLIP + sl->mode;
- if(dev->type == 260) /* KISS */
- dev->type=ARPHRD_AX25;
-}
+
/* Find a free SLIP channel, and link in this `tty' line. */
static inline struct slip *
sl_alloc(void)
{
- unsigned long flags;
- struct slip *sl;
- int i;
-
- save_flags (flags);
- cli();
- for (i = 0; i < SL_NRUNIT; i++) {
- sl = &sl_ctrl[i];
- if (sl->inuse == 0) {
- sl->inuse = 1;
- sl->tty = NULL;
- restore_flags(flags);
- return(sl);
+ struct slip *sl;
+ int i;
+
+ for (i = 0; i < SL_NRUNIT; i++) {
+ sl = &sl_ctrl[i];
+ if (!set_bit(SLF_INUSE, &sl->flags)) {
+ return sl;
+ }
}
- }
- restore_flags(flags);
- return(NULL);
+ return NULL;
}
@@ -143,121 +118,138 @@ sl_alloc(void)
static inline void
sl_free(struct slip *sl)
{
- unsigned long flags;
+ /* Free all SLIP frame buffers. */
+ if (sl->rbuff) {
+ kfree(sl->rbuff);
+ }
+ sl->rbuff = NULL;
+ if (sl->xbuff) {
+ kfree(sl->xbuff);
+ }
+ sl->xbuff = NULL;
+#ifdef SL_INCLUDE_CSLIP
+ /* Save CSLIP statistics */
+ if (sl->slcomp) {
+ sl->rx_compressed += sl->slcomp->sls_i_compressed;
+ sl->rx_dropped += sl->slcomp->sls_i_tossed;
+ sl->tx_compressed += sl->slcomp->sls_o_compressed;
+ sl->tx_misses += sl->slcomp->sls_o_misses;
+ }
+ if (sl->cbuff) {
+ kfree(sl->cbuff);
+ }
+ sl->cbuff = NULL;
+ if(sl->slcomp)
+ slhc_free(sl->slcomp);
+ sl->slcomp = NULL;
+#endif
- if (sl->inuse) {
- save_flags(flags);
- cli();
- sl->inuse = 0;
- sl->tty = NULL;
- restore_flags(flags);
- }
+ if (!clear_bit(SLF_INUSE, &sl->flags)) {
+ printk("%s: sl_free for already free unit.\n", sl->dev->name);
+ }
}
/* MTU has been changed by the IP layer. Unfortunately we are not told about this, but
we spot it ourselves and fix things up. We could be in an upcall from the tty
driver, or in an ip packet queue. */
-
+
static void sl_changedmtu(struct slip *sl)
{
- struct device *dev=sl->dev;
- unsigned char *tb,*rb,*cb,*tf,*rf,*cf;
- int l;
- int omtu=sl->mtu;
+ struct device *dev = sl->dev;
+ unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
+#ifdef SL_INCLUDE_CSLIP
+ unsigned char *cbuff, *ocbuff;
+#endif
+ int len;
+ unsigned long flags;
-#ifdef CONFIG_AX25
- sl->mtu=dev->mtu+73;
-#else
- sl->mtu=dev->mtu;
-#endif
- l=(dev->mtu *2);
+ len = dev->mtu * 2;
/*
* allow for arrival of larger UDP packets, even if we say not to
* also fixes a bug in which SunOS sends 512-byte packets even with
* an MSS of 128
*/
- if (l < (576 * 2))
- l = 576 * 2;
-
- tb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);
- rb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);
- cb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);
-
- if(tb==NULL || rb==NULL || cb==NULL)
- {
- printk("Unable to grow slip buffers. MTU change cancelled.\n");
- sl->mtu=omtu;
- dev->mtu=omtu;
- if(tb!=NULL)
- kfree(tb);
- if(rb!=NULL)
- kfree(rb);
- if(cb!=NULL)
- kfree(cb);
+ if (len < 576 * 2) {
+ len = 576 * 2;
+ }
+
+ xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+ rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+#ifdef SL_INCLUDE_CSLIP
+ cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+#endif
+
+#ifdef SL_INCLUDE_CSLIP
+ if (xbuff == NULL || rbuff == NULL || cbuff == NULL) {
+#else
+ if (xbuff == NULL || rbuff == NULL) {
+#endif
+ printk("%s: unable to grow slip buffers, MTU change cancelled.\n",
+ sl->dev->name);
+ dev->mtu = sl->mtu;
+ if (xbuff != NULL) {
+ kfree(xbuff);
+ }
+ if (rbuff != NULL) {
+ kfree(rbuff);
+ }
+#ifdef SL_INCLUDE_CSLIP
+ if (cbuff != NULL) {
+ kfree(cbuff);
+ }
+#endif
return;
}
-
- cli();
-
- tf=(unsigned char *)sl->dev->mem_start;
- sl->dev->mem_start=(unsigned long)tb;
- sl->dev->mem_end=(unsigned long) (sl->dev->mem_start + l);
- rf=(unsigned char *)sl->dev->rmem_start;
- sl->dev->rmem_start=(unsigned long)rb;
- sl->dev->rmem_end=(unsigned long) (sl->dev->rmem_start + l);
-
- sl->xbuff = (unsigned char *) sl->dev->mem_start;
- sl->rbuff = (unsigned char *) sl->dev->rmem_start;
- sl->rend = (unsigned char *) sl->dev->rmem_end;
- sl->rhead = sl->rbuff;
-
- cf=sl->cbuff;
- sl->cbuff=cb;
-
- sl->escape=0;
- sl->sending=0;
- sl->rcount=0;
- sti();
-
- if(rf!=NULL)
- kfree(rf);
- if(tf!=NULL)
- kfree(tf);
- if(cf!=NULL)
- kfree(cf);
-}
+ save_flags(flags); cli();
+ oxbuff = sl->xbuff;
+ sl->xbuff = xbuff;
+ orbuff = sl->rbuff;
+ sl->rbuff = rbuff;
+#ifdef SL_INCLUDE_CSLIP
+ ocbuff = sl->cbuff;
+ sl->cbuff = cbuff;
+#endif
+ if (sl->xleft) {
+ if (sl->xleft <= len) {
+ memcpy(sl->xbuff, sl->xhead, sl->xleft);
+ } else {
+ sl->xleft = 0;
+ sl->tx_dropped++;
+ }
+ }
+ sl->xhead = sl->xbuff;
+
+ if (sl->rcount) {
+ if (sl->rcount <= len) {
+ memcpy(sl->rbuff, orbuff, sl->rcount);
+ } else {
+ sl->rcount = 0;
+ sl->rx_over_errors++;
+ set_bit(SLF_ERROR, &sl->flags);
+ }
+ }
+#ifdef CONFIG_AX25
+ sl->mtu = dev->mtu + 73;
+#else
+ sl->mtu = dev->mtu;
+#endif
+ sl->buffsize = len;
-/* Stuff one byte into a SLIP receiver buffer. */
-static inline void
-sl_enqueue(struct slip *sl, unsigned char c)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (sl->rhead < sl->rend) {
- *sl->rhead = c;
- sl->rhead++;
- sl->rcount++;
- } else sl->roverrun++;
- restore_flags(flags);
-}
+ restore_flags(flags);
-/* Release 'i' bytes from a SLIP receiver buffer. */
-static inline void
-sl_dequeue(struct slip *sl, int i)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (sl->rhead > sl->rbuff) {
- sl->rhead -= i;
- sl->rcount -= i;
- }
- restore_flags(flags);
+ if (oxbuff != NULL) {
+ kfree(oxbuff);
+ }
+ if (orbuff != NULL) {
+ kfree(orbuff);
+ }
+#ifdef SL_INCLUDE_CSLIP
+ if (ocbuff != NULL) {
+ kfree(ocbuff);
+ }
+#endif
}
@@ -265,13 +257,9 @@ sl_dequeue(struct slip *sl, int i)
static inline void
sl_lock(struct slip *sl)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- sl->sending = 1;
- sl->dev->tbusy = 1;
- restore_flags(flags);
+ if (set_bit(0, (void *) &sl->dev->tbusy)) {
+ printk("%s: trying to lock already locked device!\n", sl->dev->name);
+ }
}
@@ -279,123 +267,121 @@ sl_lock(struct slip *sl)
static inline void
sl_unlock(struct slip *sl)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- sl->sending = 0;
- sl->dev->tbusy = 0;
- restore_flags(flags);
+ if (!clear_bit(0, (void *)&sl->dev->tbusy)) {
+ printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
+ }
}
-
/* Send one completely decapsulated IP datagram to the IP layer. */
static void
sl_bump(struct slip *sl)
{
- int done;
- unsigned char c;
- unsigned long flags;
- int count;
-
- count = sl->rcount;
-#ifdef CONFIG_INET
- if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
- if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
-#if 1
- /* ignore compressed packets when CSLIP is off */
- if (!(sl->mode & SL_MODE_CSLIP)) {
- printk("SLIP: compressed packet ignored\n");
- return;
- }
-#endif
- /* make sure we've reserved enough space for uncompress to use */
- save_flags(flags);
- cli();
- if ((sl->rhead + 80) < sl->rend) {
- sl->rhead += 80;
- sl->rcount += 80;
- done = 1;
- } else {
- sl->roverrun++;
- done = 0;
- }
- restore_flags(flags);
- if (! done) /* not enough space available */
- return;
-
- count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
- if (count <= 0) {
- sl->errors++;
- return;
- }
- } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
- if (!(sl->mode & SL_MODE_CSLIP)) {
- /* turn on header compression */
- sl->mode |= SL_MODE_CSLIP;
- printk("SLIP: header compression turned on\n");
- }
- sl->rbuff[0] &= 0x4f;
- if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {
- sl->errors++;
- return;
- }
- }
- }
+ struct sk_buff *skb;
+ int count;
+
+ count = sl->rcount;
+#ifdef SL_INCLUDE_CSLIP
+ if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
+ unsigned char c;
+ if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
+ /* ignore compressed packets when CSLIP is off */
+ if (!(sl->mode & SL_MODE_CSLIP)) {
+ printk("%s: compressed packet ignored\n", sl->dev->name);
+ return;
+ }
+ /* make sure we've reserved enough space for uncompress to use */
+ if (count + 80 > sl->buffsize) {
+ sl->rx_over_errors++;
+ return;
+ }
+ count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
+ if (count <= 0) {
+ return;
+ }
+ } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
+ if (!(sl->mode & SL_MODE_CSLIP)) {
+ /* turn on header compression */
+ sl->mode |= SL_MODE_CSLIP;
+ sl->mode &= ~SL_MODE_ADAPTIVE;
+ printk("%s: header compression turned on\n", sl->dev->name);
+ }
+ sl->rbuff[0] &= 0x4f;
+ if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {
+ return;
+ }
+ }
+ }
+#endif /* SL_INCLUDE_CSLIP */
-#endif
- /* Bump the datagram to the upper layers... */
- do {
- /* clh_dump(sl->rbuff, count); */
- done = dev_rint(sl->rbuff, count, 0, sl->dev);
- if (done == 0 || done == 1) break;
- } while(1);
-
- sl->rpacket++;
+ skb = alloc_skb(count, GFP_ATOMIC);
+ if (skb == NULL) {
+ printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
+ sl->rx_dropped++;
+ return;
+ }
+ skb->len = count;
+ skb->dev = sl->dev;
+ memcpy(skb->data, sl->rbuff, count);
+ if(sl->mode&(SL_MODE_AX25|SL_MODE_AX25VC))
+ skb->protocol=htons(ETH_P_AX25);
+ else
+ skb->protocol=htons(ETH_P_IP);
+ netif_rx(skb);
+ sl->rx_packets++;
}
/* Encapsulate one IP datagram and stuff into a TTY queue. */
static void
sl_encaps(struct slip *sl, unsigned char *icp, int len)
{
- unsigned char *p;
- int actual, count;
+ unsigned char *p;
+ int actual, count;
+
-
#ifdef CONFIG_AX25
- if(sl->mtu != sl->dev->mtu+73)/* Someone has been ifconfigging */
+ if (sl->mtu != sl->dev->mtu + 73) { /* Someone has been ifconfigging */
#else
- if(sl->mtu != sl->dev->mtu) /* Someone has been ifconfigging */
+ if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */
+#endif
+ sl_changedmtu(sl);
+ }
+
+ if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */
+ len = sl->mtu;
+ printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
+ sl->tx_dropped++;
+ sl_unlock(sl);
+ return;
+ }
+
+ p = icp;
+#ifdef SL_INCLUDE_CSLIP
+ if (sl->mode & SL_MODE_CSLIP) {
+ len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
+ }
#endif
- sl_changedmtu(sl);
-
- if(len>sl->mtu) /* Sigh, shouldn't occur BUT ... */
- {
- len=sl->mtu;
- printk("slip: truncating oversized transmit packet!\n");
- }
-
- p = icp;
-#ifdef CONFIG_INET
- if(sl->mode & SL_MODE_CSLIP)
- len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
+#ifdef CONFIG_SLIP_MODE_SLIP6
+ if(sl->mode & SL_MODE_SLIP6)
+ count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
+ else
#endif
- if(sl->mode & SL_MODE_SLIP6)
- count=slip_esc6(p, (unsigned char *)sl->xbuff,len);
- else
- count=slip_esc(p, (unsigned char *)sl->xbuff,len);
- sl->spacket++;
-
- /* Tell TTY to send it on its way. */
- actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
- if (actual == count) {
- sl_unlock(sl);
- mark_bh(NET_BH);
- } else {
- sl->xhead = sl->xbuff + count;
- sl->xtail = sl->xbuff + actual;
- sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- }
+ count = slip_esc(p, (unsigned char *) sl->xbuff, len);
+
+ /* Order of next two lines is *very* important.
+ * When we are sending a little amount of data,
+ * the transfer may be completed inside driver.write()
+ * routine, because it's running with interrupts enabled.
+ * In this case we *never* got WRITE_WAKEUP event,
+ * if we did not request it before write operation.
+ * 14 Oct 1994 Dmitry Gorodchanin.
+ */
+ sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+ actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
+#ifdef SL_CHECK_TRANSMIT
+ sl->dev->trans_start = jiffies;
+#endif
+ sl->xleft = count - actual;
+ sl->xhead = sl->xbuff + actual;
}
/*
@@ -404,103 +390,107 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
*/
static void slip_write_wakeup(struct tty_struct *tty)
{
- register int count, answer;
+ int actual;
struct slip *sl = (struct slip *) tty->disc_data;
/* First make sure we're connected. */
- if (!sl || sl->magic != SLIP_MAGIC) {
+ if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) {
return;
}
- if (!sl->xtail)
- return;
-
- cli();
- if (sl->flags & SLF_XMIT_BUSY) {
- sti();
- return;
- }
- sl->flags |= SLF_XMIT_BUSY;
- sti();
-
- count = sl->xhead - sl->xtail;
-
- answer = tty->driver.write(tty, 0, sl->xtail, count);
- if (answer == count) {
- sl->xtail = 0;
- tty->flags &= ~TTY_DO_WRITE_WAKEUP;
-
+ if (sl->xleft <= 0) {
+ /* Now serial buffer is almost free & we can start
+ * transmission of another packet */
+ sl->tx_packets++;
+ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
sl_unlock(sl);
mark_bh(NET_BH);
- } else {
- sl->xtail += answer;
+ return;
}
- sl->flags &= ~SLF_XMIT_BUSY;
-}
-/*static void sl_hex_dump(unsigned char *x,int l)
-{
- int n=0;
- printk("sl_xmit: (%d bytes)\n",l);
- while(l)
- {
- printk("%2X ",(int)*x++);
- l--;
- n++;
- if(n%32==0)
- printk("\n");
- }
- if(n%32)
- printk("\n");
-}*/
+ actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);
+ sl->xleft -= actual;
+ sl->xhead += actual;
+}
/* Encapsulate an IP datagram and kick it into a TTY queue. */
static int
sl_xmit(struct sk_buff *skb, struct device *dev)
{
- struct tty_struct *tty;
- struct slip *sl;
- int size;
-
- /* Find the correct SLIP channel to use. */
- sl = &sl_ctrl[dev->base_addr];
- tty = sl->tty;
-
- /*
- * If we are busy already- too bad. We ought to be able
- * to queue things at this point, to allow for a little
- * frame buffer. Oh well...
- */
- if (sl->sending) {
- sl->sbusy++;
- return(1);
- }
-
- /* We were not, so we are now... :-) */
- if (skb != NULL) {
- sl_lock(sl);
-
- size=skb->len;
- sl_encaps(sl, skb->data, size);
- dev_kfree_skb(skb, FREE_WRITE);
- }
- return(0);
-}
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+ if (!dev->start) {
+ printk("%s: xmit call when iface is down\n", dev->name);
+ return 1;
+ }
+ /*
+ * If we are busy already- too bad. We ought to be able
+ * to queue things at this point, to allow for a little
+ * frame buffer. Oh well...
+ * -----------------------------------------------------
+ * I hate queues in SLIP driver. May be it's efficient,
+ * but for me latency is more important. ;)
+ * So, no queues !
+ * 14 Oct 1994 Dmitry Gorodchanin.
+ */
+ if (dev->tbusy) {
+ /* May be we must check transmitter timeout here ?
+ * 14 Oct 1994 Dmitry Gorodchanin.
+ */
+#ifdef SL_CHECK_TRANSMIT
+ if (jiffies - dev->trans_start < 20 * HZ) {
+ /* 20 sec timeout not reached */
+ return 1;
+ }
+ printk("%s: transmit timed out, %s?\n", dev->name,
+ (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
+ "bad line quality" : "driver error");
+ sl->xleft = 0;
+ sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ sl_unlock(sl);
+#else
+ return 1;
+#endif
+ }
-/* Return the frame type ID. This is normally IP but maybe be AX.25. */
-static unsigned short
-sl_type_trans (struct sk_buff *skb, struct device *dev)
-{
#ifdef CONFIG_AX25
- struct slip *sl=&sl_ctrl[dev->base_addr];
- if(sl->mode&SL_MODE_AX25)
- return htons(ETH_P_AX25);
+#ifdef CONFIG_INET
+ /*
+ * This code is not very intelligent. Fix me.
+ */
+ if (skb->data[15] == LAPB_UI && skb->data[16] == AX25_P_IP) {
+ struct sk_buff *skbn;
+ char mode;
+
+ mode = ax25_ip_mode_get((ax25_address *)(skb->data + 1), dev);
+
+ if (mode == 'V' || mode == 'v' || (mode == ' ' && sl->mode & SL_MODE_AX25VC)) {
+ if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+ sl->tx_errors++;
+ return 1;
+ }
+
+ ax25_send_frame(skbn, (ax25_address *)dev->dev_addr, (ax25_address *)(skbn->data + 1), dev);
+ dev_kfree_skb(skb, FREE_WRITE);
+ mark_bh(NET_BH);
+ return 0;
+ }
+ }
#endif
- return htons(ETH_P_IP);
+#endif
+
+ /* We were not busy, so we are now... :-) */
+ if (skb != NULL) {
+ sl_lock(sl);
+ sl_encaps(sl, skb->data, skb->len);
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ return 0;
}
+/* Return the frame type ID. This is normally IP but maybe be AX.25. */
+
/* Fill in the MAC-level header. Not used by SLIP. */
static int
sl_header(unsigned char *buff, struct device *dev, unsigned short type,
@@ -508,30 +498,32 @@ sl_header(unsigned char *buff, struct device *dev, unsigned short type,
{
#ifdef CONFIG_AX25
#ifdef CONFIG_INET
- struct slip *sl=&sl_ctrl[dev->base_addr];
- if((sl->mode&SL_MODE_AX25) && type!=htons(ETH_P_AX25))
- return ax25_encapsulate(buff,dev,type,daddr,saddr,len,skb);
-#endif
-#endif
+ struct slip *sl = &sl_ctrl[dev->base_addr];
- return(0);
+ if (((sl->mode & SL_MODE_AX25) || (sl->mode & SL_MODE_AX25VC)) && type != htons(ETH_P_AX25)) {
+ return ax25_encapsulate(buff, dev, type, daddr, saddr, len, skb);
+ }
+#endif
+#endif
+ return 0;
}
/* Rebuild the MAC-level header. Not used by SLIP. */
static int
sl_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
#ifdef CONFIG_AX25
#ifdef CONFIG_INET
- struct slip *sl=&sl_ctrl[dev->base_addr];
-
- if(sl->mode&SL_MODE_AX25)
- return ax25_rebuild_header(buff,dev,raddr, skb);
-#endif
-#endif
- return(0);
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+
+ if ((sl->mode & SL_MODE_AX25) || (sl->mode & SL_MODE_AX25VC)) {
+ return ax25_rebuild_header(buff, dev, raddr, skb);
+ }
+#endif
+#endif
+ return 0;
}
@@ -539,84 +531,83 @@ sl_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
static int
sl_open(struct device *dev)
{
- struct slip *sl;
- unsigned char *p;
- unsigned long l;
-
- sl = &sl_ctrl[dev->base_addr];
- if (sl->tty == NULL) {
- return(-ENXIO);
- }
- sl->dev = dev;
-
- /*
- * Allocate the SLIP frame buffers:
- *
- * mem_end Top of frame buffers
- * mem_start Start of frame buffers
- * rmem_end Top of RECV frame buffer
- * rmem_start Start of RECV frame buffer
- */
- l = (dev->mtu * 2);
-/*
- * allow for arrival of larger UDP packets, even if we say not to
- * also fixes a bug in which SunOS sends 512-byte packets even with
- * an MSS of 128
- */
- if (l < (576 * 2))
- l = 576 * 2;
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+ unsigned long len;
+
+ if (sl->tty == NULL) {
+ return -ENODEV;
+ }
- p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
- if (p == NULL) {
- return(-ENOMEM);
- }
+ /*
+ * Allocate the SLIP frame buffers:
+ *
+ * rbuff Receive buffer.
+ * xbuff Transmit buffer.
+ * cbuff Temporary compression buffer.
+ */
+ len = dev->mtu * 2;
+ /*
+ * allow for arrival of larger UDP packets, even if we say not to
+ * also fixes a bug in which SunOS sends 512-byte packets even with
+ * an MSS of 128
+ */
+ if (len < 576 * 2) {
+ len = 576 * 2;
+ }
+ sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+ if (sl->rbuff == NULL) {
+ goto norbuff;
+ }
+ sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+ if (sl->xbuff == NULL) {
+ goto noxbuff;
+ }
+#ifdef SL_INCLUDE_CSLIP
+ sl->cbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+ if (sl->cbuff == NULL) {
+ goto nocbuff;
+ }
+ sl->slcomp = slhc_init(16, 16);
+ if (sl->slcomp == NULL) {
+ goto noslcomp;
+ }
+#endif
#ifdef CONFIG_AX25
- sl->mtu = dev->mtu+73;
-#else
- sl->mtu = dev->mtu;
-#endif
- sl->dev->mem_start = (unsigned long) p;
- sl->dev->mem_end = (unsigned long) (sl->dev->mem_start + l);
-
- p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
- if (p == NULL) {
- kfree((unsigned char *)sl->dev->mem_start);
- return(-ENOMEM);
- }
- sl->dev->rmem_start = (unsigned long) p;
- sl->dev->rmem_end = (unsigned long) (sl->dev->rmem_start + l);
-
- sl->xbuff = (unsigned char *) sl->dev->mem_start;
- sl->rbuff = (unsigned char *) sl->dev->rmem_start;
- sl->rend = (unsigned char *) sl->dev->rmem_end;
- sl->rhead = sl->rbuff;
-
- sl->escape = 0;
- sl->sending = 0;
- sl->rcount = 0;
-
- p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
- if (p == NULL) {
- kfree((unsigned char *)sl->dev->mem_start);
- kfree((unsigned char *)sl->dev->rmem_start);
- return(-ENOMEM);
- }
- sl->cbuff = p;
-#ifdef CONFIG_INET
- sl->slcomp = slhc_init(16, 16);
- if (sl->slcomp == NULL) {
- kfree((unsigned char *)sl->dev->mem_start);
- kfree((unsigned char *)sl->dev->rmem_start);
- kfree((unsigned char *)sl->cbuff);
- return(-ENOMEM);
- }
+ sl->mtu = dev->mtu + 73;
+#else
+ sl->mtu = dev->mtu;
+#endif
+ sl->buffsize = len;
+ sl->rcount = 0;
+ sl->xleft = 0;
+#ifdef CONFIG_SLIP_MODE_SLIP6
+ sl->xdata = 0;
+ sl->xbits = 0;
+#endif
+ sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
+
+ /* Needed because address '0' is special */
+ if (dev->pa_addr == 0) {
+ dev->pa_addr=ntohl(0xC0A80001);
+ }
+ dev->tbusy = 0;
+/* dev->flags |= IFF_UP; */
+ dev->start = 1;
+
+ return 0;
+
+ /* Cleanup */
+#ifdef SL_INCLUDE_CSLIP
+noslcomp:
+ kfree(sl->cbuff);
+nocbuff:
#endif
- dev->flags|=IFF_UP;
- /* Needed because address '0' is special */
- if(dev->pa_addr==0)
- dev->pa_addr=ntohl(0xC0A80001);
- return(0);
+ kfree(sl->xbuff);
+noxbuff:
+ kfree(sl->rbuff);
+norbuff:
+ return -ENOMEM;
}
@@ -624,28 +615,22 @@ sl_open(struct device *dev)
static int
sl_close(struct device *dev)
{
- struct slip *sl;
-
- sl = &sl_ctrl[dev->base_addr];
- if (sl->tty == NULL) {
- return(-EBUSY);
- }
- sl->tty->disc_data = 0;
- sl_free(sl);
-
- /* Free all SLIP frame buffers. */
- kfree(sl->rbuff);
- kfree(sl->xbuff);
- kfree(sl->cbuff);
-#ifdef CONFIG_INET
- slhc_free(sl->slcomp);
-#endif
- sl_initialize(sl, dev);
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+
+ if (sl->tty == NULL) {
+ return -EBUSY;
+ }
+ sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ dev->tbusy = 1;
+ dev->start = 0;
+
+/* dev->flags &= ~IFF_UP; */
- return(0);
+ return 0;
}
-static int slip_receive_room(struct tty_struct *tty)
+static int
+slip_receive_room(struct tty_struct *tty)
{
return 65536; /* We can handle an infinite amount of data. :-) */
}
@@ -656,41 +641,46 @@ static int slip_receive_room(struct tty_struct *tty)
* a block of SLIP data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
-static void slip_receive_buf(struct tty_struct *tty, unsigned char *cp,
- char *fp, int count)
+static void
+slip_receive_buf(struct tty_struct *tty, unsigned char *cp, char *fp, int count)
{
struct slip *sl = (struct slip *) tty->disc_data;
-
- if (!sl || sl->magic != SLIP_MAGIC)
+
+ if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start)
return;
-
+
/*
* Argh! mtu change time! - costs us the packet part received
* at the change
*/
#ifdef CONFIG_AX25
- if(sl->mtu!=sl->dev->mtu+73)
-#else
- if(sl->mtu!=sl->dev->mtu)
-#endif
+ if (sl->mtu != sl->dev->mtu + 73) {
+#else
+ if (sl->mtu != sl->dev->mtu) {
+#endif
sl_changedmtu(sl);
-
+ }
+
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- sl->flags |= SLF_ERROR;
+ if (!set_bit(SLF_ERROR, &sl->flags)) {
+ sl->rx_errors++;
+ }
cp++;
continue;
}
+#ifdef CONFIG_SLIP_MODE_SLIP6
if (sl->mode & SL_MODE_SLIP6)
- slip_unesc6(sl,*cp++);
+ slip_unesc6(sl, *cp++);
else
- slip_unesc(sl,*cp++);
+#endif
+ slip_unesc(sl, *cp++);
}
}
/*
- * Open the high-level part of the SLIP channel.
+ * Open the high-level part of the SLIP channel.
* This function is called by the TTY module when the
* SLIP line discipline is called for. Because we are
* sure the tty line exists, we only have to link it to
@@ -699,63 +689,50 @@ static void slip_receive_buf(struct tty_struct *tty, unsigned char *cp,
static int
slip_open(struct tty_struct *tty)
{
- struct slip *sl = (struct slip *) tty->disc_data;
-
- /* First make sure we're not already connected. */
- if (sl && sl->magic == SLIP_MAGIC) {
- return(-EEXIST);
- }
-
- /* OK. Find a free SLIP channel to use. */
- if ((sl = sl_alloc()) == NULL) {
- return(-ENFILE);
- }
- sl->tty = tty;
- tty->disc_data = sl;
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
-
- /* Perform the low-level SLIP initialization. */
- (void) sl_open(sl->dev);
-
- /* Done. We have linked the TTY line to a channel. */
- return(sl->line);
-}
+ struct slip *sl = (struct slip *) tty->disc_data;
+ int err;
-
-static struct enet_statistics *
-sl_get_stats(struct device *dev)
-{
- static struct enet_statistics stats;
- struct slip *sl;
- struct slcompress *comp;
-
- /* Find the correct SLIP channel to use. */
- sl = &sl_ctrl[dev->base_addr];
- if (! sl)
- return NULL;
-
- memset(&stats, 0, sizeof(struct enet_statistics));
-
- stats.rx_packets = sl->rpacket;
- stats.rx_over_errors = sl->roverrun;
- stats.tx_packets = sl->spacket;
- stats.tx_dropped = sl->sbusy;
- stats.rx_errors = sl->errors;
-#ifdef CONFIG_INET
- comp = sl->slcomp;
- if (comp) {
- stats.rx_fifo_errors = comp->sls_i_compressed;
- stats.rx_dropped = comp->sls_i_tossed;
- stats.tx_fifo_errors = comp->sls_o_compressed;
- stats.collisions = comp->sls_o_misses;
- }
+ /* First make sure we're not already connected. */
+ if (sl && sl->magic == SLIP_MAGIC) {
+ return -EEXIST;
+ }
+
+ /* OK. Find a free SLIP channel to use. */
+ if ((sl = sl_alloc()) == NULL) {
+ return -ENFILE;
+ }
+
+ sl->tty = tty;
+ tty->disc_data = sl;
+ if (tty->driver.flush_buffer) {
+ tty->driver.flush_buffer(tty);
+ }
+ if (tty->ldisc.flush_buffer) {
+ tty->ldisc.flush_buffer(tty);
+ }
+
+ /* Restore default settings */
+ sl->mode = SL_MODE_DEFAULT;
+ sl->dev->type = ARPHRD_SLIP + sl->mode;
+#ifdef CONFIG_AX25
+ if (sl->dev->type == 260 || sl->dev->type == 272) { /* KISS */
+ sl->dev->type = ARPHRD_AX25;
+ }
+#endif
+ /* Perform the low-level SLIP initialization. */
+ if ((err = sl_open(sl->dev))) {
+ return err;
+ }
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
#endif
- return (&stats);
+
+ /* Done. We have linked the TTY line to a channel. */
+ return sl->dev->base_addr;
}
+
/*
* Close down a SLIP channel.
* This means flushing out any pending queues, and then restoring the
@@ -765,334 +742,488 @@ sl_get_stats(struct device *dev)
static void
slip_close(struct tty_struct *tty)
{
- struct slip *sl = (struct slip *) tty->disc_data;
+ struct slip *sl = (struct slip *) tty->disc_data;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLIP_MAGIC) {
+ return;
+ }
+
+ (void) dev_close(sl->dev);
+
+ tty->disc_data = 0;
+ sl->tty = NULL;
+ sl_free(sl);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
- /* First make sure we're connected. */
- if (!sl || sl->magic != SLIP_MAGIC) {
- return;
- }
- (void) dev_close(sl->dev);
+static struct enet_statistics *
+sl_get_stats(struct device *dev)
+{
+ static struct enet_statistics stats;
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+#ifdef SL_INCLUDE_CSLIP
+ struct slcompress *comp;
+#endif
+
+ memset(&stats, 0, sizeof(struct enet_statistics));
+
+ stats.rx_packets = sl->rx_packets;
+ stats.tx_packets = sl->tx_packets;
+ stats.rx_dropped = sl->rx_dropped;
+ stats.tx_dropped = sl->tx_dropped;
+ stats.tx_errors = sl->tx_errors;
+ stats.rx_errors = sl->rx_errors;
+ stats.rx_over_errors = sl->rx_over_errors;
+#ifdef SL_INCLUDE_CSLIP
+ stats.rx_fifo_errors = sl->rx_compressed;
+ stats.tx_fifo_errors = sl->tx_compressed;
+ stats.collisions = sl->tx_misses;
+ comp = sl->slcomp;
+ if (comp) {
+ stats.rx_fifo_errors += comp->sls_i_compressed;
+ stats.rx_dropped += comp->sls_i_tossed;
+ stats.tx_fifo_errors += comp->sls_o_compressed;
+ stats.collisions += comp->sls_o_misses;
+ }
+#endif /* CONFIG_INET */
+ return (&stats);
}
/************************************************************************
- * STANDARD SLIP ENCAPSULATION *
- ************************************************************************
- *
- */
-
- int
- slip_esc(unsigned char *s, unsigned char *d, int len)
- {
- int count = 0;
-
- /*
- * Send an initial END character to flush out any
- * data that may have accumulated in the receiver
- * due to line noise.
- */
-
- d[count++] = END;
-
- /*
- * For each byte in the packet, send the appropriate
- * character sequence, according to the SLIP protocol.
- */
-
- while(len-- > 0) {
- switch(*s) {
- case END:
- d[count++] = ESC;
- d[count++] = ESC_END;
- break;
- case ESC:
- d[count++] = ESC;
- d[count++] = ESC_ESC;
- break;
- default:
- d[count++] = *s;
- }
- ++s;
- }
- d[count++] = END;
- return(count);
- }
-
- void
- slip_unesc(struct slip *sl, unsigned char s)
- {
- switch(s) {
- case ESC:
- sl->flags |= SLF_ESCAPE;
- break;
- case ESC_ESC:
- if (sl->flags & SLF_ESCAPE)
- sl_enqueue(sl, ESC);
- else
- sl_enqueue(sl, s);
- sl->flags &= ~SLF_ESCAPE;
- break;
- case ESC_END:
- if (sl->flags & SLF_ESCAPE)
- sl_enqueue(sl, END);
- else
- sl_enqueue(sl, s);
- sl->flags &= ~SLF_ESCAPE;
- break;
- case END:
- if (sl->rcount > 2)
- sl_bump(sl);
- sl_dequeue(sl, sl->rcount);
- sl->rcount = 0;
- sl->flags &= ~(SLF_ESCAPE | SLF_ERROR);
- break;
- default:
- sl_enqueue(sl, s);
- sl->flags &= ~SLF_ESCAPE;
- }
- }
-
-
- /************************************************************************
- * 6 BIT SLIP ENCAPSULATION *
- ************************************************************************
- *
- */
-
- int
- slip_esc6(unsigned char *s, unsigned char *d, int len)
- {
- int count = 0;
- int i;
- unsigned short v = 0;
- short bits = 0;
-
- /*
- * Send an initial END character to flush out any
- * data that may have accumulated in the receiver
- * due to line noise.
- */
-
- d[count++] = 0x70;
-
- /*
- * Encode the packet into printable ascii characters
- */
-
- for (i = 0; i < len; ++i) {
- v = (v << 8) | s[i];
- bits += 8;
- while (bits >= 6) {
- unsigned char c;
-
- bits -= 6;
- c = 0x30 + ((v >> bits) & 0x3F);
- d[count++] = c;
- }
- }
- if (bits) {
- unsigned char c;
-
- c = 0x30 + ((v << (6 - bits)) & 0x3F);
- d[count++] = c;
- }
- d[count++] = 0x70;
- return(count);
- }
-
- void
- slip_unesc6(struct slip *sl, unsigned char s)
- {
- unsigned char c;
-
- if (s == 0x70) {
- if (sl->rcount > 8) { /* XXX must be 2 for compressed slip */
- #ifdef NOTDEF
- printk("rbuff %02x %02x %02x %02x\n",
- sl->rbuff[0],
- sl->rbuff[1],
- sl->rbuff[2],
- sl->rbuff[3]
- );
- #endif
- sl_bump(sl);
- }
- sl_dequeue(sl, sl->rcount);
- sl->rcount = 0;
- sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); /* SLF_ESCAPE not used */
- sl->xbits = 0;
+ * STANDARD SLIP ENCAPSULATION *
+ ************************************************************************/
+
+int
+slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+ unsigned char *ptr = d;
+ unsigned char c;
+
+ /*
+ * Send an initial END character to flush out any
+ * data that may have accumulated in the receiver
+ * due to line noise.
+ */
+
+ *ptr++ = END;
+
+ /*
+ * For each byte in the packet, send the appropriate
+ * character sequence, according to the SLIP protocol.
+ */
+
+ while (len-- > 0) {
+ switch(c = *s++) {
+ case END:
+ *ptr++ = ESC;
+ *ptr++ = ESC_END;
+ break;
+ case ESC:
+ *ptr++ = ESC;
+ *ptr++ = ESC_ESC;
+ break;
+ default:
+ *ptr++ = c;
+ break;
+ }
+ }
+ *ptr++ = END;
+ return (ptr - d);
+}
+
+static void
+slip_unesc(struct slip *sl, unsigned char s)
+{
+
+ switch(s) {
+ case END:
+ if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
+ sl_bump(sl);
+ }
+ clear_bit(SLF_ESCAPE, &sl->flags);
+ sl->rcount = 0;
+ return;
+
+ case ESC:
+ set_bit(SLF_ESCAPE, &sl->flags);
+ return;
+ case ESC_ESC:
+ if (clear_bit(SLF_ESCAPE, &sl->flags)) {
+ s = ESC;
+ }
+ break;
+ case ESC_END:
+ if (clear_bit(SLF_ESCAPE, &sl->flags)) {
+ s = END;
+ }
+ break;
+ }
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < sl->buffsize) {
+ sl->rbuff[sl->rcount++] = s;
+ return;
+ }
+ sl->rx_over_errors++;
+ set_bit(SLF_ERROR, &sl->flags);
+ }
+}
+
+
+#ifdef CONFIG_SLIP_MODE_SLIP6
+/************************************************************************
+ * 6 BIT SLIP ENCAPSULATION *
+ ************************************************************************/
+
+int
+slip_esc6(unsigned char *s, unsigned char *d, int len)
+{
+ unsigned char *ptr = d;
+ unsigned char c;
+ int i;
+ unsigned short v = 0;
+ short bits = 0;
+
+ /*
+ * Send an initial END character to flush out any
+ * data that may have accumulated in the receiver
+ * due to line noise.
+ */
+
+ *ptr++ = 0x70;
+
+ /*
+ * Encode the packet into printable ascii characters
+ */
+
+ for (i = 0; i < len; ++i) {
+ v = (v << 8) | s[i];
+ bits += 8;
+ while (bits >= 6) {
+ bits -= 6;
+ c = 0x30 + ((v >> bits) & 0x3F);
+ *ptr++ = c;
+ }
+ }
+ if (bits) {
+ c = 0x30 + ((v << (6 - bits)) & 0x3F);
+ *ptr++ = c;
+ }
+ *ptr++ = 0x70;
+ return ptr - d;
+}
+
+void
+slip_unesc6(struct slip *sl, unsigned char s)
+{
+ unsigned char c;
+
+ if (s == 0x70) {
+ if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
+ sl_bump(sl);
+ }
+ sl->rcount = 0;
+ sl->xbits = 0;
+ sl->xdata = 0;
} else if (s >= 0x30 && s < 0x70) {
sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
sl->xbits += 6;
if (sl->xbits >= 8) {
sl->xbits -= 8;
c = (unsigned char)(sl->xdata >> sl->xbits);
- sl_enqueue(sl, c);
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < sl->buffsize) {
+ sl->rbuff[sl->rcount++] = c;
+ return;
+ }
+ sl->rx_over_errors++;
+ set_bit(SLF_ERROR, &sl->flags);
+ }
}
}
- }
-
-
+}
+#endif /* CONFIG_SLIP_MODE_SLIP6 */
#ifdef CONFIG_AX25
-
-int sl_set_mac_address(struct device *dev, void *addr)
+int
+sl_set_mac_address(struct device *dev, void *addr)
{
- int err=verify_area(VERIFY_READ,addr,7);
- if(err)
+ int err;
+
+ err = verify_area(VERIFY_READ, addr, 7);
+ if (err) {
return err;
- memcpy_fromfs(dev->dev_addr,addr,7); /* addr is an AX.25 shifted ASCII mac address */
+ }
+
+ memcpy_fromfs(dev->dev_addr, addr, 7); /* addr is an AX.25 shifted ASCII mac address */
+
return 0;
}
-static int sl_set_dev_mac_address(struct device *dev, void *addr)
+static int
+sl_set_dev_mac_address(struct device *dev, void *addr)
{
- memcpy(dev->dev_addr,addr,7);
+ memcpy(dev->dev_addr, addr, 7);
return 0;
}
-#endif
+#endif /* CONFIG_AX25 */
/* Perform I/O control on an active SLIP channel. */
static int
slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
{
- struct slip *sl = (struct slip *) tty->disc_data;
- int err;
-
- /* First make sure we're connected. */
- if (!sl || sl->magic != SLIP_MAGIC) {
- return(-EINVAL);
- }
-
- switch(cmd) {
- case SIOCGIFNAME:
- err=verify_area(VERIFY_WRITE, arg, 16);
- if(err)
+ struct slip *sl = (struct slip *) tty->disc_data;
+ int err;
+ unsigned int tmp;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLIP_MAGIC) {
+ return -EINVAL;
+ }
+
+ switch(cmd) {
+ case SIOCGIFNAME:
+ err = verify_area(VERIFY_WRITE, arg, 16);
+ if (err) {
return -err;
+ }
memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1);
- return(0);
+ return 0;
+
case SIOCGIFENCAP:
- err=verify_area(VERIFY_WRITE,arg,sizeof(long));
- put_fs_long(sl->mode,(long *)arg);
- return(0);
+ err = verify_area(VERIFY_WRITE, arg, sizeof(long));
+ if (err) {
+ return -err;
+ }
+ put_fs_long(sl->mode, (long *)arg);
+ return 0;
+
case SIOCSIFENCAP:
- err=verify_area(VERIFY_READ,arg,sizeof(long));
- sl->mode=get_fs_long((long *)arg);
-#ifdef CONFIG_AX25
- if(sl->mode & SL_MODE_AX25)
- {
+ err = verify_area(VERIFY_READ, arg, sizeof(long));
+ if (err) {
+ return -err;
+ }
+ tmp = get_fs_long((long *)arg);
+#ifndef SL_INCLUDE_CSLIP
+ if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) {
+ return -EINVAL;
+ }
+#else
+ if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
+ (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
+ /* return -EINVAL; */
+ tmp &= ~SL_MODE_ADAPTIVE;
+ }
+#endif
+#ifndef CONFIG_SLIP_MODE_SLIP6
+ if (tmp & SL_MODE_SLIP6) {
+ return -EINVAL;
+ }
+#endif
+#ifndef CONFIG_AX25
+ if ((tmp & SL_MODE_AX25) || (tmp & SL_MODE_AX25VC)) {
+ return -EINVAL;
+ }
+#else
+ if ((tmp & SL_MODE_AX25) || (tmp & SL_MODE_AX25VC)) {
sl->dev->addr_len=7; /* sizeof an AX.25 addr */
sl->dev->hard_header_len=17; /* We don't do digipeaters */
- }
- else
- {
+ } else {
sl->dev->addr_len=0; /* No mac addr in slip mode */
sl->dev->hard_header_len=0;
}
+#endif
+ sl->mode = tmp;
+ sl->dev->type = ARPHRD_SLIP+sl->mode;
+#ifdef CONFIG_AX25
+ if (sl->dev->type == 260 || sl->dev->type == 272) {
+ sl->dev->type = ARPHRD_AX25;
+ }
#endif
- sl->dev->type=ARPHRD_SLIP+sl->mode;
- if(sl->dev->type==260)
- sl->dev->type=ARPHRD_AX25;
- return(0);
- case SIOCSIFHWADDR:
-#ifdef CONFIG_AX25
- return sl_set_mac_address(sl->dev,arg);
+ return 0;
+
+ case SIOCSIFHWADDR:
+#ifdef CONFIG_AX25
+ return sl_set_mac_address(sl->dev, arg);
+#else
+ return -EINVAL;
#endif
+
/* Allow stty to read, but not set, the serial port */
case TCGETS:
case TCGETA:
return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
-
+
default:
return -ENOIOCTLCMD;
- }
+ }
}
+static int sl_open_dev(struct device *dev)
+{
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+ if(sl->tty==NULL)
+ return -ENODEV;
+ return 0;
+}
/* Initialize the SLIP driver. Called by DDI. */
int
slip_init(struct device *dev)
{
- struct slip *sl;
- int i;
-#ifdef CONFIG_AX25
- static char ax25_bcast[7]={'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
- static char ax25_test[7]={'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
+ struct slip *sl = &sl_ctrl[dev->base_addr];
+ int i;
+#ifdef CONFIG_AX25
+ static char ax25_bcast[7] =
+ {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
+ static char ax25_test[7] =
+ {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
#endif
- sl = &sl_ctrl[dev->base_addr];
-
- if (already++ == 0) {
- printk("SLIP: version %s (%d channels)\n",
- SLIP_VERSION, SL_NRUNIT);
-#ifdef SL_COMPRESSED
- printk("CSLIP: code copyright 1989 Regents of the University of California\n");
+ if (already++ == 0) {
+ printk("SLIP: version %s (%d channels) %s\n",
+ SLIP_VERSION, SL_NRUNIT,
+#ifdef CONFIG_SLIP_MODE_SLIP6
+ "(6 bit encapsulation enabled)"
+#else
+ ""
+#endif
+ );
+#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)
+ printk("CSLIP: code copyright 1989 Regents of the University of California\n");
#endif
#ifdef CONFIG_AX25
- printk("AX25: KISS encapsulation enabled\n");
+ printk("AX25: KISS encapsulation enabled\n");
#endif
- /* Fill in our LDISC request block. */
- memset(&sl_ldisc, 0, sizeof(sl_ldisc));
- sl_ldisc.magic = TTY_LDISC_MAGIC;
- sl_ldisc.flags = 0;
- sl_ldisc.open = slip_open;
- sl_ldisc.close = slip_close;
- sl_ldisc.read = NULL;
- sl_ldisc.write = NULL;
- sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *,
- unsigned int, unsigned long)) slip_ioctl;
- sl_ldisc.select = NULL;
- sl_ldisc.receive_buf = slip_receive_buf;
- sl_ldisc.receive_room = slip_receive_room;
- sl_ldisc.write_wakeup = slip_write_wakeup;
- if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)
- printk("ERROR: %d\n", i);
- }
-
- /* Set up the "SLIP Control Block". */
- sl_initialize(sl, dev);
-
- /* Clear all statistics. */
- sl->rcount = 0; /* SLIP receiver count */
- sl->rpacket = 0; /* #frames received */
- sl->roverrun = 0; /* "overrun" counter */
- sl->spacket = 0; /* #frames sent out */
- sl->sbusy = 0; /* "xmit busy" counter */
- sl->errors = 0; /* not used at present */
-
- /* Finish setting up the DEVICE info. */
- dev->mtu = SL_MTU;
- dev->hard_start_xmit = sl_xmit;
- dev->open = sl_open;
- dev->stop = sl_close;
- dev->hard_header = sl_header;
- dev->type_trans = sl_type_trans;
- dev->get_stats = sl_get_stats;
+ /* Fill in our LDISC request block. */
+ memset(&sl_ldisc, 0, sizeof(sl_ldisc));
+ sl_ldisc.magic = TTY_LDISC_MAGIC;
+ sl_ldisc.flags = 0;
+ sl_ldisc.open = slip_open;
+ sl_ldisc.close = slip_close;
+ sl_ldisc.read = NULL;
+ sl_ldisc.write = NULL;
+ sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *,
+ unsigned int, unsigned long)) slip_ioctl;
+ sl_ldisc.select = NULL;
+ sl_ldisc.receive_buf = slip_receive_buf;
+ sl_ldisc.receive_room = slip_receive_room;
+ sl_ldisc.write_wakeup = slip_write_wakeup;
+ if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
+ printk("SLIP: can't register line discipline (err = %d)\n", i);
+ }
+ }
+
+ /* Set up the "SLIP Control Block". (And clear statistics) */
+
+ memset(sl, 0, sizeof (struct slip));
+ sl->magic = SLIP_MAGIC;
+ sl->dev = dev;
+
+ /* Finish setting up the DEVICE info. */
+ dev->mtu = SL_MTU;
+ dev->hard_start_xmit = sl_xmit;
+ dev->open = sl_open_dev;
+ dev->stop = sl_close;
+ dev->hard_header = sl_header;
+ dev->get_stats = sl_get_stats;
#ifdef HAVE_SET_MAC_ADDR
#ifdef CONFIG_AX25
- dev->set_mac_address = sl_set_dev_mac_address;
+ dev->set_mac_address = sl_set_dev_mac_address;
+#endif
#endif
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP + SL_MODE_DEFAULT;
+#ifdef CONFIG_AX25
+ if (sl->dev->type == 260 || sl->dev->type == 272) {
+ sl->dev->type = ARPHRD_AX25;
+ }
+ memcpy(dev->broadcast, ax25_bcast, 7); /* Only activated in AX.25 mode */
+ memcpy(dev->dev_addr, ax25_test, 7); /* "" "" "" "" */
#endif
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = 0;
-#ifdef CONFIG_AX25
- memcpy(dev->broadcast,ax25_bcast,7); /* Only activated in AX.25 mode */
- memcpy(dev->dev_addr,ax25_test,7); /* "" "" "" "" */
-#endif
- dev->rebuild_header = sl_rebuild_header;
- for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init(&dev->buffs[i]);
-
- /* New-style flags. */
- dev->flags = 0;
- dev->family = AF_INET;
- dev->pa_addr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = sizeof(unsigned long);
-
- return(0);
+ dev->rebuild_header = sl_rebuild_header;
+
+ for (i = 0; i < DEV_NUMBUFFS; i++) {
+ skb_queue_head_init(&dev->buffs[i]);
+ }
+
+ /* New-style flags. */
+ dev->flags = 0;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = sizeof(unsigned long);
+
+ return 0;
+}
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+static struct device dev_slip[SL_NRUNIT] = {
+ {
+ "sl0", /* slip */
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, slip_init,
+ },
+ { "sl1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, slip_init },
+ { "sl2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, slip_init },
+ { "sl3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, slip_init },
+#ifdef SL_SLIP_LOTS
+ { "sl4" , 0, 0, 0, 0, 4, 0, 0, 0, 0, NULL, slip_init },
+ { "sl5" , 0, 0, 0, 0, 5, 0, 0, 0, 0, NULL, slip_init },
+ { "sl6" , 0, 0, 0, 0, 6, 0, 0, 0, 0, NULL, slip_init },
+ { "sl7" , 0, 0, 0, 0, 7, 0, 0, 0, 0, NULL, slip_init },
+ { "sl8" , 0, 0, 0, 0, 8, 0, 0, 0, 0, NULL, slip_init },
+ { "sl9" , 0, 0, 0, 0, 9, 0, 0, 0, 0, NULL, slip_init },
+ { "sl10", 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, slip_init },
+ { "sl11", 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, slip_init },
+ { "sl12", 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, slip_init },
+ { "sl13", 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, slip_init },
+ { "sl14", 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, slip_init },
+ { "sl15", 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, slip_init },
+#endif /* SL_SLIP_LOTS */
+};
+
+int
+init_module(void)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < SL_NRUNIT; i++) {
+ if ((err = register_netdev(&dev_slip[i]))) {
+ if (err == -EEXIST) {
+ printk("SLIP: devices already present. Module not loaded.\n");
+ }
+ return err;
+ }
+ }
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ int i;
+
+ if (MOD_IN_USE) {
+ printk("SLIP: device busy, remove delayed\n");
+ return;
+ }
+ for (i = 0; i < SL_NRUNIT; i++) {
+ unregister_netdev(&dev_slip[i]);
+ }
+ if ((i = tty_register_ldisc(N_SLIP, NULL))) {
+ printk("SLIP: can't unregister line discipline (err = %d)\n", i);
+ }
+ already = 0;
}
+#endif /* MODULE */