1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * PPP synchronous tty channel driver for Linux. |
4 | * |
5 | * This is a ppp channel driver that can be used with tty device drivers |
6 | * that are frame oriented, such as synchronous HDLC devices. |
7 | * |
8 | * Complete PPP frames without encoding/decoding are exchanged between |
9 | * the channel driver and the device driver. |
10 | * |
11 | * The async map IOCTL codes are implemented to keep the user mode |
12 | * applications happy if they call them. Synchronous PPP does not use |
13 | * the async maps. |
14 | * |
15 | * Copyright 1999 Paul Mackerras. |
16 | * |
17 | * Also touched by the grubby hands of Paul Fulghum paulkf@microgate.com |
18 | * |
19 | * This driver provides the encapsulation and framing for sending |
20 | * and receiving PPP frames over sync serial lines. It relies on |
21 | * the generic PPP layer to give it frames to send and to process |
22 | * received frames. It implements the PPP line discipline. |
23 | * |
24 | * Part of the code in this driver was inspired by the old async-only |
25 | * PPP driver, written by Michael Callahan and Al Longyear, and |
26 | * subsequently hacked by Paul Mackerras. |
27 | * |
28 | * ==FILEVERSION 20040616== |
29 | */ |
30 | |
31 | #include <linux/module.h> |
32 | #include <linux/kernel.h> |
33 | #include <linux/skbuff.h> |
34 | #include <linux/tty.h> |
35 | #include <linux/netdevice.h> |
36 | #include <linux/poll.h> |
37 | #include <linux/ppp_defs.h> |
38 | #include <linux/ppp-ioctl.h> |
39 | #include <linux/ppp_channel.h> |
40 | #include <linux/spinlock.h> |
41 | #include <linux/completion.h> |
42 | #include <linux/init.h> |
43 | #include <linux/interrupt.h> |
44 | #include <linux/slab.h> |
45 | #include <linux/refcount.h> |
46 | #include <asm/unaligned.h> |
47 | #include <linux/uaccess.h> |
48 | |
49 | #define PPP_VERSION "2.4.2" |
50 | |
51 | /* Structure for storing local state. */ |
52 | struct syncppp { |
53 | struct tty_struct *tty; |
54 | unsigned int flags; |
55 | unsigned int rbits; |
56 | int mru; |
57 | spinlock_t xmit_lock; |
58 | spinlock_t recv_lock; |
59 | unsigned long xmit_flags; |
60 | u32 xaccm[8]; |
61 | u32 raccm; |
62 | unsigned int bytes_sent; |
63 | unsigned int bytes_rcvd; |
64 | |
65 | struct sk_buff *tpkt; |
66 | unsigned long last_xmit; |
67 | |
68 | struct sk_buff_head rqueue; |
69 | |
70 | struct tasklet_struct tsk; |
71 | |
72 | refcount_t refcnt; |
73 | struct completion dead_cmp; |
74 | struct ppp_channel chan; /* interface to generic ppp layer */ |
75 | }; |
76 | |
77 | /* Bit numbers in xmit_flags */ |
78 | #define XMIT_WAKEUP 0 |
79 | #define XMIT_FULL 1 |
80 | |
81 | /* Bits in rbits */ |
82 | #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) |
83 | |
84 | #define PPPSYNC_MAX_RQLEN 32 /* arbitrary */ |
85 | |
86 | /* |
87 | * Prototypes. |
88 | */ |
89 | static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *); |
90 | static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb); |
91 | static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, |
92 | unsigned long arg); |
93 | static void ppp_sync_process(struct tasklet_struct *t); |
94 | static int ppp_sync_push(struct syncppp *ap); |
95 | static void ppp_sync_flush_output(struct syncppp *ap); |
96 | static void ppp_sync_input(struct syncppp *ap, const u8 *buf, const u8 *flags, |
97 | int count); |
98 | |
99 | static const struct ppp_channel_ops sync_ops = { |
100 | .start_xmit = ppp_sync_send, |
101 | .ioctl = ppp_sync_ioctl, |
102 | }; |
103 | |
104 | /* |
105 | * Utility procedure to print a buffer in hex/ascii |
106 | */ |
107 | static void |
108 | ppp_print_buffer (const char *name, const __u8 *buf, int count) |
109 | { |
110 | if (name != NULL) |
111 | printk(KERN_DEBUG "ppp_synctty: %s, count = %d\n" , name, count); |
112 | |
113 | print_hex_dump_bytes("" , DUMP_PREFIX_NONE, buf, count); |
114 | } |
115 | |
116 | |
117 | /* |
118 | * Routines implementing the synchronous PPP line discipline. |
119 | */ |
120 | |
121 | /* |
122 | * We have a potential race on dereferencing tty->disc_data, |
123 | * because the tty layer provides no locking at all - thus one |
124 | * cpu could be running ppp_synctty_receive while another |
125 | * calls ppp_synctty_close, which zeroes tty->disc_data and |
126 | * frees the memory that ppp_synctty_receive is using. The best |
127 | * way to fix this is to use a rwlock in the tty struct, but for now |
128 | * we use a single global rwlock for all ttys in ppp line discipline. |
129 | * |
130 | * FIXME: Fixed in tty_io nowadays. |
131 | */ |
132 | static DEFINE_RWLOCK(disc_data_lock); |
133 | |
134 | static struct syncppp *sp_get(struct tty_struct *tty) |
135 | { |
136 | struct syncppp *ap; |
137 | |
138 | read_lock(&disc_data_lock); |
139 | ap = tty->disc_data; |
140 | if (ap != NULL) |
141 | refcount_inc(r: &ap->refcnt); |
142 | read_unlock(&disc_data_lock); |
143 | return ap; |
144 | } |
145 | |
146 | static void sp_put(struct syncppp *ap) |
147 | { |
148 | if (refcount_dec_and_test(r: &ap->refcnt)) |
149 | complete(&ap->dead_cmp); |
150 | } |
151 | |
152 | /* |
153 | * Called when a tty is put into sync-PPP line discipline. |
154 | */ |
155 | static int |
156 | ppp_sync_open(struct tty_struct *tty) |
157 | { |
158 | struct syncppp *ap; |
159 | int err; |
160 | int speed; |
161 | |
162 | if (tty->ops->write == NULL) |
163 | return -EOPNOTSUPP; |
164 | |
165 | ap = kzalloc(size: sizeof(*ap), GFP_KERNEL); |
166 | err = -ENOMEM; |
167 | if (!ap) |
168 | goto out; |
169 | |
170 | /* initialize the syncppp structure */ |
171 | ap->tty = tty; |
172 | ap->mru = PPP_MRU; |
173 | spin_lock_init(&ap->xmit_lock); |
174 | spin_lock_init(&ap->recv_lock); |
175 | ap->xaccm[0] = ~0U; |
176 | ap->xaccm[3] = 0x60000000U; |
177 | ap->raccm = ~0U; |
178 | |
179 | skb_queue_head_init(list: &ap->rqueue); |
180 | tasklet_setup(t: &ap->tsk, callback: ppp_sync_process); |
181 | |
182 | refcount_set(r: &ap->refcnt, n: 1); |
183 | init_completion(x: &ap->dead_cmp); |
184 | |
185 | ap->chan.private = ap; |
186 | ap->chan.ops = &sync_ops; |
187 | ap->chan.mtu = PPP_MRU; |
188 | ap->chan.hdrlen = 2; /* for A/C bytes */ |
189 | speed = tty_get_baud_rate(tty); |
190 | ap->chan.speed = speed; |
191 | err = ppp_register_channel(&ap->chan); |
192 | if (err) |
193 | goto out_free; |
194 | |
195 | tty->disc_data = ap; |
196 | tty->receive_room = 65536; |
197 | return 0; |
198 | |
199 | out_free: |
200 | kfree(objp: ap); |
201 | out: |
202 | return err; |
203 | } |
204 | |
205 | /* |
206 | * Called when the tty is put into another line discipline |
207 | * or it hangs up. We have to wait for any cpu currently |
208 | * executing in any of the other ppp_synctty_* routines to |
209 | * finish before we can call ppp_unregister_channel and free |
210 | * the syncppp struct. This routine must be called from |
211 | * process context, not interrupt or softirq context. |
212 | */ |
213 | static void |
214 | ppp_sync_close(struct tty_struct *tty) |
215 | { |
216 | struct syncppp *ap; |
217 | |
218 | write_lock_irq(&disc_data_lock); |
219 | ap = tty->disc_data; |
220 | tty->disc_data = NULL; |
221 | write_unlock_irq(&disc_data_lock); |
222 | if (!ap) |
223 | return; |
224 | |
225 | /* |
226 | * We have now ensured that nobody can start using ap from now |
227 | * on, but we have to wait for all existing users to finish. |
228 | * Note that ppp_unregister_channel ensures that no calls to |
229 | * our channel ops (i.e. ppp_sync_send/ioctl) are in progress |
230 | * by the time it returns. |
231 | */ |
232 | if (!refcount_dec_and_test(r: &ap->refcnt)) |
233 | wait_for_completion(&ap->dead_cmp); |
234 | tasklet_kill(t: &ap->tsk); |
235 | |
236 | ppp_unregister_channel(&ap->chan); |
237 | skb_queue_purge(list: &ap->rqueue); |
238 | kfree_skb(skb: ap->tpkt); |
239 | kfree(objp: ap); |
240 | } |
241 | |
242 | /* |
243 | * Called on tty hangup in process context. |
244 | * |
245 | * Wait for I/O to driver to complete and unregister PPP channel. |
246 | * This is already done by the close routine, so just call that. |
247 | */ |
248 | static void ppp_sync_hangup(struct tty_struct *tty) |
249 | { |
250 | ppp_sync_close(tty); |
251 | } |
252 | |
253 | /* |
254 | * Read does nothing - no data is ever available this way. |
255 | * Pppd reads and writes packets via /dev/ppp instead. |
256 | */ |
257 | static ssize_t |
258 | ppp_sync_read(struct tty_struct *tty, struct file *file, u8 *buf, size_t count, |
259 | void **cookie, unsigned long offset) |
260 | { |
261 | return -EAGAIN; |
262 | } |
263 | |
264 | /* |
265 | * Write on the tty does nothing, the packets all come in |
266 | * from the ppp generic stuff. |
267 | */ |
268 | static ssize_t |
269 | ppp_sync_write(struct tty_struct *tty, struct file *file, const u8 *buf, |
270 | size_t count) |
271 | { |
272 | return -EAGAIN; |
273 | } |
274 | |
275 | static int |
276 | ppp_synctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) |
277 | { |
278 | struct syncppp *ap = sp_get(tty); |
279 | int __user *p = (int __user *)arg; |
280 | int err, val; |
281 | |
282 | if (!ap) |
283 | return -ENXIO; |
284 | err = -EFAULT; |
285 | switch (cmd) { |
286 | case PPPIOCGCHAN: |
287 | err = -EFAULT; |
288 | if (put_user(ppp_channel_index(&ap->chan), p)) |
289 | break; |
290 | err = 0; |
291 | break; |
292 | |
293 | case PPPIOCGUNIT: |
294 | err = -EFAULT; |
295 | if (put_user(ppp_unit_number(&ap->chan), p)) |
296 | break; |
297 | err = 0; |
298 | break; |
299 | |
300 | case TCFLSH: |
301 | /* flush our buffers and the serial port's buffer */ |
302 | if (arg == TCIOFLUSH || arg == TCOFLUSH) |
303 | ppp_sync_flush_output(ap); |
304 | err = n_tty_ioctl_helper(tty, cmd, arg); |
305 | break; |
306 | |
307 | case FIONREAD: |
308 | val = 0; |
309 | if (put_user(val, p)) |
310 | break; |
311 | err = 0; |
312 | break; |
313 | |
314 | default: |
315 | err = tty_mode_ioctl(tty, cmd, arg); |
316 | break; |
317 | } |
318 | |
319 | sp_put(ap); |
320 | return err; |
321 | } |
322 | |
323 | /* May sleep, don't call from interrupt level or with interrupts disabled */ |
324 | static void |
325 | ppp_sync_receive(struct tty_struct *tty, const u8 *buf, const u8 *cflags, |
326 | size_t count) |
327 | { |
328 | struct syncppp *ap = sp_get(tty); |
329 | unsigned long flags; |
330 | |
331 | if (!ap) |
332 | return; |
333 | spin_lock_irqsave(&ap->recv_lock, flags); |
334 | ppp_sync_input(ap, buf, flags: cflags, count); |
335 | spin_unlock_irqrestore(lock: &ap->recv_lock, flags); |
336 | if (!skb_queue_empty(list: &ap->rqueue)) |
337 | tasklet_schedule(t: &ap->tsk); |
338 | sp_put(ap); |
339 | tty_unthrottle(tty); |
340 | } |
341 | |
342 | static void |
343 | ppp_sync_wakeup(struct tty_struct *tty) |
344 | { |
345 | struct syncppp *ap = sp_get(tty); |
346 | |
347 | clear_bit(TTY_DO_WRITE_WAKEUP, addr: &tty->flags); |
348 | if (!ap) |
349 | return; |
350 | set_bit(XMIT_WAKEUP, addr: &ap->xmit_flags); |
351 | tasklet_schedule(t: &ap->tsk); |
352 | sp_put(ap); |
353 | } |
354 | |
355 | |
356 | static struct tty_ldisc_ops ppp_sync_ldisc = { |
357 | .owner = THIS_MODULE, |
358 | .num = N_SYNC_PPP, |
359 | .name = "pppsync" , |
360 | .open = ppp_sync_open, |
361 | .close = ppp_sync_close, |
362 | .hangup = ppp_sync_hangup, |
363 | .read = ppp_sync_read, |
364 | .write = ppp_sync_write, |
365 | .ioctl = ppp_synctty_ioctl, |
366 | .receive_buf = ppp_sync_receive, |
367 | .write_wakeup = ppp_sync_wakeup, |
368 | }; |
369 | |
370 | static int __init |
371 | ppp_sync_init(void) |
372 | { |
373 | int err; |
374 | |
375 | err = tty_register_ldisc(new_ldisc: &ppp_sync_ldisc); |
376 | if (err != 0) |
377 | printk(KERN_ERR "PPP_sync: error %d registering line disc.\n" , |
378 | err); |
379 | return err; |
380 | } |
381 | |
382 | /* |
383 | * The following routines provide the PPP channel interface. |
384 | */ |
385 | static int |
386 | ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg) |
387 | { |
388 | struct syncppp *ap = chan->private; |
389 | int err, val; |
390 | u32 accm[8]; |
391 | void __user *argp = (void __user *)arg; |
392 | u32 __user *p = argp; |
393 | |
394 | err = -EFAULT; |
395 | switch (cmd) { |
396 | case PPPIOCGFLAGS: |
397 | val = ap->flags | ap->rbits; |
398 | if (put_user(val, (int __user *) argp)) |
399 | break; |
400 | err = 0; |
401 | break; |
402 | case PPPIOCSFLAGS: |
403 | if (get_user(val, (int __user *) argp)) |
404 | break; |
405 | ap->flags = val & ~SC_RCV_BITS; |
406 | spin_lock_irq(lock: &ap->recv_lock); |
407 | ap->rbits = val & SC_RCV_BITS; |
408 | spin_unlock_irq(lock: &ap->recv_lock); |
409 | err = 0; |
410 | break; |
411 | |
412 | case PPPIOCGASYNCMAP: |
413 | if (put_user(ap->xaccm[0], p)) |
414 | break; |
415 | err = 0; |
416 | break; |
417 | case PPPIOCSASYNCMAP: |
418 | if (get_user(ap->xaccm[0], p)) |
419 | break; |
420 | err = 0; |
421 | break; |
422 | |
423 | case PPPIOCGRASYNCMAP: |
424 | if (put_user(ap->raccm, p)) |
425 | break; |
426 | err = 0; |
427 | break; |
428 | case PPPIOCSRASYNCMAP: |
429 | if (get_user(ap->raccm, p)) |
430 | break; |
431 | err = 0; |
432 | break; |
433 | |
434 | case PPPIOCGXASYNCMAP: |
435 | if (copy_to_user(to: argp, from: ap->xaccm, n: sizeof(ap->xaccm))) |
436 | break; |
437 | err = 0; |
438 | break; |
439 | case PPPIOCSXASYNCMAP: |
440 | if (copy_from_user(to: accm, from: argp, n: sizeof(accm))) |
441 | break; |
442 | accm[2] &= ~0x40000000U; /* can't escape 0x5e */ |
443 | accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ |
444 | memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); |
445 | err = 0; |
446 | break; |
447 | |
448 | case PPPIOCGMRU: |
449 | if (put_user(ap->mru, (int __user *) argp)) |
450 | break; |
451 | err = 0; |
452 | break; |
453 | case PPPIOCSMRU: |
454 | if (get_user(val, (int __user *) argp)) |
455 | break; |
456 | if (val < PPP_MRU) |
457 | val = PPP_MRU; |
458 | ap->mru = val; |
459 | err = 0; |
460 | break; |
461 | |
462 | default: |
463 | err = -ENOTTY; |
464 | } |
465 | return err; |
466 | } |
467 | |
468 | /* |
469 | * This is called at softirq level to deliver received packets |
470 | * to the ppp_generic code, and to tell the ppp_generic code |
471 | * if we can accept more output now. |
472 | */ |
473 | static void ppp_sync_process(struct tasklet_struct *t) |
474 | { |
475 | struct syncppp *ap = from_tasklet(ap, t, tsk); |
476 | struct sk_buff *skb; |
477 | |
478 | /* process received packets */ |
479 | while ((skb = skb_dequeue(list: &ap->rqueue)) != NULL) { |
480 | if (skb->len == 0) { |
481 | /* zero length buffers indicate error */ |
482 | ppp_input_error(&ap->chan, code: 0); |
483 | kfree_skb(skb); |
484 | } |
485 | else |
486 | ppp_input(&ap->chan, skb); |
487 | } |
488 | |
489 | /* try to push more stuff out */ |
490 | if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_sync_push(ap)) |
491 | ppp_output_wakeup(&ap->chan); |
492 | } |
493 | |
494 | /* |
495 | * Procedures for encapsulation and framing. |
496 | */ |
497 | |
498 | static struct sk_buff* |
499 | ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) |
500 | { |
501 | int proto; |
502 | unsigned char *data; |
503 | int islcp; |
504 | |
505 | data = skb->data; |
506 | proto = get_unaligned_be16(p: data); |
507 | |
508 | /* LCP packets with codes between 1 (configure-request) |
509 | * and 7 (code-reject) must be sent as though no options |
510 | * have been negotiated. |
511 | */ |
512 | islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7; |
513 | |
514 | /* compress protocol field if option enabled */ |
515 | if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp) |
516 | skb_pull(skb,len: 1); |
517 | |
518 | /* prepend address/control fields if necessary */ |
519 | if ((ap->flags & SC_COMP_AC) == 0 || islcp) { |
520 | if (skb_headroom(skb) < 2) { |
521 | struct sk_buff *npkt = dev_alloc_skb(length: skb->len + 2); |
522 | if (npkt == NULL) { |
523 | kfree_skb(skb); |
524 | return NULL; |
525 | } |
526 | skb_reserve(skb: npkt,len: 2); |
527 | skb_copy_from_linear_data(skb, |
528 | to: skb_put(skb: npkt, len: skb->len), len: skb->len); |
529 | consume_skb(skb); |
530 | skb = npkt; |
531 | } |
532 | skb_push(skb,len: 2); |
533 | skb->data[0] = PPP_ALLSTATIONS; |
534 | skb->data[1] = PPP_UI; |
535 | } |
536 | |
537 | ap->last_xmit = jiffies; |
538 | |
539 | if (skb && ap->flags & SC_LOG_OUTPKT) |
540 | ppp_print_buffer (name: "send buffer" , buf: skb->data, count: skb->len); |
541 | |
542 | return skb; |
543 | } |
544 | |
545 | /* |
546 | * Transmit-side routines. |
547 | */ |
548 | |
549 | /* |
550 | * Send a packet to the peer over an sync tty line. |
551 | * Returns 1 iff the packet was accepted. |
552 | * If the packet was not accepted, we will call ppp_output_wakeup |
553 | * at some later time. |
554 | */ |
555 | static int |
556 | ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb) |
557 | { |
558 | struct syncppp *ap = chan->private; |
559 | |
560 | ppp_sync_push(ap); |
561 | |
562 | if (test_and_set_bit(XMIT_FULL, addr: &ap->xmit_flags)) |
563 | return 0; /* already full */ |
564 | skb = ppp_sync_txmunge(ap, skb); |
565 | if (skb != NULL) |
566 | ap->tpkt = skb; |
567 | else |
568 | clear_bit(XMIT_FULL, addr: &ap->xmit_flags); |
569 | |
570 | ppp_sync_push(ap); |
571 | return 1; |
572 | } |
573 | |
574 | /* |
575 | * Push as much data as possible out to the tty. |
576 | */ |
577 | static int |
578 | ppp_sync_push(struct syncppp *ap) |
579 | { |
580 | int sent, done = 0; |
581 | struct tty_struct *tty = ap->tty; |
582 | int tty_stuffed = 0; |
583 | |
584 | if (!spin_trylock_bh(lock: &ap->xmit_lock)) |
585 | return 0; |
586 | for (;;) { |
587 | if (test_and_clear_bit(XMIT_WAKEUP, addr: &ap->xmit_flags)) |
588 | tty_stuffed = 0; |
589 | if (!tty_stuffed && ap->tpkt) { |
590 | set_bit(TTY_DO_WRITE_WAKEUP, addr: &tty->flags); |
591 | sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len); |
592 | if (sent < 0) |
593 | goto flush; /* error, e.g. loss of CD */ |
594 | if (sent < ap->tpkt->len) { |
595 | tty_stuffed = 1; |
596 | } else { |
597 | consume_skb(skb: ap->tpkt); |
598 | ap->tpkt = NULL; |
599 | clear_bit(XMIT_FULL, addr: &ap->xmit_flags); |
600 | done = 1; |
601 | } |
602 | continue; |
603 | } |
604 | /* haven't made any progress */ |
605 | spin_unlock_bh(lock: &ap->xmit_lock); |
606 | if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || |
607 | (!tty_stuffed && ap->tpkt))) |
608 | break; |
609 | if (!spin_trylock_bh(lock: &ap->xmit_lock)) |
610 | break; |
611 | } |
612 | return done; |
613 | |
614 | flush: |
615 | if (ap->tpkt) { |
616 | kfree_skb(skb: ap->tpkt); |
617 | ap->tpkt = NULL; |
618 | clear_bit(XMIT_FULL, addr: &ap->xmit_flags); |
619 | done = 1; |
620 | } |
621 | spin_unlock_bh(lock: &ap->xmit_lock); |
622 | return done; |
623 | } |
624 | |
625 | /* |
626 | * Flush output from our internal buffers. |
627 | * Called for the TCFLSH ioctl. |
628 | */ |
629 | static void |
630 | ppp_sync_flush_output(struct syncppp *ap) |
631 | { |
632 | int done = 0; |
633 | |
634 | spin_lock_bh(lock: &ap->xmit_lock); |
635 | if (ap->tpkt != NULL) { |
636 | kfree_skb(skb: ap->tpkt); |
637 | ap->tpkt = NULL; |
638 | clear_bit(XMIT_FULL, addr: &ap->xmit_flags); |
639 | done = 1; |
640 | } |
641 | spin_unlock_bh(lock: &ap->xmit_lock); |
642 | if (done) |
643 | ppp_output_wakeup(&ap->chan); |
644 | } |
645 | |
646 | /* |
647 | * Receive-side routines. |
648 | */ |
649 | |
650 | /* called when the tty driver has data for us. |
651 | * |
652 | * Data is frame oriented: each call to ppp_sync_input is considered |
653 | * a whole frame. If the 1st flag byte is non-zero then the whole |
654 | * frame is considered to be in error and is tossed. |
655 | */ |
656 | static void |
657 | ppp_sync_input(struct syncppp *ap, const u8 *buf, const u8 *flags, int count) |
658 | { |
659 | struct sk_buff *skb; |
660 | unsigned char *p; |
661 | |
662 | if (count == 0) |
663 | return; |
664 | |
665 | if (ap->flags & SC_LOG_INPKT) |
666 | ppp_print_buffer (name: "receive buffer" , buf, count); |
667 | |
668 | /* stuff the chars in the skb */ |
669 | skb = dev_alloc_skb(length: ap->mru + PPP_HDRLEN + 2); |
670 | if (!skb) { |
671 | printk(KERN_ERR "PPPsync: no memory (input pkt)\n" ); |
672 | goto err; |
673 | } |
674 | /* Try to get the payload 4-byte aligned */ |
675 | if (buf[0] != PPP_ALLSTATIONS) |
676 | skb_reserve(skb, len: 2 + (buf[0] & 1)); |
677 | |
678 | if (flags && *flags) { |
679 | /* error flag set, ignore frame */ |
680 | goto err; |
681 | } else if (count > skb_tailroom(skb)) { |
682 | /* packet overflowed MRU */ |
683 | goto err; |
684 | } |
685 | |
686 | skb_put_data(skb, data: buf, len: count); |
687 | |
688 | /* strip address/control field if present */ |
689 | p = skb->data; |
690 | if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { |
691 | /* chop off address/control */ |
692 | if (skb->len < 3) |
693 | goto err; |
694 | p = skb_pull(skb, len: 2); |
695 | } |
696 | |
697 | /* PPP packet length should be >= 2 bytes when protocol field is not |
698 | * compressed. |
699 | */ |
700 | if (!(p[0] & 0x01) && skb->len < 2) |
701 | goto err; |
702 | |
703 | /* queue the frame to be processed */ |
704 | skb_queue_tail(list: &ap->rqueue, newsk: skb); |
705 | return; |
706 | |
707 | err: |
708 | /* queue zero length packet as error indication */ |
709 | if (skb || (skb = dev_alloc_skb(length: 0))) { |
710 | skb_trim(skb, len: 0); |
711 | skb_queue_tail(list: &ap->rqueue, newsk: skb); |
712 | } |
713 | } |
714 | |
715 | static void __exit |
716 | ppp_sync_cleanup(void) |
717 | { |
718 | tty_unregister_ldisc(ldisc: &ppp_sync_ldisc); |
719 | } |
720 | |
721 | module_init(ppp_sync_init); |
722 | module_exit(ppp_sync_cleanup); |
723 | MODULE_LICENSE("GPL" ); |
724 | MODULE_ALIAS_LDISC(N_SYNC_PPP); |
725 | |