blob: 25cec06d6dcc661f0c6bcbb6f039555b529ea836 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * slip.c This module implements the SLIP protocol for kernel-based
3 * devices like TTY. It interfaces between a raw TTY, and the
4 * kernel's INET protocol layers.
5 *
6 * Version: @(#)slip.c 0.8.3 12/24/94
7 *
8 * Authors: Laurence Culhane, <loz@holmes.demon.co.uk>
9 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10 *
11 * Fixes:
12 * Alan Cox : Sanity checks and avoid tx overruns.
13 * Has a new sl->mtu field.
Alan Cox9ce6cf22007-11-19 15:03:38 +000014 * Alan Cox : Found cause of overrun. ifconfig sl0
15 * mtu upwards. Driver now spots this
16 * and grows/shrinks its buffers(hack!).
17 * Memory leak if you run out of memory
18 * setting up a slip driver fixed.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 * Matt Dillon : Printable slip (borrowed from NET2E)
20 * Pauline Middelink : Slip driver fixes.
21 * Alan Cox : Honours the old SL_COMPRESSED flag
22 * Alan Cox : KISS AX.25 and AXUI IP support
23 * Michael Riepe : Automatic CSLIP recognition added
24 * Charles Hedrick : CSLIP header length problem fix.
25 * Alan Cox : Corrected non-IP cases of the above.
26 * Alan Cox : Now uses hardware type as per FvK.
27 * Alan Cox : Default to 192.168.0.0 (RFC 1597)
28 * A.N.Kuznetsov : dev_tint() recursion fix.
29 * Dmitry Gorodchanin : SLIP memory leaks
30 * Dmitry Gorodchanin : Code cleanup. Reduce tty driver
31 * buffering from 4096 to 256 bytes.
32 * Improving SLIP response time.
33 * CONFIG_SLIP_MODE_SLIP6.
Alan Cox9ce6cf22007-11-19 15:03:38 +000034 * ifconfig sl? up & down now works
35 * correctly.
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 * Modularization.
37 * Alan Cox : Oops - fix AX.25 buffer lengths
38 * Dmitry Gorodchanin : Even more cleanups. Preserve CSLIP
39 * statistics. Include CSLIP code only
40 * if it really needed.
41 * Alan Cox : Free slhc buffers in the right place.
42 * Alan Cox : Allow for digipeated IP over AX.25
43 * Matti Aarnio : Dynamic SLIP devices, with ideas taken
44 * from Jim Freeman's <jfree@caldera.com>
45 * dynamic PPP devices. We do NOT kfree()
46 * device entries, just reg./unreg. them
47 * as they are needed. We kfree() them
48 * at module cleanup.
Alan Cox9ce6cf22007-11-19 15:03:38 +000049 * With MODULE-loading ``insmod'', user
50 * can issue parameter: slip_maxdev=1024
51 * (Or how much he/she wants.. Default
52 * is 256)
53 * Stanislav Voronyi : Slip line checking, with ideas taken
54 * from multislip BSDI driver which was
55 * written by Igor Chechik, RELCOM Corp.
56 * Only algorithms have been ported to
57 * Linux SLIP driver.
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 * Vitaly E. Lavrov : Sane behaviour on tty hangup.
Alan Cox9ce6cf22007-11-19 15:03:38 +000059 * Alexey Kuznetsov : Cleanup interfaces to tty & netdevice
60 * modules.
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 */
62
63#define SL_CHECK_TRANSMIT
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <linux/module.h>
65#include <linux/moduleparam.h>
66
67#include <asm/system.h>
68#include <asm/uaccess.h>
69#include <linux/bitops.h>
70#include <linux/string.h>
71#include <linux/mm.h>
72#include <linux/interrupt.h>
73#include <linux/in.h>
74#include <linux/tty.h>
75#include <linux/errno.h>
76#include <linux/netdevice.h>
77#include <linux/etherdevice.h>
78#include <linux/skbuff.h>
79#include <linux/rtnetlink.h>
80#include <linux/if_arp.h>
81#include <linux/if_slip.h>
David S. Miller12dc2fd2005-06-28 16:27:32 -070082#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/init.h>
84#include "slip.h"
85#ifdef CONFIG_INET
86#include <linux/ip.h>
87#include <linux/tcp.h>
88#include <net/slhc_vj.h>
89#endif
90
91#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY"
92
93static struct net_device **slip_devs;
94
95static int slip_maxdev = SL_NRUNIT;
96module_param(slip_maxdev, int, 0);
97MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices");
98
99static int slip_esc(unsigned char *p, unsigned char *d, int len);
100static void slip_unesc(struct slip *sl, unsigned char c);
101#ifdef CONFIG_SLIP_MODE_SLIP6
102static int slip_esc6(unsigned char *p, unsigned char *d, int len);
103static void slip_unesc6(struct slip *sl, unsigned char c);
104#endif
105#ifdef CONFIG_SLIP_SMART
106static void sl_keepalive(unsigned long sls);
107static void sl_outfill(unsigned long sls);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000108static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#endif
110
111/********************************
112* Buffer administration routines:
113* sl_alloc_bufs()
114* sl_free_bufs()
115* sl_realloc_bufs()
116*
117* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because
118* sl_realloc_bufs provides strong atomicity and reallocation
119* on actively running device.
120*********************************/
121
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400122/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 Allocate channel buffers.
124 */
125
Alan Cox9ce6cf22007-11-19 15:03:38 +0000126static int sl_alloc_bufs(struct slip *sl, int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 int err = -ENOBUFS;
129 unsigned long len;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000130 char *rbuff = NULL;
131 char *xbuff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132#ifdef SL_INCLUDE_CSLIP
Alan Cox9ce6cf22007-11-19 15:03:38 +0000133 char *cbuff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct slcompress *slcomp = NULL;
135#endif
136
137 /*
138 * Allocate the SLIP frame buffers:
139 *
140 * rbuff Receive buffer.
141 * xbuff Transmit buffer.
142 * cbuff Temporary compression buffer.
143 */
144 len = mtu * 2;
145
146 /*
147 * allow for arrival of larger UDP packets, even if we say not to
148 * also fixes a bug in which SunOS sends 512-byte packets even with
149 * an MSS of 128
150 */
151 if (len < 576 * 2)
152 len = 576 * 2;
153 rbuff = kmalloc(len + 4, GFP_KERNEL);
154 if (rbuff == NULL)
155 goto err_exit;
156 xbuff = kmalloc(len + 4, GFP_KERNEL);
157 if (xbuff == NULL)
158 goto err_exit;
159#ifdef SL_INCLUDE_CSLIP
160 cbuff = kmalloc(len + 4, GFP_KERNEL);
161 if (cbuff == NULL)
162 goto err_exit;
163 slcomp = slhc_init(16, 16);
164 if (slcomp == NULL)
165 goto err_exit;
166#endif
167 spin_lock_bh(&sl->lock);
168 if (sl->tty == NULL) {
169 spin_unlock_bh(&sl->lock);
170 err = -ENODEV;
171 goto err_exit;
172 }
173 sl->mtu = mtu;
174 sl->buffsize = len;
175 sl->rcount = 0;
176 sl->xleft = 0;
177 rbuff = xchg(&sl->rbuff, rbuff);
178 xbuff = xchg(&sl->xbuff, xbuff);
179#ifdef SL_INCLUDE_CSLIP
180 cbuff = xchg(&sl->cbuff, cbuff);
181 slcomp = xchg(&sl->slcomp, slcomp);
182#ifdef CONFIG_SLIP_MODE_SLIP6
183 sl->xdata = 0;
184 sl->xbits = 0;
185#endif
186#endif
187 spin_unlock_bh(&sl->lock);
188 err = 0;
189
190 /* Cleanup */
191err_exit:
192#ifdef SL_INCLUDE_CSLIP
Jesper Juhl158a0e42005-04-24 18:59:30 -0700193 kfree(cbuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 if (slcomp)
195 slhc_free(slcomp);
196#endif
Jesper Juhl158a0e42005-04-24 18:59:30 -0700197 kfree(xbuff);
198 kfree(rbuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 return err;
200}
201
202/* Free a SLIP channel buffers. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000203static void sl_free_bufs(struct slip *sl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 /* Free all SLIP frame buffers. */
Jesper Juhl9b200b02005-06-23 21:06:56 -0700206 kfree(xchg(&sl->rbuff, NULL));
207 kfree(xchg(&sl->xbuff, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208#ifdef SL_INCLUDE_CSLIP
Jesper Juhl9b200b02005-06-23 21:06:56 -0700209 kfree(xchg(&sl->cbuff, NULL));
210 slhc_free(xchg(&sl->slcomp, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211#endif
212}
213
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400214/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 Reallocate slip channel buffers.
216 */
217
218static int sl_realloc_bufs(struct slip *sl, int mtu)
219{
220 int err = 0;
221 struct net_device *dev = sl->dev;
222 unsigned char *xbuff, *rbuff;
223#ifdef SL_INCLUDE_CSLIP
224 unsigned char *cbuff;
225#endif
226 int len = mtu * 2;
227
228/*
229 * allow for arrival of larger UDP packets, even if we say not to
230 * also fixes a bug in which SunOS sends 512-byte packets even with
231 * an MSS of 128
232 */
233 if (len < 576 * 2)
234 len = 576 * 2;
235
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800236 xbuff = kmalloc(len + 4, GFP_ATOMIC);
237 rbuff = kmalloc(len + 4, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238#ifdef SL_INCLUDE_CSLIP
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800239 cbuff = kmalloc(len + 4, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240#endif
241
242
243#ifdef SL_INCLUDE_CSLIP
244 if (xbuff == NULL || rbuff == NULL || cbuff == NULL) {
245#else
246 if (xbuff == NULL || rbuff == NULL) {
247#endif
248 if (mtu >= sl->mtu) {
249 printk(KERN_WARNING "%s: unable to grow slip buffers, MTU change cancelled.\n",
250 dev->name);
251 err = -ENOBUFS;
252 }
253 goto done;
254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 spin_lock_bh(&sl->lock);
256
257 err = -ENODEV;
258 if (sl->tty == NULL)
259 goto done_on_bh;
260
261 xbuff = xchg(&sl->xbuff, xbuff);
262 rbuff = xchg(&sl->rbuff, rbuff);
263#ifdef SL_INCLUDE_CSLIP
264 cbuff = xchg(&sl->cbuff, cbuff);
265#endif
266 if (sl->xleft) {
267 if (sl->xleft <= len) {
268 memcpy(sl->xbuff, sl->xhead, sl->xleft);
269 } else {
270 sl->xleft = 0;
271 sl->tx_dropped++;
272 }
273 }
274 sl->xhead = sl->xbuff;
275
276 if (sl->rcount) {
277 if (sl->rcount <= len) {
278 memcpy(sl->rbuff, rbuff, sl->rcount);
279 } else {
280 sl->rcount = 0;
281 sl->rx_over_errors++;
282 set_bit(SLF_ERROR, &sl->flags);
283 }
284 }
285 sl->mtu = mtu;
286 dev->mtu = mtu;
287 sl->buffsize = len;
288 err = 0;
289
290done_on_bh:
291 spin_unlock_bh(&sl->lock);
292
293done:
Jesper Juhl158a0e42005-04-24 18:59:30 -0700294 kfree(xbuff);
295 kfree(rbuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296#ifdef SL_INCLUDE_CSLIP
Jesper Juhl158a0e42005-04-24 18:59:30 -0700297 kfree(cbuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298#endif
299 return err;
300}
301
302
303/* Set the "sending" flag. This must be atomic hence the set_bit. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000304static inline void sl_lock(struct slip *sl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 netif_stop_queue(sl->dev);
307}
308
309
310/* Clear the "sending" flag. This must be atomic, hence the ASM. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000311static inline void sl_unlock(struct slip *sl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
313 netif_wake_queue(sl->dev);
314}
315
316/* Send one completely decapsulated IP datagram to the IP layer. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000317static void sl_bump(struct slip *sl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 struct sk_buff *skb;
320 int count;
321
322 count = sl->rcount;
323#ifdef SL_INCLUDE_CSLIP
324 if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000325 unsigned char c = sl->rbuff[0];
326 if (c & SL_TYPE_COMPRESSED_TCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 /* ignore compressed packets when CSLIP is off */
328 if (!(sl->mode & SL_MODE_CSLIP)) {
329 printk(KERN_WARNING "%s: compressed packet ignored\n", sl->dev->name);
330 return;
331 }
Alan Cox9ce6cf22007-11-19 15:03:38 +0000332 /* make sure we've reserved enough space for uncompress
333 to use */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 if (count + 80 > sl->buffsize) {
335 sl->rx_over_errors++;
336 return;
337 }
338 count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000339 if (count <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
342 if (!(sl->mode & SL_MODE_CSLIP)) {
343 /* turn on header compression */
344 sl->mode |= SL_MODE_CSLIP;
345 sl->mode &= ~SL_MODE_ADAPTIVE;
346 printk(KERN_INFO "%s: header compression turned on\n", sl->dev->name);
347 }
348 sl->rbuff[0] &= 0x4f;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000349 if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
352 }
353#endif /* SL_INCLUDE_CSLIP */
354
Alan Cox9ce6cf22007-11-19 15:03:38 +0000355 sl->rx_bytes += count;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 skb = dev_alloc_skb(count);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000358 if (skb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
360 sl->rx_dropped++;
361 return;
362 }
363 skb->dev = sl->dev;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000364 memcpy(skb_put(skb, count), sl->rbuff, count);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700365 skb_reset_mac_header(skb);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000366 skb->protocol = htons(ETH_P_IP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 netif_rx(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 sl->rx_packets++;
369}
370
371/* Encapsulate one IP datagram and stuff into a TTY queue. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000372static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 unsigned char *p;
375 int actual, count;
376
377 if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */
378 printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name);
379 sl->tx_dropped++;
380 sl_unlock(sl);
381 return;
382 }
383
384 p = icp;
385#ifdef SL_INCLUDE_CSLIP
Alan Cox9ce6cf22007-11-19 15:03:38 +0000386 if (sl->mode & SL_MODE_CSLIP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388#endif
389#ifdef CONFIG_SLIP_MODE_SLIP6
Alan Cox9ce6cf22007-11-19 15:03:38 +0000390 if (sl->mode & SL_MODE_SLIP6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
392 else
393#endif
394 count = slip_esc(p, (unsigned char *) sl->xbuff, len);
395
396 /* Order of next two lines is *very* important.
397 * When we are sending a little amount of data,
Alan Coxf34d7a52008-04-30 00:54:13 -0700398 * the transfer may be completed inside the ops->write()
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 * routine, because it's running with interrupts enabled.
400 * In this case we *never* got WRITE_WAKEUP event,
401 * if we did not request it before write operation.
402 * 14 Oct 1994 Dmitry Gorodchanin.
403 */
404 sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
Alan Coxf34d7a52008-04-30 00:54:13 -0700405 actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#ifdef SL_CHECK_TRANSMIT
407 sl->dev->trans_start = jiffies;
408#endif
409 sl->xleft = count - actual;
410 sl->xhead = sl->xbuff + actual;
411#ifdef CONFIG_SLIP_SMART
412 /* VSV */
413 clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
414#endif
415}
416
417/*
418 * Called by the driver when there's room for more data. If we have
419 * more packets to send, we send them here.
420 */
421static void slip_write_wakeup(struct tty_struct *tty)
422{
423 int actual;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000424 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 /* First make sure we're connected. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000427 if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 return;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 if (sl->xleft <= 0) {
431 /* Now serial buffer is almost free & we can start
432 * transmission of another packet */
433 sl->tx_packets++;
434 tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
435 sl_unlock(sl);
436 return;
437 }
438
Alan Coxf34d7a52008-04-30 00:54:13 -0700439 actual = tty->ops->write(tty, sl->xhead, sl->xleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 sl->xleft -= actual;
441 sl->xhead += actual;
442}
443
444static void sl_tx_timeout(struct net_device *dev)
445{
446 struct slip *sl = netdev_priv(dev);
447
448 spin_lock(&sl->lock);
449
450 if (netif_queue_stopped(dev)) {
451 if (!netif_running(dev))
452 goto out;
453
454 /* May be we must check transmitter timeout here ?
455 * 14 Oct 1994 Dmitry Gorodchanin.
456 */
457#ifdef SL_CHECK_TRANSMIT
458 if (time_before(jiffies, dev->trans_start + 20 * HZ)) {
459 /* 20 sec timeout not reached */
460 goto out;
461 }
Alan Cox9ce6cf22007-11-19 15:03:38 +0000462 printk(KERN_WARNING "%s: transmit timed out, %s?\n",
463 dev->name,
Alan Coxf34d7a52008-04-30 00:54:13 -0700464 (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
Alan Cox9ce6cf22007-11-19 15:03:38 +0000465 "bad line quality" : "driver error");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 sl->xleft = 0;
467 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
468 sl_unlock(sl);
469#endif
470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471out:
472 spin_unlock(&sl->lock);
473}
474
475
476/* Encapsulate an IP datagram and kick it into a TTY queue. */
477static int
478sl_xmit(struct sk_buff *skb, struct net_device *dev)
479{
480 struct slip *sl = netdev_priv(dev);
481
482 spin_lock(&sl->lock);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000483 if (!netif_running(dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 spin_unlock(&sl->lock);
485 printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
486 dev_kfree_skb(skb);
487 return 0;
488 }
489 if (sl->tty == NULL) {
490 spin_unlock(&sl->lock);
491 dev_kfree_skb(skb);
492 return 0;
493 }
494
495 sl_lock(sl);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000496 sl->tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 sl_encaps(sl, skb->data, skb->len);
498 spin_unlock(&sl->lock);
499
500 dev_kfree_skb(skb);
501 return 0;
502}
503
504
505/******************************************
506 * Routines looking at netdevice side.
507 ******************************************/
508
509/* Netdevice UP -> DOWN routine */
510
511static int
512sl_close(struct net_device *dev)
513{
514 struct slip *sl = netdev_priv(dev);
515
516 spin_lock_bh(&sl->lock);
517 if (sl->tty) {
518 /* TTY discipline is running. */
519 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
520 }
521 netif_stop_queue(dev);
522 sl->rcount = 0;
523 sl->xleft = 0;
524 spin_unlock_bh(&sl->lock);
525
526 return 0;
527}
528
529/* Netdevice DOWN -> UP routine */
530
531static int sl_open(struct net_device *dev)
532{
533 struct slip *sl = netdev_priv(dev);
534
Alan Cox9ce6cf22007-11-19 15:03:38 +0000535 if (sl->tty == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return -ENODEV;
537
538 sl->flags &= (1 << SLF_INUSE);
539 netif_start_queue(dev);
540 return 0;
541}
542
543/* Netdevice change MTU request */
544
545static int sl_change_mtu(struct net_device *dev, int new_mtu)
546{
547 struct slip *sl = netdev_priv(dev);
548
549 if (new_mtu < 68 || new_mtu > 65534)
550 return -EINVAL;
551
552 if (new_mtu != dev->mtu)
553 return sl_realloc_bufs(sl, new_mtu);
554 return 0;
555}
556
557/* Netdevice get statistics request */
558
559static struct net_device_stats *
560sl_get_stats(struct net_device *dev)
561{
562 static struct net_device_stats stats;
563 struct slip *sl = netdev_priv(dev);
564#ifdef SL_INCLUDE_CSLIP
565 struct slcompress *comp;
566#endif
567
568 memset(&stats, 0, sizeof(struct net_device_stats));
569
570 stats.rx_packets = sl->rx_packets;
571 stats.tx_packets = sl->tx_packets;
572 stats.rx_bytes = sl->rx_bytes;
573 stats.tx_bytes = sl->tx_bytes;
574 stats.rx_dropped = sl->rx_dropped;
575 stats.tx_dropped = sl->tx_dropped;
576 stats.tx_errors = sl->tx_errors;
577 stats.rx_errors = sl->rx_errors;
578 stats.rx_over_errors = sl->rx_over_errors;
579#ifdef SL_INCLUDE_CSLIP
580 stats.rx_fifo_errors = sl->rx_compressed;
581 stats.tx_fifo_errors = sl->tx_compressed;
582 stats.collisions = sl->tx_misses;
583 comp = sl->slcomp;
584 if (comp) {
585 stats.rx_fifo_errors += comp->sls_i_compressed;
586 stats.rx_dropped += comp->sls_i_tossed;
587 stats.tx_fifo_errors += comp->sls_o_compressed;
588 stats.collisions += comp->sls_o_misses;
589 }
590#endif /* CONFIG_INET */
591 return (&stats);
592}
593
594/* Netdevice register callback */
595
596static int sl_init(struct net_device *dev)
597{
598 struct slip *sl = netdev_priv(dev);
599
600 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400601 * Finish setting up the DEVICE info.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 */
603
604 dev->mtu = sl->mtu;
605 dev->type = ARPHRD_SLIP + sl->mode;
606#ifdef SL_CHECK_TRANSMIT
607 dev->tx_timeout = sl_tx_timeout;
608 dev->watchdog_timeo = 20*HZ;
609#endif
610 return 0;
611}
612
613
614static void sl_uninit(struct net_device *dev)
615{
616 struct slip *sl = netdev_priv(dev);
617
618 sl_free_bufs(sl);
619}
620
621static void sl_setup(struct net_device *dev)
622{
623 dev->init = sl_init;
624 dev->uninit = sl_uninit;
625 dev->open = sl_open;
626 dev->destructor = free_netdev;
627 dev->stop = sl_close;
628 dev->get_stats = sl_get_stats;
629 dev->change_mtu = sl_change_mtu;
630 dev->hard_start_xmit = sl_xmit;
631#ifdef CONFIG_SLIP_SMART
632 dev->do_ioctl = sl_ioctl;
633#endif
634 dev->hard_header_len = 0;
635 dev->addr_len = 0;
636 dev->tx_queue_len = 10;
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* New-style flags. */
639 dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
640}
641
642/******************************************
643 Routines looking at TTY side.
644 ******************************************/
645
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647/*
648 * Handle the 'receiver data ready' interrupt.
649 * This function is called by the 'tty_io' module in the kernel when
650 * a block of SLIP data has been received, which can now be decapsulated
651 * and sent on to some IP layer for further processing. This will not
652 * be re-entered while running but other ldisc functions may be called
653 * in parallel
654 */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400655
Alan Cox9ce6cf22007-11-19 15:03:38 +0000656static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
657 char *fp, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
Alan Cox9ce6cf22007-11-19 15:03:38 +0000659 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Alan Cox9ce6cf22007-11-19 15:03:38 +0000661 if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return;
663
664 /* Read the characters out of the buffer */
665 while (count--) {
666 if (fp && *fp++) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000667 if (!test_and_set_bit(SLF_ERROR, &sl->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 sl->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 cp++;
670 continue;
671 }
672#ifdef CONFIG_SLIP_MODE_SLIP6
673 if (sl->mode & SL_MODE_SLIP6)
674 slip_unesc6(sl, *cp++);
675 else
676#endif
677 slip_unesc(sl, *cp++);
678 }
679}
680
681/************************************
682 * slip_open helper routines.
683 ************************************/
684
685/* Collect hanged up channels */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686static void sl_sync(void)
687{
688 int i;
689 struct net_device *dev;
690 struct slip *sl;
691
692 for (i = 0; i < slip_maxdev; i++) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000693 dev = slip_devs[i];
694 if (dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 break;
696
697 sl = netdev_priv(dev);
698 if (sl->tty || sl->leased)
699 continue;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000700 if (dev->flags & IFF_UP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 dev_close(dev);
702 }
703}
704
705
706/* Find a free SLIP channel, and link in this `tty' line. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000707static struct slip *sl_alloc(dev_t line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 int i;
710 int sel = -1;
711 int score = -1;
712 struct net_device *dev = NULL;
713 struct slip *sl;
714
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400715 if (slip_devs == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 return NULL; /* Master array missing ! */
717
718 for (i = 0; i < slip_maxdev; i++) {
719 dev = slip_devs[i];
720 if (dev == NULL)
721 break;
722
723 sl = netdev_priv(dev);
724 if (sl->leased) {
725 if (sl->line != line)
726 continue;
727 if (sl->tty)
728 return NULL;
729
730 /* Clear ESCAPE & ERROR flags */
731 sl->flags &= (1 << SLF_INUSE);
732 return sl;
733 }
734
735 if (sl->tty)
736 continue;
737
738 if (current->pid == sl->pid) {
739 if (sl->line == line && score < 3) {
740 sel = i;
741 score = 3;
742 continue;
743 }
744 if (score < 2) {
745 sel = i;
746 score = 2;
747 }
748 continue;
749 }
750 if (sl->line == line && score < 1) {
751 sel = i;
752 score = 1;
753 continue;
754 }
755 if (score < 0) {
756 sel = i;
757 score = 0;
758 }
759 }
760
761 if (sel >= 0) {
762 i = sel;
763 dev = slip_devs[i];
764 if (score > 1) {
765 sl = netdev_priv(dev);
766 sl->flags &= (1 << SLF_INUSE);
767 return sl;
768 }
769 }
770
771 /* Sorry, too many, all slots in use */
772 if (i >= slip_maxdev)
773 return NULL;
774
775 if (dev) {
776 sl = netdev_priv(dev);
777 if (test_bit(SLF_INUSE, &sl->flags)) {
778 unregister_netdevice(dev);
779 dev = NULL;
780 slip_devs[i] = NULL;
781 }
782 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (!dev) {
785 char name[IFNAMSIZ];
786 sprintf(name, "sl%d", i);
787
788 dev = alloc_netdev(sizeof(*sl), name, sl_setup);
789 if (!dev)
790 return NULL;
791 dev->base_addr = i;
792 }
793
794 sl = netdev_priv(dev);
795
796 /* Initialize channel control data */
797 sl->magic = SLIP_MAGIC;
798 sl->dev = dev;
799 spin_lock_init(&sl->lock);
800 sl->mode = SL_MODE_DEFAULT;
801#ifdef CONFIG_SLIP_SMART
Alan Cox9ce6cf22007-11-19 15:03:38 +0000802 /* initialize timer_list struct */
803 init_timer(&sl->keepalive_timer);
804 sl->keepalive_timer.data = (unsigned long)sl;
805 sl->keepalive_timer.function = sl_keepalive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 init_timer(&sl->outfill_timer);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000807 sl->outfill_timer.data = (unsigned long)sl;
808 sl->outfill_timer.function = sl_outfill;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809#endif
810 slip_devs[i] = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return sl;
812}
813
814/*
815 * Open the high-level part of the SLIP channel.
816 * This function is called by the TTY module when the
817 * SLIP line discipline is called for. Because we are
818 * sure the tty line exists, we only have to link it to
819 * a free SLIP channel...
820 *
821 * Called in process context serialized from other ldisc calls.
822 */
823
824static int slip_open(struct tty_struct *tty)
825{
826 struct slip *sl;
827 int err;
828
Alan Cox9ce6cf22007-11-19 15:03:38 +0000829 if (!capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 return -EPERM;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400831
Alan Coxf34d7a52008-04-30 00:54:13 -0700832 if (tty->ops->write == NULL)
833 return -EOPNOTSUPP;
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 /* RTnetlink lock is misused here to serialize concurrent
836 opens of slip channels. There are better ways, but it is
837 the simplest one.
838 */
839 rtnl_lock();
840
841 /* Collect hanged up channels. */
842 sl_sync();
843
Alan Cox9ce6cf22007-11-19 15:03:38 +0000844 sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 err = -EEXIST;
847 /* First make sure we're not already connected. */
848 if (sl && sl->magic == SLIP_MAGIC)
849 goto err_exit;
850
851 /* OK. Find a free SLIP channel to use. */
852 err = -ENFILE;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000853 sl = sl_alloc(tty_devnum(tty));
854 if (sl == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 goto err_exit;
856
857 sl->tty = tty;
858 tty->disc_data = sl;
859 sl->line = tty_devnum(tty);
860 sl->pid = current->pid;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (!test_bit(SLF_INUSE, &sl->flags)) {
863 /* Perform the low-level SLIP initialization. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000864 err = sl_alloc_bufs(sl, SL_MTU);
865 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 goto err_free_chan;
867
868 set_bit(SLF_INUSE, &sl->flags);
869
Alan Cox9ce6cf22007-11-19 15:03:38 +0000870 err = register_netdevice(sl->dev);
871 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 goto err_free_bufs;
873 }
874
875#ifdef CONFIG_SLIP_SMART
876 if (sl->keepalive) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000877 sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ;
878 add_timer(&sl->keepalive_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 }
880 if (sl->outfill) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000881 sl->outfill_timer.expires = jiffies + sl->outfill * HZ;
882 add_timer(&sl->outfill_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 }
884#endif
885
886 /* Done. We have linked the TTY line to a channel. */
887 rtnl_unlock();
Alan Cox33f0f882006-01-09 20:54:13 -0800888 tty->receive_room = 65536; /* We don't flow control */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return sl->dev->base_addr;
890
891err_free_bufs:
892 sl_free_bufs(sl);
893
894err_free_chan:
895 sl->tty = NULL;
896 tty->disc_data = NULL;
897 clear_bit(SLF_INUSE, &sl->flags);
898
899err_exit:
900 rtnl_unlock();
901
902 /* Count references from TTY module */
903 return err;
904}
905
906/*
907
908 FIXME: 1,2 are fixed 3 was never true anyway.
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 Let me to blame a bit.
911 1. TTY module calls this funstion on soft interrupt.
912 2. TTY module calls this function WITH MASKED INTERRUPTS!
913 3. TTY module does not notify us about line discipline
914 shutdown,
915
916 Seems, now it is clean. The solution is to consider netdevice and
917 line discipline sides as two independent threads.
918
919 By-product (not desired): sl? does not feel hangups and remains open.
920 It is supposed, that user level program (dip, diald, slattach...)
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400921 will catch SIGHUP and make the rest of work.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 I see no way to make more with current tty code. --ANK
924 */
925
926/*
927 * Close down a SLIP channel.
928 * This means flushing out any pending queues, and then returning. This
929 * call is serialized against other ldisc functions.
930 */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000931static void slip_close(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Alan Cox9ce6cf22007-11-19 15:03:38 +0000933 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 /* First make sure we're connected. */
936 if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)
937 return;
938
939 tty->disc_data = NULL;
940 sl->tty = NULL;
941 if (!sl->leased)
942 sl->line = 0;
943
944 /* VSV = very important to remove timers */
945#ifdef CONFIG_SLIP_SMART
946 del_timer_sync(&sl->keepalive_timer);
947 del_timer_sync(&sl->outfill_timer);
948#endif
949
950 /* Count references from TTY module */
951}
952
953 /************************************************************************
954 * STANDARD SLIP ENCAPSULATION *
955 ************************************************************************/
956
Alan Cox9ce6cf22007-11-19 15:03:38 +0000957static int slip_esc(unsigned char *s, unsigned char *d, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
959 unsigned char *ptr = d;
960 unsigned char c;
961
962 /*
963 * Send an initial END character to flush out any
964 * data that may have accumulated in the receiver
965 * due to line noise.
966 */
967
968 *ptr++ = END;
969
970 /*
971 * For each byte in the packet, send the appropriate
972 * character sequence, according to the SLIP protocol.
973 */
974
975 while (len-- > 0) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000976 switch (c = *s++) {
977 case END:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 *ptr++ = ESC;
979 *ptr++ = ESC_END;
980 break;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000981 case ESC:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 *ptr++ = ESC;
983 *ptr++ = ESC_ESC;
984 break;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000985 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 *ptr++ = c;
987 break;
988 }
989 }
990 *ptr++ = END;
991 return (ptr - d);
992}
993
994static void slip_unesc(struct slip *sl, unsigned char s)
995{
996
Alan Cox9ce6cf22007-11-19 15:03:38 +0000997 switch (s) {
998 case END:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999#ifdef CONFIG_SLIP_SMART
1000 /* drop keeptest bit = VSV */
1001 if (test_bit(SLF_KEEPTEST, &sl->flags))
1002 clear_bit(SLF_KEEPTEST, &sl->flags);
1003#endif
1004
Alan Cox9ce6cf22007-11-19 15:03:38 +00001005 if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
1006 && (sl->rcount > 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 sl_bump(sl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 clear_bit(SLF_ESCAPE, &sl->flags);
1009 sl->rcount = 0;
1010 return;
1011
Alan Cox9ce6cf22007-11-19 15:03:38 +00001012 case ESC:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 set_bit(SLF_ESCAPE, &sl->flags);
1014 return;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001015 case ESC_ESC:
1016 if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 s = ESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 break;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001019 case ESC_END:
1020 if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 s = END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 break;
1023 }
1024 if (!test_bit(SLF_ERROR, &sl->flags)) {
1025 if (sl->rcount < sl->buffsize) {
1026 sl->rbuff[sl->rcount++] = s;
1027 return;
1028 }
1029 sl->rx_over_errors++;
1030 set_bit(SLF_ERROR, &sl->flags);
1031 }
1032}
1033
1034
1035#ifdef CONFIG_SLIP_MODE_SLIP6
1036/************************************************************************
1037 * 6 BIT SLIP ENCAPSULATION *
1038 ************************************************************************/
1039
Alan Cox9ce6cf22007-11-19 15:03:38 +00001040static int slip_esc6(unsigned char *s, unsigned char *d, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041{
1042 unsigned char *ptr = d;
1043 unsigned char c;
1044 int i;
1045 unsigned short v = 0;
1046 short bits = 0;
1047
1048 /*
1049 * Send an initial END character to flush out any
1050 * data that may have accumulated in the receiver
1051 * due to line noise.
1052 */
1053
1054 *ptr++ = 0x70;
1055
1056 /*
1057 * Encode the packet into printable ascii characters
1058 */
1059
1060 for (i = 0; i < len; ++i) {
1061 v = (v << 8) | s[i];
1062 bits += 8;
1063 while (bits >= 6) {
1064 bits -= 6;
1065 c = 0x30 + ((v >> bits) & 0x3F);
1066 *ptr++ = c;
1067 }
1068 }
1069 if (bits) {
1070 c = 0x30 + ((v << (6 - bits)) & 0x3F);
1071 *ptr++ = c;
1072 }
1073 *ptr++ = 0x70;
1074 return ptr - d;
1075}
1076
Alan Cox9ce6cf22007-11-19 15:03:38 +00001077static void slip_unesc6(struct slip *sl, unsigned char s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
1079 unsigned char c;
1080
1081 if (s == 0x70) {
1082#ifdef CONFIG_SLIP_SMART
1083 /* drop keeptest bit = VSV */
1084 if (test_bit(SLF_KEEPTEST, &sl->flags))
1085 clear_bit(SLF_KEEPTEST, &sl->flags);
1086#endif
1087
Alan Cox9ce6cf22007-11-19 15:03:38 +00001088 if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
1089 && (sl->rcount > 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 sl_bump(sl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 sl->rcount = 0;
1092 sl->xbits = 0;
1093 sl->xdata = 0;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001094 } else if (s >= 0x30 && s < 0x70) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
1096 sl->xbits += 6;
1097 if (sl->xbits >= 8) {
1098 sl->xbits -= 8;
1099 c = (unsigned char)(sl->xdata >> sl->xbits);
1100 if (!test_bit(SLF_ERROR, &sl->flags)) {
1101 if (sl->rcount < sl->buffsize) {
1102 sl->rbuff[sl->rcount++] = c;
1103 return;
1104 }
1105 sl->rx_over_errors++;
1106 set_bit(SLF_ERROR, &sl->flags);
1107 }
1108 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110}
1111#endif /* CONFIG_SLIP_MODE_SLIP6 */
1112
1113/* Perform I/O control on an active SLIP channel. */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001114static int slip_ioctl(struct tty_struct *tty, struct file *file,
1115 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
Alan Cox9ce6cf22007-11-19 15:03:38 +00001117 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 unsigned int tmp;
1119 int __user *p = (int __user *)arg;
1120
1121 /* First make sure we're connected. */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001122 if (!sl || sl->magic != SLIP_MAGIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Alan Cox9ce6cf22007-11-19 15:03:38 +00001125 switch (cmd) {
1126 case SIOCGIFNAME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 tmp = strlen(sl->dev->name) + 1;
1128 if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
1129 return -EFAULT;
1130 return 0;
1131
1132 case SIOCGIFENCAP:
1133 if (put_user(sl->mode, p))
1134 return -EFAULT;
1135 return 0;
1136
1137 case SIOCSIFENCAP:
1138 if (get_user(tmp, p))
1139 return -EFAULT;
1140#ifndef SL_INCLUDE_CSLIP
Alan Cox9ce6cf22007-11-19 15:03:38 +00001141 if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143#else
1144 if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
Alan Cox9ce6cf22007-11-19 15:03:38 +00001145 (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 /* return -EINVAL; */
1147 tmp &= ~SL_MODE_ADAPTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148#endif
1149#ifndef CONFIG_SLIP_MODE_SLIP6
Alan Cox9ce6cf22007-11-19 15:03:38 +00001150 if (tmp & SL_MODE_SLIP6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152#endif
1153 sl->mode = tmp;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001154 sl->dev->type = ARPHRD_SLIP + sl->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 return 0;
1156
Alan Cox9ce6cf22007-11-19 15:03:38 +00001157 case SIOCSIFHWADDR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 return -EINVAL;
1159
1160#ifdef CONFIG_SLIP_SMART
1161 /* VSV changes start here */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001162 case SIOCSKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 if (get_user(tmp, p))
1164 return -EFAULT;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001165 if (tmp > 255) /* max for unchar */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 return -EINVAL;
1167
1168 spin_lock_bh(&sl->lock);
1169 if (!sl->tty) {
1170 spin_unlock_bh(&sl->lock);
1171 return -ENODEV;
1172 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001173 sl->keepalive = (u8)tmp;
1174 if (sl->keepalive != 0) {
1175 mod_timer(&sl->keepalive_timer,
1176 jiffies + sl->keepalive * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 set_bit(SLF_KEEPTEST, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001178 } else
1179 del_timer(&sl->keepalive_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 spin_unlock_bh(&sl->lock);
1181 return 0;
1182
Alan Cox9ce6cf22007-11-19 15:03:38 +00001183 case SIOCGKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (put_user(sl->keepalive, p))
1185 return -EFAULT;
1186 return 0;
1187
Alan Cox9ce6cf22007-11-19 15:03:38 +00001188 case SIOCSOUTFILL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 if (get_user(tmp, p))
1190 return -EFAULT;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001191 if (tmp > 255) /* max for unchar */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return -EINVAL;
1193 spin_lock_bh(&sl->lock);
1194 if (!sl->tty) {
1195 spin_unlock_bh(&sl->lock);
1196 return -ENODEV;
1197 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001198 sl->outfill = (u8)tmp;
1199 if (sl->outfill != 0) {
1200 mod_timer(&sl->outfill_timer,
1201 jiffies + sl->outfill * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 set_bit(SLF_OUTWAIT, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001203 } else
1204 del_timer(&sl->outfill_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 spin_unlock_bh(&sl->lock);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001206 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Alan Cox9ce6cf22007-11-19 15:03:38 +00001208 case SIOCGOUTFILL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 if (put_user(sl->outfill, p))
1210 return -EFAULT;
1211 return 0;
1212 /* VSV changes end */
1213#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 default:
Alan Coxd0127532007-11-07 01:27:34 -08001215 return tty_mode_ioctl(tty, file, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217}
1218
1219/* VSV changes start here */
1220#ifdef CONFIG_SLIP_SMART
1221/* function do_ioctl called from net/core/dev.c
1222 to allow get/set outfill/keepalive parameter
1223 by ifconfig */
1224
Alan Cox9ce6cf22007-11-19 15:03:38 +00001225static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
1227 struct slip *sl = netdev_priv(dev);
1228 unsigned long *p = (unsigned long *)&rq->ifr_ifru;
1229
1230 if (sl == NULL) /* Allocation failed ?? */
1231 return -ENODEV;
1232
1233 spin_lock_bh(&sl->lock);
1234
1235 if (!sl->tty) {
1236 spin_unlock_bh(&sl->lock);
1237 return -ENODEV;
1238 }
1239
Alan Cox9ce6cf22007-11-19 15:03:38 +00001240 switch (cmd) {
1241 case SIOCSKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 /* max for unchar */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001243 if ((unsigned)*p > 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 spin_unlock_bh(&sl->lock);
1245 return -EINVAL;
1246 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001247 sl->keepalive = (u8)*p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (sl->keepalive != 0) {
Alan Cox9ce6cf22007-11-19 15:03:38 +00001249 sl->keepalive_timer.expires =
1250 jiffies + sl->keepalive * HZ;
1251 mod_timer(&sl->keepalive_timer,
1252 jiffies + sl->keepalive * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 set_bit(SLF_KEEPTEST, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001254 } else
1255 del_timer(&sl->keepalive_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 break;
1257
Alan Cox9ce6cf22007-11-19 15:03:38 +00001258 case SIOCGKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 *p = sl->keepalive;
1260 break;
1261
Alan Cox9ce6cf22007-11-19 15:03:38 +00001262 case SIOCSOUTFILL:
1263 if ((unsigned)*p > 255) { /* max for unchar */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 spin_unlock_bh(&sl->lock);
1265 return -EINVAL;
1266 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001267 sl->outfill = (u8)*p;
1268 if (sl->outfill != 0) {
1269 mod_timer(&sl->outfill_timer,
1270 jiffies + sl->outfill * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 set_bit(SLF_OUTWAIT, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001272 } else
1273 del_timer(&sl->outfill_timer);
1274 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Alan Cox9ce6cf22007-11-19 15:03:38 +00001276 case SIOCGOUTFILL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 *p = sl->outfill;
1278 break;
1279
Alan Cox9ce6cf22007-11-19 15:03:38 +00001280 case SIOCSLEASE:
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001281 /* Resolve race condition, when ioctl'ing hanged up
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 and opened by another process device.
1283 */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001284 if (sl->tty != current->signal->tty &&
1285 sl->pid != current->pid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 spin_unlock_bh(&sl->lock);
1287 return -EPERM;
1288 }
1289 sl->leased = 0;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001290 if (*p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 sl->leased = 1;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001292 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Alan Cox9ce6cf22007-11-19 15:03:38 +00001294 case SIOCGLEASE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 *p = sl->leased;
1296 };
1297 spin_unlock_bh(&sl->lock);
1298 return 0;
1299}
1300#endif
1301/* VSV changes end */
1302
Alan Coxa352def2008-07-16 21:53:12 +01001303static struct tty_ldisc_ops sl_ldisc = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 .owner = THIS_MODULE,
1305 .magic = TTY_LDISC_MAGIC,
1306 .name = "slip",
1307 .open = slip_open,
1308 .close = slip_close,
1309 .ioctl = slip_ioctl,
1310 .receive_buf = slip_receive_buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 .write_wakeup = slip_write_wakeup,
1312};
1313
1314static int __init slip_init(void)
1315{
1316 int status;
1317
1318 if (slip_maxdev < 4)
1319 slip_maxdev = 4; /* Sanity */
1320
1321 printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"
1322#ifdef CONFIG_SLIP_MODE_SLIP6
1323 " (6 bit encapsulation enabled)"
1324#endif
1325 ".\n",
Alan Cox9ce6cf22007-11-19 15:03:38 +00001326 SLIP_VERSION, slip_maxdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327#if defined(SL_INCLUDE_CSLIP)
1328 printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n");
1329#endif
1330#ifdef CONFIG_SLIP_SMART
1331 printk(KERN_INFO "SLIP linefill/keepalive option.\n");
1332#endif
1333
Alan Cox9ce6cf22007-11-19 15:03:38 +00001334 slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev,
1335 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 if (!slip_devs) {
Alan Cox9ce6cf22007-11-19 15:03:38 +00001337 printk(KERN_ERR "SLIP: Can't allocate slip devices array.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 return -ENOMEM;
1339 }
1340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 /* Fill in our line protocol discipline, and register it */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001342 status = tty_register_ldisc(N_SLIP, &sl_ldisc);
1343 if (status != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
1345 kfree(slip_devs);
1346 }
1347 return status;
1348}
1349
1350static void __exit slip_exit(void)
1351{
1352 int i;
1353 struct net_device *dev;
1354 struct slip *sl;
1355 unsigned long timeout = jiffies + HZ;
1356 int busy = 0;
1357
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001358 if (slip_devs == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 return;
1360
1361 /* First of all: check for active disciplines and hangup them.
1362 */
1363 do {
Nishanth Aravamudana9fc2512005-05-01 23:34:57 -07001364 if (busy)
1365 msleep_interruptible(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 busy = 0;
1368 for (i = 0; i < slip_maxdev; i++) {
1369 dev = slip_devs[i];
1370 if (!dev)
1371 continue;
1372 sl = netdev_priv(dev);
1373 spin_lock_bh(&sl->lock);
1374 if (sl->tty) {
1375 busy++;
1376 tty_hangup(sl->tty);
1377 }
1378 spin_unlock_bh(&sl->lock);
1379 }
1380 } while (busy && time_before(jiffies, timeout));
1381
1382
1383 for (i = 0; i < slip_maxdev; i++) {
1384 dev = slip_devs[i];
1385 if (!dev)
1386 continue;
1387 slip_devs[i] = NULL;
1388
1389 sl = netdev_priv(dev);
1390 if (sl->tty) {
1391 printk(KERN_ERR "%s: tty discipline still running\n",
1392 dev->name);
1393 /* Intentionally leak the control block. */
1394 dev->destructor = NULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
1397 unregister_netdev(dev);
1398 }
1399
1400 kfree(slip_devs);
1401 slip_devs = NULL;
1402
Alan Cox9ce6cf22007-11-19 15:03:38 +00001403 i = tty_unregister_ldisc(N_SLIP);
1404 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406}
1407
1408module_init(slip_init);
1409module_exit(slip_exit);
1410
1411#ifdef CONFIG_SLIP_SMART
1412/*
1413 * This is start of the code for multislip style line checking
1414 * added by Stanislav Voronyi. All changes before marked VSV
1415 */
1416
1417static void sl_outfill(unsigned long sls)
1418{
Alan Cox9ce6cf22007-11-19 15:03:38 +00001419 struct slip *sl = (struct slip *)sls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421 spin_lock(&sl->lock);
1422
1423 if (sl->tty == NULL)
1424 goto out;
1425
Alan Cox9ce6cf22007-11-19 15:03:38 +00001426 if (sl->outfill) {
1427 if (test_bit(SLF_OUTWAIT, &sl->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 /* no packets were transmitted, do outfill */
1429#ifdef CONFIG_SLIP_MODE_SLIP6
1430 unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;
1431#else
1432 unsigned char s = END;
1433#endif
1434 /* put END into tty queue. Is it right ??? */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001435 if (!netif_queue_stopped(sl->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 /* if device busy no outfill */
Alan Coxf34d7a52008-04-30 00:54:13 -07001437 sl->tty->ops->write(sl->tty, &s, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001439 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 set_bit(SLF_OUTWAIT, &sl->flags);
1441
1442 mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
1443 }
1444out:
1445 spin_unlock(&sl->lock);
1446}
1447
1448static void sl_keepalive(unsigned long sls)
1449{
Alan Cox9ce6cf22007-11-19 15:03:38 +00001450 struct slip *sl = (struct slip *)sls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
1452 spin_lock(&sl->lock);
1453
1454 if (sl->tty == NULL)
1455 goto out;
1456
Alan Cox9ce6cf22007-11-19 15:03:38 +00001457 if (sl->keepalive) {
1458 if (test_bit(SLF_KEEPTEST, &sl->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 /* keepalive still high :(, we must hangup */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001460 if (sl->outfill)
1461 /* outfill timer must be deleted too */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 (void)del_timer(&sl->outfill_timer);
1463 printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001464 /* this must hangup tty & close slip */
1465 tty_hangup(sl->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 /* I think we need not something else */
1467 goto out;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001468 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 set_bit(SLF_KEEPTEST, &sl->flags);
1470
1471 mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
1472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473out:
1474 spin_unlock(&sl->lock);
1475}
1476
1477#endif
1478MODULE_LICENSE("GPL");
1479MODULE_ALIAS_LDISC(N_SLIP);