21 #include <linux/module.h>
22 #include <linux/kernel.h>
24 #include <linux/tty.h>
25 #include <linux/netdevice.h>
26 #include <linux/poll.h>
28 #include <linux/ppp_defs.h>
35 #include <linux/slab.h>
36 #include <asm/unaligned.h>
37 #include <asm/uaccess.h>
38 #include <asm/string.h>
40 #define PPP_VERSION "2.4.2"
86 #define SC_PREV_ERROR 4
89 #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
91 static int flag_time =
HZ;
93 MODULE_PARM_DESC(flag_time,
"ppp_async: interval between flagged packets (in clock ticks)");
100 static int ppp_async_encode(
struct asyncppp *ap);
102 static int ppp_async_push(
struct asyncppp *ap);
103 static void ppp_async_flush_output(
struct asyncppp *ap);
104 static void ppp_async_input(
struct asyncppp *ap,
const unsigned char *
buf,
108 static void ppp_async_process(
unsigned long arg);
110 static void async_lcp_peek(
struct asyncppp *ap,
unsigned char *
data,
111 int len,
int inbound);
114 .start_xmit = ppp_async_send,
115 .ioctl = ppp_async_ioctl,
148 static void ap_put(
struct asyncppp *ap)
179 ap->
xaccm[3] = 0x60000000
U;
185 skb_queue_head_init(&ap->
rqueue);
191 ap->
chan.private = ap;
192 ap->
chan.ops = &async_ops;
195 ap->
chan.speed = speed;
254 static int ppp_asynctty_hangup(
struct tty_struct *tty)
256 ppp_asynctty_close(tty);
266 unsigned char __user *
buf,
size_t count)
277 const unsigned char *
buf,
size_t count)
289 unsigned int cmd,
unsigned long arg)
316 ppp_async_flush_output(ap);
345 ppp_asynctty_receive(
struct tty_struct *tty,
const unsigned char *
buf,
354 ppp_async_input(ap, buf, cflags, count);
355 spin_unlock_irqrestore(&ap->
recv_lock, flags);
356 if (!skb_queue_empty(&ap->
rqueue))
357 tasklet_schedule(&ap->
tsk);
371 tasklet_schedule(&ap->
tsk);
380 .open = ppp_asynctty_open,
381 .close = ppp_asynctty_close,
382 .hangup = ppp_asynctty_hangup,
383 .read = ppp_asynctty_read,
384 .write = ppp_asynctty_write,
385 .ioctl = ppp_asynctty_ioctl,
386 .poll = ppp_asynctty_poll,
387 .receive_buf = ppp_asynctty_receive,
388 .write_wakeup = ppp_asynctty_wakeup,
407 ppp_async_ioctl(
struct ppp_channel *
chan,
unsigned int cmd,
unsigned long arg)
463 accm[2] &= ~0x40000000
U;
464 accm[3] |= 0x60000000
U;
495 static void ppp_async_process(
unsigned long arg)
524 #define PUT_BYTE(ap, buf, c, islcp) do { \
525 if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\
526 *buf++ = PPP_ESCAPE; \
527 *buf++ = c ^ PPP_TRANS; \
533 ppp_async_encode(
struct asyncppp *ap)
536 unsigned char *
buf, *buflim;
544 data = ap->
tpkt->data;
545 count = ap->
tpkt->len;
547 proto = get_unaligned_be16(data);
554 islcp = proto ==
PPP_LCP && 1 <= data[2] && data[2] <= 7;
558 async_lcp_peek(ap, data, count, 0);
564 if (islcp || flag_time == 0 ||
587 while (i < count && buf < buflim) {
611 c = (fcs >> 8) & 0xff;
672 if (!tty_stuffed && ap->
optr < ap->
olim) {
675 sent = tty->
ops->write(tty, ap->
optr, avail);
684 if (ppp_async_encode(ap)) {
703 (!tty_stuffed && ap->
tpkt)))
731 ppp_async_flush_output(
struct asyncppp *ap)
754 scan_ordinary(
struct asyncppp *ap,
const unsigned char *buf,
int count)
758 for (i = 0; i <
count; ++
i) {
761 (c < 0x20 && (ap->
raccm & (1 << c)) != 0))
769 process_input_packet(
struct asyncppp *ap)
788 for (; len > 0; --
len)
809 proto = (proto << 8) + p[1];
811 async_lcp_peek(ap, p, skb->
len, 1);
815 skb->cb[0] = ap->
state;
827 skb_reserve(skb, - skb_headroom(skb));
835 ppp_async_input(
struct asyncppp *ap,
const unsigned char *buf,
836 char *flags,
int count)
843 if (~ap->
rbits & SC_RCV_BITS) {
845 for (i = 0; i <
count; ++
i) {
847 if (flags && flags[i] != 0)
850 c = ((c >> 4) ^ c) & 0xf;
861 n = scan_ordinary(ap, buf, count);
866 for (j = 0; j <
n; ++
j)
867 if ((f = flags[j]) != 0)
891 skb_reserve(skb, 2 + (buf[0] & 1));
893 if (n > skb_tailroom(skb)) {
910 if (flags !=
NULL && flags[n] != 0) {
913 process_input_packet(ap);
953 #define LCP_ASYNCMAP 2
955 static void async_lcp_peek(
struct asyncppp *ap,
unsigned char *
data,
956 int len,
int inbound)
968 dlen = get_unaligned_be16(data + 2);
978 for (i = 1; i <
dlen; ++
i)
999 while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) {
1002 val = get_unaligned_be16(data + 2);
1021 static void __exit ppp_async_cleanup(
void)