blob: 1d58991d395b6ef32120e1e265c8245ab61219e3 [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);
368 sl->dev->last_rx = jiffies;
369 sl->rx_packets++;
370}
371
372/* Encapsulate one IP datagram and stuff into a TTY queue. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000373static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
375 unsigned char *p;
376 int actual, count;
377
378 if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */
379 printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name);
380 sl->tx_dropped++;
381 sl_unlock(sl);
382 return;
383 }
384
385 p = icp;
386#ifdef SL_INCLUDE_CSLIP
Alan Cox9ce6cf22007-11-19 15:03:38 +0000387 if (sl->mode & SL_MODE_CSLIP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389#endif
390#ifdef CONFIG_SLIP_MODE_SLIP6
Alan Cox9ce6cf22007-11-19 15:03:38 +0000391 if (sl->mode & SL_MODE_SLIP6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
393 else
394#endif
395 count = slip_esc(p, (unsigned char *) sl->xbuff, len);
396
397 /* Order of next two lines is *very* important.
398 * When we are sending a little amount of data,
Alan Coxf34d7a52008-04-30 00:54:13 -0700399 * the transfer may be completed inside the ops->write()
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 * routine, because it's running with interrupts enabled.
401 * In this case we *never* got WRITE_WAKEUP event,
402 * if we did not request it before write operation.
403 * 14 Oct 1994 Dmitry Gorodchanin.
404 */
405 sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
Alan Coxf34d7a52008-04-30 00:54:13 -0700406 actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407#ifdef SL_CHECK_TRANSMIT
408 sl->dev->trans_start = jiffies;
409#endif
410 sl->xleft = count - actual;
411 sl->xhead = sl->xbuff + actual;
412#ifdef CONFIG_SLIP_SMART
413 /* VSV */
414 clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
415#endif
416}
417
418/*
419 * Called by the driver when there's room for more data. If we have
420 * more packets to send, we send them here.
421 */
422static void slip_write_wakeup(struct tty_struct *tty)
423{
424 int actual;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000425 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 /* First make sure we're connected. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000428 if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 if (sl->xleft <= 0) {
432 /* Now serial buffer is almost free & we can start
433 * transmission of another packet */
434 sl->tx_packets++;
435 tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
436 sl_unlock(sl);
437 return;
438 }
439
Alan Coxf34d7a52008-04-30 00:54:13 -0700440 actual = tty->ops->write(tty, sl->xhead, sl->xleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sl->xleft -= actual;
442 sl->xhead += actual;
443}
444
445static void sl_tx_timeout(struct net_device *dev)
446{
447 struct slip *sl = netdev_priv(dev);
448
449 spin_lock(&sl->lock);
450
451 if (netif_queue_stopped(dev)) {
452 if (!netif_running(dev))
453 goto out;
454
455 /* May be we must check transmitter timeout here ?
456 * 14 Oct 1994 Dmitry Gorodchanin.
457 */
458#ifdef SL_CHECK_TRANSMIT
459 if (time_before(jiffies, dev->trans_start + 20 * HZ)) {
460 /* 20 sec timeout not reached */
461 goto out;
462 }
Alan Cox9ce6cf22007-11-19 15:03:38 +0000463 printk(KERN_WARNING "%s: transmit timed out, %s?\n",
464 dev->name,
Alan Coxf34d7a52008-04-30 00:54:13 -0700465 (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
Alan Cox9ce6cf22007-11-19 15:03:38 +0000466 "bad line quality" : "driver error");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 sl->xleft = 0;
468 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
469 sl_unlock(sl);
470#endif
471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472out:
473 spin_unlock(&sl->lock);
474}
475
476
477/* Encapsulate an IP datagram and kick it into a TTY queue. */
478static int
479sl_xmit(struct sk_buff *skb, struct net_device *dev)
480{
481 struct slip *sl = netdev_priv(dev);
482
483 spin_lock(&sl->lock);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000484 if (!netif_running(dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 spin_unlock(&sl->lock);
486 printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
487 dev_kfree_skb(skb);
488 return 0;
489 }
490 if (sl->tty == NULL) {
491 spin_unlock(&sl->lock);
492 dev_kfree_skb(skb);
493 return 0;
494 }
495
496 sl_lock(sl);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000497 sl->tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 sl_encaps(sl, skb->data, skb->len);
499 spin_unlock(&sl->lock);
500
501 dev_kfree_skb(skb);
502 return 0;
503}
504
505
506/******************************************
507 * Routines looking at netdevice side.
508 ******************************************/
509
510/* Netdevice UP -> DOWN routine */
511
512static int
513sl_close(struct net_device *dev)
514{
515 struct slip *sl = netdev_priv(dev);
516
517 spin_lock_bh(&sl->lock);
518 if (sl->tty) {
519 /* TTY discipline is running. */
520 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
521 }
522 netif_stop_queue(dev);
523 sl->rcount = 0;
524 sl->xleft = 0;
525 spin_unlock_bh(&sl->lock);
526
527 return 0;
528}
529
530/* Netdevice DOWN -> UP routine */
531
532static int sl_open(struct net_device *dev)
533{
534 struct slip *sl = netdev_priv(dev);
535
Alan Cox9ce6cf22007-11-19 15:03:38 +0000536 if (sl->tty == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return -ENODEV;
538
539 sl->flags &= (1 << SLF_INUSE);
540 netif_start_queue(dev);
541 return 0;
542}
543
544/* Netdevice change MTU request */
545
546static int sl_change_mtu(struct net_device *dev, int new_mtu)
547{
548 struct slip *sl = netdev_priv(dev);
549
550 if (new_mtu < 68 || new_mtu > 65534)
551 return -EINVAL;
552
553 if (new_mtu != dev->mtu)
554 return sl_realloc_bufs(sl, new_mtu);
555 return 0;
556}
557
558/* Netdevice get statistics request */
559
560static struct net_device_stats *
561sl_get_stats(struct net_device *dev)
562{
563 static struct net_device_stats stats;
564 struct slip *sl = netdev_priv(dev);
565#ifdef SL_INCLUDE_CSLIP
566 struct slcompress *comp;
567#endif
568
569 memset(&stats, 0, sizeof(struct net_device_stats));
570
571 stats.rx_packets = sl->rx_packets;
572 stats.tx_packets = sl->tx_packets;
573 stats.rx_bytes = sl->rx_bytes;
574 stats.tx_bytes = sl->tx_bytes;
575 stats.rx_dropped = sl->rx_dropped;
576 stats.tx_dropped = sl->tx_dropped;
577 stats.tx_errors = sl->tx_errors;
578 stats.rx_errors = sl->rx_errors;
579 stats.rx_over_errors = sl->rx_over_errors;
580#ifdef SL_INCLUDE_CSLIP
581 stats.rx_fifo_errors = sl->rx_compressed;
582 stats.tx_fifo_errors = sl->tx_compressed;
583 stats.collisions = sl->tx_misses;
584 comp = sl->slcomp;
585 if (comp) {
586 stats.rx_fifo_errors += comp->sls_i_compressed;
587 stats.rx_dropped += comp->sls_i_tossed;
588 stats.tx_fifo_errors += comp->sls_o_compressed;
589 stats.collisions += comp->sls_o_misses;
590 }
591#endif /* CONFIG_INET */
592 return (&stats);
593}
594
595/* Netdevice register callback */
596
597static int sl_init(struct net_device *dev)
598{
599 struct slip *sl = netdev_priv(dev);
600
601 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400602 * Finish setting up the DEVICE info.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 */
604
605 dev->mtu = sl->mtu;
606 dev->type = ARPHRD_SLIP + sl->mode;
607#ifdef SL_CHECK_TRANSMIT
608 dev->tx_timeout = sl_tx_timeout;
609 dev->watchdog_timeo = 20*HZ;
610#endif
611 return 0;
612}
613
614
615static void sl_uninit(struct net_device *dev)
616{
617 struct slip *sl = netdev_priv(dev);
618
619 sl_free_bufs(sl);
620}
621
622static void sl_setup(struct net_device *dev)
623{
624 dev->init = sl_init;
625 dev->uninit = sl_uninit;
626 dev->open = sl_open;
627 dev->destructor = free_netdev;
628 dev->stop = sl_close;
629 dev->get_stats = sl_get_stats;
630 dev->change_mtu = sl_change_mtu;
631 dev->hard_start_xmit = sl_xmit;
632#ifdef CONFIG_SLIP_SMART
633 dev->do_ioctl = sl_ioctl;
634#endif
635 dev->hard_header_len = 0;
636 dev->addr_len = 0;
637 dev->tx_queue_len = 10;
638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 /* New-style flags. */
640 dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
641}
642
643/******************************************
644 Routines looking at TTY side.
645 ******************************************/
646
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648/*
649 * Handle the 'receiver data ready' interrupt.
650 * This function is called by the 'tty_io' module in the kernel when
651 * a block of SLIP data has been received, which can now be decapsulated
652 * and sent on to some IP layer for further processing. This will not
653 * be re-entered while running but other ldisc functions may be called
654 * in parallel
655 */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400656
Alan Cox9ce6cf22007-11-19 15:03:38 +0000657static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
658 char *fp, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
Alan Cox9ce6cf22007-11-19 15:03:38 +0000660 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Alan Cox9ce6cf22007-11-19 15:03:38 +0000662 if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return;
664
665 /* Read the characters out of the buffer */
666 while (count--) {
667 if (fp && *fp++) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000668 if (!test_and_set_bit(SLF_ERROR, &sl->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 sl->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 cp++;
671 continue;
672 }
673#ifdef CONFIG_SLIP_MODE_SLIP6
674 if (sl->mode & SL_MODE_SLIP6)
675 slip_unesc6(sl, *cp++);
676 else
677#endif
678 slip_unesc(sl, *cp++);
679 }
680}
681
682/************************************
683 * slip_open helper routines.
684 ************************************/
685
686/* Collect hanged up channels */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687static void sl_sync(void)
688{
689 int i;
690 struct net_device *dev;
691 struct slip *sl;
692
693 for (i = 0; i < slip_maxdev; i++) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000694 dev = slip_devs[i];
695 if (dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 break;
697
698 sl = netdev_priv(dev);
699 if (sl->tty || sl->leased)
700 continue;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000701 if (dev->flags & IFF_UP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 dev_close(dev);
703 }
704}
705
706
707/* Find a free SLIP channel, and link in this `tty' line. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000708static struct slip *sl_alloc(dev_t line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
710 int i;
711 int sel = -1;
712 int score = -1;
713 struct net_device *dev = NULL;
714 struct slip *sl;
715
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400716 if (slip_devs == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 return NULL; /* Master array missing ! */
718
719 for (i = 0; i < slip_maxdev; i++) {
720 dev = slip_devs[i];
721 if (dev == NULL)
722 break;
723
724 sl = netdev_priv(dev);
725 if (sl->leased) {
726 if (sl->line != line)
727 continue;
728 if (sl->tty)
729 return NULL;
730
731 /* Clear ESCAPE & ERROR flags */
732 sl->flags &= (1 << SLF_INUSE);
733 return sl;
734 }
735
736 if (sl->tty)
737 continue;
738
739 if (current->pid == sl->pid) {
740 if (sl->line == line && score < 3) {
741 sel = i;
742 score = 3;
743 continue;
744 }
745 if (score < 2) {
746 sel = i;
747 score = 2;
748 }
749 continue;
750 }
751 if (sl->line == line && score < 1) {
752 sel = i;
753 score = 1;
754 continue;
755 }
756 if (score < 0) {
757 sel = i;
758 score = 0;
759 }
760 }
761
762 if (sel >= 0) {
763 i = sel;
764 dev = slip_devs[i];
765 if (score > 1) {
766 sl = netdev_priv(dev);
767 sl->flags &= (1 << SLF_INUSE);
768 return sl;
769 }
770 }
771
772 /* Sorry, too many, all slots in use */
773 if (i >= slip_maxdev)
774 return NULL;
775
776 if (dev) {
777 sl = netdev_priv(dev);
778 if (test_bit(SLF_INUSE, &sl->flags)) {
779 unregister_netdevice(dev);
780 dev = NULL;
781 slip_devs[i] = NULL;
782 }
783 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (!dev) {
786 char name[IFNAMSIZ];
787 sprintf(name, "sl%d", i);
788
789 dev = alloc_netdev(sizeof(*sl), name, sl_setup);
790 if (!dev)
791 return NULL;
792 dev->base_addr = i;
793 }
794
795 sl = netdev_priv(dev);
796
797 /* Initialize channel control data */
798 sl->magic = SLIP_MAGIC;
799 sl->dev = dev;
800 spin_lock_init(&sl->lock);
801 sl->mode = SL_MODE_DEFAULT;
802#ifdef CONFIG_SLIP_SMART
Alan Cox9ce6cf22007-11-19 15:03:38 +0000803 /* initialize timer_list struct */
804 init_timer(&sl->keepalive_timer);
805 sl->keepalive_timer.data = (unsigned long)sl;
806 sl->keepalive_timer.function = sl_keepalive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 init_timer(&sl->outfill_timer);
Alan Cox9ce6cf22007-11-19 15:03:38 +0000808 sl->outfill_timer.data = (unsigned long)sl;
809 sl->outfill_timer.function = sl_outfill;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810#endif
811 slip_devs[i] = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 return sl;
813}
814
815/*
816 * Open the high-level part of the SLIP channel.
817 * This function is called by the TTY module when the
818 * SLIP line discipline is called for. Because we are
819 * sure the tty line exists, we only have to link it to
820 * a free SLIP channel...
821 *
822 * Called in process context serialized from other ldisc calls.
823 */
824
825static int slip_open(struct tty_struct *tty)
826{
827 struct slip *sl;
828 int err;
829
Alan Cox9ce6cf22007-11-19 15:03:38 +0000830 if (!capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return -EPERM;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400832
Alan Coxf34d7a52008-04-30 00:54:13 -0700833 if (tty->ops->write == NULL)
834 return -EOPNOTSUPP;
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 /* RTnetlink lock is misused here to serialize concurrent
837 opens of slip channels. There are better ways, but it is
838 the simplest one.
839 */
840 rtnl_lock();
841
842 /* Collect hanged up channels. */
843 sl_sync();
844
Alan Cox9ce6cf22007-11-19 15:03:38 +0000845 sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
847 err = -EEXIST;
848 /* First make sure we're not already connected. */
849 if (sl && sl->magic == SLIP_MAGIC)
850 goto err_exit;
851
852 /* OK. Find a free SLIP channel to use. */
853 err = -ENFILE;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000854 sl = sl_alloc(tty_devnum(tty));
855 if (sl == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 goto err_exit;
857
858 sl->tty = tty;
859 tty->disc_data = sl;
860 sl->line = tty_devnum(tty);
861 sl->pid = current->pid;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 if (!test_bit(SLF_INUSE, &sl->flags)) {
864 /* Perform the low-level SLIP initialization. */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000865 err = sl_alloc_bufs(sl, SL_MTU);
866 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 goto err_free_chan;
868
869 set_bit(SLF_INUSE, &sl->flags);
870
Alan Cox9ce6cf22007-11-19 15:03:38 +0000871 err = register_netdevice(sl->dev);
872 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 goto err_free_bufs;
874 }
875
876#ifdef CONFIG_SLIP_SMART
877 if (sl->keepalive) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000878 sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ;
879 add_timer(&sl->keepalive_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
881 if (sl->outfill) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000882 sl->outfill_timer.expires = jiffies + sl->outfill * HZ;
883 add_timer(&sl->outfill_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885#endif
886
887 /* Done. We have linked the TTY line to a channel. */
888 rtnl_unlock();
Alan Cox33f0f882006-01-09 20:54:13 -0800889 tty->receive_room = 65536; /* We don't flow control */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return sl->dev->base_addr;
891
892err_free_bufs:
893 sl_free_bufs(sl);
894
895err_free_chan:
896 sl->tty = NULL;
897 tty->disc_data = NULL;
898 clear_bit(SLF_INUSE, &sl->flags);
899
900err_exit:
901 rtnl_unlock();
902
903 /* Count references from TTY module */
904 return err;
905}
906
907/*
908
909 FIXME: 1,2 are fixed 3 was never true anyway.
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 Let me to blame a bit.
912 1. TTY module calls this funstion on soft interrupt.
913 2. TTY module calls this function WITH MASKED INTERRUPTS!
914 3. TTY module does not notify us about line discipline
915 shutdown,
916
917 Seems, now it is clean. The solution is to consider netdevice and
918 line discipline sides as two independent threads.
919
920 By-product (not desired): sl? does not feel hangups and remains open.
921 It is supposed, that user level program (dip, diald, slattach...)
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400922 will catch SIGHUP and make the rest of work.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 I see no way to make more with current tty code. --ANK
925 */
926
927/*
928 * Close down a SLIP channel.
929 * This means flushing out any pending queues, and then returning. This
930 * call is serialized against other ldisc functions.
931 */
Alan Cox9ce6cf22007-11-19 15:03:38 +0000932static void slip_close(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
Alan Cox9ce6cf22007-11-19 15:03:38 +0000934 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 /* First make sure we're connected. */
937 if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)
938 return;
939
940 tty->disc_data = NULL;
941 sl->tty = NULL;
942 if (!sl->leased)
943 sl->line = 0;
944
945 /* VSV = very important to remove timers */
946#ifdef CONFIG_SLIP_SMART
947 del_timer_sync(&sl->keepalive_timer);
948 del_timer_sync(&sl->outfill_timer);
949#endif
950
951 /* Count references from TTY module */
952}
953
954 /************************************************************************
955 * STANDARD SLIP ENCAPSULATION *
956 ************************************************************************/
957
Alan Cox9ce6cf22007-11-19 15:03:38 +0000958static int slip_esc(unsigned char *s, unsigned char *d, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 unsigned char *ptr = d;
961 unsigned char c;
962
963 /*
964 * Send an initial END character to flush out any
965 * data that may have accumulated in the receiver
966 * due to line noise.
967 */
968
969 *ptr++ = END;
970
971 /*
972 * For each byte in the packet, send the appropriate
973 * character sequence, according to the SLIP protocol.
974 */
975
976 while (len-- > 0) {
Alan Cox9ce6cf22007-11-19 15:03:38 +0000977 switch (c = *s++) {
978 case END:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 *ptr++ = ESC;
980 *ptr++ = ESC_END;
981 break;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000982 case ESC:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 *ptr++ = ESC;
984 *ptr++ = ESC_ESC;
985 break;
Alan Cox9ce6cf22007-11-19 15:03:38 +0000986 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 *ptr++ = c;
988 break;
989 }
990 }
991 *ptr++ = END;
992 return (ptr - d);
993}
994
995static void slip_unesc(struct slip *sl, unsigned char s)
996{
997
Alan Cox9ce6cf22007-11-19 15:03:38 +0000998 switch (s) {
999 case END:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000#ifdef CONFIG_SLIP_SMART
1001 /* drop keeptest bit = VSV */
1002 if (test_bit(SLF_KEEPTEST, &sl->flags))
1003 clear_bit(SLF_KEEPTEST, &sl->flags);
1004#endif
1005
Alan Cox9ce6cf22007-11-19 15:03:38 +00001006 if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
1007 && (sl->rcount > 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 sl_bump(sl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 clear_bit(SLF_ESCAPE, &sl->flags);
1010 sl->rcount = 0;
1011 return;
1012
Alan Cox9ce6cf22007-11-19 15:03:38 +00001013 case ESC:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 set_bit(SLF_ESCAPE, &sl->flags);
1015 return;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001016 case ESC_ESC:
1017 if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 s = ESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 break;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001020 case ESC_END:
1021 if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 s = END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 break;
1024 }
1025 if (!test_bit(SLF_ERROR, &sl->flags)) {
1026 if (sl->rcount < sl->buffsize) {
1027 sl->rbuff[sl->rcount++] = s;
1028 return;
1029 }
1030 sl->rx_over_errors++;
1031 set_bit(SLF_ERROR, &sl->flags);
1032 }
1033}
1034
1035
1036#ifdef CONFIG_SLIP_MODE_SLIP6
1037/************************************************************************
1038 * 6 BIT SLIP ENCAPSULATION *
1039 ************************************************************************/
1040
Alan Cox9ce6cf22007-11-19 15:03:38 +00001041static int slip_esc6(unsigned char *s, unsigned char *d, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
1043 unsigned char *ptr = d;
1044 unsigned char c;
1045 int i;
1046 unsigned short v = 0;
1047 short bits = 0;
1048
1049 /*
1050 * Send an initial END character to flush out any
1051 * data that may have accumulated in the receiver
1052 * due to line noise.
1053 */
1054
1055 *ptr++ = 0x70;
1056
1057 /*
1058 * Encode the packet into printable ascii characters
1059 */
1060
1061 for (i = 0; i < len; ++i) {
1062 v = (v << 8) | s[i];
1063 bits += 8;
1064 while (bits >= 6) {
1065 bits -= 6;
1066 c = 0x30 + ((v >> bits) & 0x3F);
1067 *ptr++ = c;
1068 }
1069 }
1070 if (bits) {
1071 c = 0x30 + ((v << (6 - bits)) & 0x3F);
1072 *ptr++ = c;
1073 }
1074 *ptr++ = 0x70;
1075 return ptr - d;
1076}
1077
Alan Cox9ce6cf22007-11-19 15:03:38 +00001078static void slip_unesc6(struct slip *sl, unsigned char s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079{
1080 unsigned char c;
1081
1082 if (s == 0x70) {
1083#ifdef CONFIG_SLIP_SMART
1084 /* drop keeptest bit = VSV */
1085 if (test_bit(SLF_KEEPTEST, &sl->flags))
1086 clear_bit(SLF_KEEPTEST, &sl->flags);
1087#endif
1088
Alan Cox9ce6cf22007-11-19 15:03:38 +00001089 if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
1090 && (sl->rcount > 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 sl_bump(sl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 sl->rcount = 0;
1093 sl->xbits = 0;
1094 sl->xdata = 0;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001095 } else if (s >= 0x30 && s < 0x70) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
1097 sl->xbits += 6;
1098 if (sl->xbits >= 8) {
1099 sl->xbits -= 8;
1100 c = (unsigned char)(sl->xdata >> sl->xbits);
1101 if (!test_bit(SLF_ERROR, &sl->flags)) {
1102 if (sl->rcount < sl->buffsize) {
1103 sl->rbuff[sl->rcount++] = c;
1104 return;
1105 }
1106 sl->rx_over_errors++;
1107 set_bit(SLF_ERROR, &sl->flags);
1108 }
1109 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111}
1112#endif /* CONFIG_SLIP_MODE_SLIP6 */
1113
1114/* Perform I/O control on an active SLIP channel. */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001115static int slip_ioctl(struct tty_struct *tty, struct file *file,
1116 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
Alan Cox9ce6cf22007-11-19 15:03:38 +00001118 struct slip *sl = tty->disc_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 unsigned int tmp;
1120 int __user *p = (int __user *)arg;
1121
1122 /* First make sure we're connected. */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001123 if (!sl || sl->magic != SLIP_MAGIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Alan Cox9ce6cf22007-11-19 15:03:38 +00001126 switch (cmd) {
1127 case SIOCGIFNAME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 tmp = strlen(sl->dev->name) + 1;
1129 if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
1130 return -EFAULT;
1131 return 0;
1132
1133 case SIOCGIFENCAP:
1134 if (put_user(sl->mode, p))
1135 return -EFAULT;
1136 return 0;
1137
1138 case SIOCSIFENCAP:
1139 if (get_user(tmp, p))
1140 return -EFAULT;
1141#ifndef SL_INCLUDE_CSLIP
Alan Cox9ce6cf22007-11-19 15:03:38 +00001142 if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144#else
1145 if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
Alan Cox9ce6cf22007-11-19 15:03:38 +00001146 (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 /* return -EINVAL; */
1148 tmp &= ~SL_MODE_ADAPTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149#endif
1150#ifndef CONFIG_SLIP_MODE_SLIP6
Alan Cox9ce6cf22007-11-19 15:03:38 +00001151 if (tmp & SL_MODE_SLIP6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153#endif
1154 sl->mode = tmp;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001155 sl->dev->type = ARPHRD_SLIP + sl->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return 0;
1157
Alan Cox9ce6cf22007-11-19 15:03:38 +00001158 case SIOCSIFHWADDR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 return -EINVAL;
1160
1161#ifdef CONFIG_SLIP_SMART
1162 /* VSV changes start here */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001163 case SIOCSKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 if (get_user(tmp, p))
1165 return -EFAULT;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001166 if (tmp > 255) /* max for unchar */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 return -EINVAL;
1168
1169 spin_lock_bh(&sl->lock);
1170 if (!sl->tty) {
1171 spin_unlock_bh(&sl->lock);
1172 return -ENODEV;
1173 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001174 sl->keepalive = (u8)tmp;
1175 if (sl->keepalive != 0) {
1176 mod_timer(&sl->keepalive_timer,
1177 jiffies + sl->keepalive * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 set_bit(SLF_KEEPTEST, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001179 } else
1180 del_timer(&sl->keepalive_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 spin_unlock_bh(&sl->lock);
1182 return 0;
1183
Alan Cox9ce6cf22007-11-19 15:03:38 +00001184 case SIOCGKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (put_user(sl->keepalive, p))
1186 return -EFAULT;
1187 return 0;
1188
Alan Cox9ce6cf22007-11-19 15:03:38 +00001189 case SIOCSOUTFILL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (get_user(tmp, p))
1191 return -EFAULT;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001192 if (tmp > 255) /* max for unchar */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return -EINVAL;
1194 spin_lock_bh(&sl->lock);
1195 if (!sl->tty) {
1196 spin_unlock_bh(&sl->lock);
1197 return -ENODEV;
1198 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001199 sl->outfill = (u8)tmp;
1200 if (sl->outfill != 0) {
1201 mod_timer(&sl->outfill_timer,
1202 jiffies + sl->outfill * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 set_bit(SLF_OUTWAIT, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001204 } else
1205 del_timer(&sl->outfill_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 spin_unlock_bh(&sl->lock);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001207 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Alan Cox9ce6cf22007-11-19 15:03:38 +00001209 case SIOCGOUTFILL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 if (put_user(sl->outfill, p))
1211 return -EFAULT;
1212 return 0;
1213 /* VSV changes end */
1214#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 default:
Alan Coxd0127532007-11-07 01:27:34 -08001216 return tty_mode_ioctl(tty, file, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218}
1219
1220/* VSV changes start here */
1221#ifdef CONFIG_SLIP_SMART
1222/* function do_ioctl called from net/core/dev.c
1223 to allow get/set outfill/keepalive parameter
1224 by ifconfig */
1225
Alan Cox9ce6cf22007-11-19 15:03:38 +00001226static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
1228 struct slip *sl = netdev_priv(dev);
1229 unsigned long *p = (unsigned long *)&rq->ifr_ifru;
1230
1231 if (sl == NULL) /* Allocation failed ?? */
1232 return -ENODEV;
1233
1234 spin_lock_bh(&sl->lock);
1235
1236 if (!sl->tty) {
1237 spin_unlock_bh(&sl->lock);
1238 return -ENODEV;
1239 }
1240
Alan Cox9ce6cf22007-11-19 15:03:38 +00001241 switch (cmd) {
1242 case SIOCSKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 /* max for unchar */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001244 if ((unsigned)*p > 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 spin_unlock_bh(&sl->lock);
1246 return -EINVAL;
1247 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001248 sl->keepalive = (u8)*p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if (sl->keepalive != 0) {
Alan Cox9ce6cf22007-11-19 15:03:38 +00001250 sl->keepalive_timer.expires =
1251 jiffies + sl->keepalive * HZ;
1252 mod_timer(&sl->keepalive_timer,
1253 jiffies + sl->keepalive * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 set_bit(SLF_KEEPTEST, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001255 } else
1256 del_timer(&sl->keepalive_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 break;
1258
Alan Cox9ce6cf22007-11-19 15:03:38 +00001259 case SIOCGKEEPALIVE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 *p = sl->keepalive;
1261 break;
1262
Alan Cox9ce6cf22007-11-19 15:03:38 +00001263 case SIOCSOUTFILL:
1264 if ((unsigned)*p > 255) { /* max for unchar */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 spin_unlock_bh(&sl->lock);
1266 return -EINVAL;
1267 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001268 sl->outfill = (u8)*p;
1269 if (sl->outfill != 0) {
1270 mod_timer(&sl->outfill_timer,
1271 jiffies + sl->outfill * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 set_bit(SLF_OUTWAIT, &sl->flags);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001273 } else
1274 del_timer(&sl->outfill_timer);
1275 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Alan Cox9ce6cf22007-11-19 15:03:38 +00001277 case SIOCGOUTFILL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 *p = sl->outfill;
1279 break;
1280
Alan Cox9ce6cf22007-11-19 15:03:38 +00001281 case SIOCSLEASE:
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001282 /* Resolve race condition, when ioctl'ing hanged up
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 and opened by another process device.
1284 */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001285 if (sl->tty != current->signal->tty &&
1286 sl->pid != current->pid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 spin_unlock_bh(&sl->lock);
1288 return -EPERM;
1289 }
1290 sl->leased = 0;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001291 if (*p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 sl->leased = 1;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001293 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Alan Cox9ce6cf22007-11-19 15:03:38 +00001295 case SIOCGLEASE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 *p = sl->leased;
1297 };
1298 spin_unlock_bh(&sl->lock);
1299 return 0;
1300}
1301#endif
1302/* VSV changes end */
1303
Alan Coxa352def2008-07-16 21:53:12 +01001304static struct tty_ldisc_ops sl_ldisc = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 .owner = THIS_MODULE,
1306 .magic = TTY_LDISC_MAGIC,
1307 .name = "slip",
1308 .open = slip_open,
1309 .close = slip_close,
1310 .ioctl = slip_ioctl,
1311 .receive_buf = slip_receive_buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 .write_wakeup = slip_write_wakeup,
1313};
1314
1315static int __init slip_init(void)
1316{
1317 int status;
1318
1319 if (slip_maxdev < 4)
1320 slip_maxdev = 4; /* Sanity */
1321
1322 printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"
1323#ifdef CONFIG_SLIP_MODE_SLIP6
1324 " (6 bit encapsulation enabled)"
1325#endif
1326 ".\n",
Alan Cox9ce6cf22007-11-19 15:03:38 +00001327 SLIP_VERSION, slip_maxdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328#if defined(SL_INCLUDE_CSLIP)
1329 printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n");
1330#endif
1331#ifdef CONFIG_SLIP_SMART
1332 printk(KERN_INFO "SLIP linefill/keepalive option.\n");
1333#endif
1334
Alan Cox9ce6cf22007-11-19 15:03:38 +00001335 slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev,
1336 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (!slip_devs) {
Alan Cox9ce6cf22007-11-19 15:03:38 +00001338 printk(KERN_ERR "SLIP: Can't allocate slip devices array.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 return -ENOMEM;
1340 }
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 /* Fill in our line protocol discipline, and register it */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001343 status = tty_register_ldisc(N_SLIP, &sl_ldisc);
1344 if (status != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
1346 kfree(slip_devs);
1347 }
1348 return status;
1349}
1350
1351static void __exit slip_exit(void)
1352{
1353 int i;
1354 struct net_device *dev;
1355 struct slip *sl;
1356 unsigned long timeout = jiffies + HZ;
1357 int busy = 0;
1358
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001359 if (slip_devs == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return;
1361
1362 /* First of all: check for active disciplines and hangup them.
1363 */
1364 do {
Nishanth Aravamudana9fc2512005-05-01 23:34:57 -07001365 if (busy)
1366 msleep_interruptible(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 busy = 0;
1369 for (i = 0; i < slip_maxdev; i++) {
1370 dev = slip_devs[i];
1371 if (!dev)
1372 continue;
1373 sl = netdev_priv(dev);
1374 spin_lock_bh(&sl->lock);
1375 if (sl->tty) {
1376 busy++;
1377 tty_hangup(sl->tty);
1378 }
1379 spin_unlock_bh(&sl->lock);
1380 }
1381 } while (busy && time_before(jiffies, timeout));
1382
1383
1384 for (i = 0; i < slip_maxdev; i++) {
1385 dev = slip_devs[i];
1386 if (!dev)
1387 continue;
1388 slip_devs[i] = NULL;
1389
1390 sl = netdev_priv(dev);
1391 if (sl->tty) {
1392 printk(KERN_ERR "%s: tty discipline still running\n",
1393 dev->name);
1394 /* Intentionally leak the control block. */
1395 dev->destructor = NULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
1398 unregister_netdev(dev);
1399 }
1400
1401 kfree(slip_devs);
1402 slip_devs = NULL;
1403
Alan Cox9ce6cf22007-11-19 15:03:38 +00001404 i = tty_unregister_ldisc(N_SLIP);
1405 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407}
1408
1409module_init(slip_init);
1410module_exit(slip_exit);
1411
1412#ifdef CONFIG_SLIP_SMART
1413/*
1414 * This is start of the code for multislip style line checking
1415 * added by Stanislav Voronyi. All changes before marked VSV
1416 */
1417
1418static void sl_outfill(unsigned long sls)
1419{
Alan Cox9ce6cf22007-11-19 15:03:38 +00001420 struct slip *sl = (struct slip *)sls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422 spin_lock(&sl->lock);
1423
1424 if (sl->tty == NULL)
1425 goto out;
1426
Alan Cox9ce6cf22007-11-19 15:03:38 +00001427 if (sl->outfill) {
1428 if (test_bit(SLF_OUTWAIT, &sl->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 /* no packets were transmitted, do outfill */
1430#ifdef CONFIG_SLIP_MODE_SLIP6
1431 unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;
1432#else
1433 unsigned char s = END;
1434#endif
1435 /* put END into tty queue. Is it right ??? */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001436 if (!netif_queue_stopped(sl->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* if device busy no outfill */
Alan Coxf34d7a52008-04-30 00:54:13 -07001438 sl->tty->ops->write(sl->tty, &s, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
Alan Cox9ce6cf22007-11-19 15:03:38 +00001440 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 set_bit(SLF_OUTWAIT, &sl->flags);
1442
1443 mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
1444 }
1445out:
1446 spin_unlock(&sl->lock);
1447}
1448
1449static void sl_keepalive(unsigned long sls)
1450{
Alan Cox9ce6cf22007-11-19 15:03:38 +00001451 struct slip *sl = (struct slip *)sls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
1453 spin_lock(&sl->lock);
1454
1455 if (sl->tty == NULL)
1456 goto out;
1457
Alan Cox9ce6cf22007-11-19 15:03:38 +00001458 if (sl->keepalive) {
1459 if (test_bit(SLF_KEEPTEST, &sl->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 /* keepalive still high :(, we must hangup */
Alan Cox9ce6cf22007-11-19 15:03:38 +00001461 if (sl->outfill)
1462 /* outfill timer must be deleted too */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 (void)del_timer(&sl->outfill_timer);
1464 printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name);
Alan Cox9ce6cf22007-11-19 15:03:38 +00001465 /* this must hangup tty & close slip */
1466 tty_hangup(sl->tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 /* I think we need not something else */
1468 goto out;
Alan Cox9ce6cf22007-11-19 15:03:38 +00001469 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 set_bit(SLF_KEEPTEST, &sl->flags);
1471
1472 mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
1473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474out:
1475 spin_unlock(&sl->lock);
1476}
1477
1478#endif
1479MODULE_LICENSE("GPL");
1480MODULE_ALIAS_LDISC(N_SLIP);