2 * PPP async serial channel driver for Linux.
4 * Copyright 1999 Paul Mackerras.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 * This driver provides the encapsulation and framing for sending
12 * and receiving PPP frames over async serial lines. It relies on
13 * the generic PPP layer to give it frames to send and to process
14 * received frames. It implements the PPP line discipline.
16 * Part of the code in this driver was inspired by the old async-only
17 * PPP driver, written by Michael Callahan and Al Longyear, and
18 * subsequently hacked by Paul Mackerras.
20 * ==FILEVERSION 20000227==
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/skbuff.h>
26 #include <linux/tty.h>
27 #include <linux/netdevice.h>
28 #include <linux/poll.h>
29 #include <linux/ppp_defs.h>
30 #include <linux/if_ppp.h>
31 #include <linux/ppp_channel.h>
32 #include <linux/spinlock.h>
33 #include <linux/init.h>
34 #include <asm/uaccess.h>
36 #ifndef spin_trylock_bh
37 #define spin_trylock_bh(lock) ({ int __r; local_bh_disable(); \
38 __r = spin_trylock(lock); \
39 if (!__r) local_bh_enable(); \
43 #define PPP_VERSION "2.4.1"
47 /* Structure for storing local state. */
49 struct tty_struct
*tty
;
56 unsigned long xmit_flags
;
59 unsigned int bytes_sent
;
60 unsigned int bytes_rcvd
;
67 unsigned long last_xmit
;
72 struct ppp_channel chan
; /* interface to generic ppp layer */
73 unsigned char obuf
[OBUFSIZE
];
76 /* Bit numbers in xmit_flags */
81 #define SC_TOSS 0x20000000
82 #define SC_ESCAPE 0x40000000
85 #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
87 static int flag_time
= HZ
;
88 MODULE_PARM(flag_time
, "i");
93 static int ppp_async_encode(struct asyncppp
*ap
);
94 static int ppp_async_send(struct ppp_channel
*chan
, struct sk_buff
*skb
);
95 static int ppp_async_push(struct asyncppp
*ap
);
96 static void ppp_async_flush_output(struct asyncppp
*ap
);
97 static void ppp_async_input(struct asyncppp
*ap
, const unsigned char *buf
,
98 char *flags
, int count
);
99 static int ppp_async_ioctl(struct ppp_channel
*chan
, unsigned int cmd
,
101 static void async_lcp_peek(struct asyncppp
*ap
, unsigned char *data
,
102 int len
, int inbound
);
104 struct ppp_channel_ops async_ops
= {
110 * Routines implementing the PPP line discipline.
114 * Called when a tty is put into PPP line discipline.
117 ppp_asynctty_open(struct tty_struct
*tty
)
124 ap
= kmalloc(sizeof(*ap
), GFP_KERNEL
);
128 /* initialize the asyncppp structure */
129 memset(ap
, 0, sizeof(*ap
));
132 spin_lock_init(&ap
->xmit_lock
);
133 spin_lock_init(&ap
->recv_lock
);
135 ap
->xaccm
[3] = 0x60000000U
;
141 ap
->chan
.private = ap
;
142 ap
->chan
.ops
= &async_ops
;
143 ap
->chan
.mtu
= PPP_MRU
;
144 err
= ppp_register_channel(&ap
->chan
);
160 * Called when the tty is put into another line discipline
162 * We assume that while we are in this routine, the tty layer
163 * won't call any of the other line discipline entries for the
167 ppp_asynctty_close(struct tty_struct
*tty
)
169 struct asyncppp
*ap
= tty
->disc_data
;
174 ppp_unregister_channel(&ap
->chan
);
187 ppp_asynctty_read(struct tty_struct
*tty
, struct file
*file
,
188 unsigned char *buf
, size_t count
)
190 /* For now, do the same as the old 2.3.x code useta */
191 struct asyncppp
*ap
= tty
->disc_data
;
195 return ppp_channel_read(&ap
->chan
, file
, buf
, count
);
199 * Write on the tty does nothing, the packets all come in
200 * from the ppp generic stuff.
203 ppp_asynctty_write(struct tty_struct
*tty
, struct file
*file
,
204 const unsigned char *buf
, size_t count
)
206 /* For now, do the same as the old 2.3.x code useta */
207 struct asyncppp
*ap
= tty
->disc_data
;
211 return ppp_channel_write(&ap
->chan
, buf
, count
);
215 ppp_asynctty_ioctl(struct tty_struct
*tty
, struct file
*file
,
216 unsigned int cmd
, unsigned long arg
)
218 struct asyncppp
*ap
= tty
->disc_data
;
228 if (put_user(ppp_channel_index(&ap
->chan
), (int *) arg
))
238 if (put_user(ppp_unit_number(&ap
->chan
), (int *) arg
))
245 err
= n_tty_ioctl(tty
, file
, cmd
, arg
);
249 /* flush our buffers and the serial port's buffer */
250 if (arg
== TCIOFLUSH
|| arg
== TCOFLUSH
)
251 ppp_async_flush_output(ap
);
252 err
= n_tty_ioctl(tty
, file
, cmd
, arg
);
257 if (put_user(val
, (int *) arg
))
263 * For now, do the same as the old 2.3 driver useta
267 case PPPIOCGASYNCMAP
:
268 case PPPIOCSASYNCMAP
:
269 case PPPIOCGRASYNCMAP
:
270 case PPPIOCSRASYNCMAP
:
271 case PPPIOCGXASYNCMAP
:
272 case PPPIOCSXASYNCMAP
:
276 if (!capable(CAP_NET_ADMIN
))
278 err
= ppp_async_ioctl(&ap
->chan
, cmd
, arg
);
283 err
= ppp_channel_ioctl(&ap
->chan
, cmd
, arg
);
294 ppp_asynctty_poll(struct tty_struct
*tty
, struct file
*file
, poll_table
*wait
)
297 struct asyncppp
*ap
= tty
->disc_data
;
299 mask
= POLLOUT
| POLLWRNORM
;
301 * For now, do the same as the old 2.3 driver useta
304 mask
|= ppp_channel_poll(&ap
->chan
, file
, wait
);
305 if (test_bit(TTY_OTHER_CLOSED
, &tty
->flags
) || tty_hung_up_p(file
))
311 ppp_asynctty_room(struct tty_struct
*tty
)
317 ppp_asynctty_receive(struct tty_struct
*tty
, const unsigned char *buf
,
318 char *flags
, int count
)
320 struct asyncppp
*ap
= tty
->disc_data
;
324 spin_lock_bh(&ap
->recv_lock
);
325 ppp_async_input(ap
, buf
, flags
, count
);
326 spin_unlock_bh(&ap
->recv_lock
);
327 if (test_and_clear_bit(TTY_THROTTLED
, &tty
->flags
)
328 && tty
->driver
.unthrottle
)
329 tty
->driver
.unthrottle(tty
);
333 ppp_asynctty_wakeup(struct tty_struct
*tty
)
335 struct asyncppp
*ap
= tty
->disc_data
;
337 clear_bit(TTY_DO_WRITE_WAKEUP
, &tty
->flags
);
340 if (ppp_async_push(ap
))
341 ppp_output_wakeup(&ap
->chan
);
345 static struct tty_ldisc ppp_ldisc
= {
346 magic
: TTY_LDISC_MAGIC
,
348 open
: ppp_asynctty_open
,
349 close
: ppp_asynctty_close
,
350 read
: ppp_asynctty_read
,
351 write
: ppp_asynctty_write
,
352 ioctl
: ppp_asynctty_ioctl
,
353 poll
: ppp_asynctty_poll
,
354 receive_room
: ppp_asynctty_room
,
355 receive_buf
: ppp_asynctty_receive
,
356 write_wakeup
: ppp_asynctty_wakeup
,
364 err
= tty_register_ldisc(N_PPP
, &ppp_ldisc
);
366 printk(KERN_ERR
"PPP_async: error %d registering line disc.\n",
372 * The following routines provide the PPP channel interface.
375 ppp_async_ioctl(struct ppp_channel
*chan
, unsigned int cmd
, unsigned long arg
)
377 struct asyncppp
*ap
= chan
->private;
384 val
= ap
->flags
| ap
->rbits
;
385 if (put_user(val
, (int *) arg
))
390 if (get_user(val
, (int *) arg
))
392 ap
->flags
= val
& ~SC_RCV_BITS
;
393 spin_lock_bh(&ap
->recv_lock
);
394 ap
->rbits
= val
& SC_RCV_BITS
;
395 spin_unlock_bh(&ap
->recv_lock
);
399 case PPPIOCGASYNCMAP
:
400 if (put_user(ap
->xaccm
[0], (u32
*) arg
))
404 case PPPIOCSASYNCMAP
:
405 if (get_user(ap
->xaccm
[0], (u32
*) arg
))
410 case PPPIOCGRASYNCMAP
:
411 if (put_user(ap
->raccm
, (u32
*) arg
))
415 case PPPIOCSRASYNCMAP
:
416 if (get_user(ap
->raccm
, (u32
*) arg
))
421 case PPPIOCGXASYNCMAP
:
422 if (copy_to_user((void *) arg
, ap
->xaccm
, sizeof(ap
->xaccm
)))
426 case PPPIOCSXASYNCMAP
:
427 if (copy_from_user(accm
, (void *) arg
, sizeof(accm
)))
429 accm
[2] &= ~0x40000000U
; /* can't escape 0x5e */
430 accm
[3] |= 0x60000000U
; /* must escape 0x7d, 0x7e */
431 memcpy(ap
->xaccm
, accm
, sizeof(ap
->xaccm
));
436 if (put_user(ap
->mru
, (int *) arg
))
441 if (get_user(val
, (int *) arg
))
457 * Procedures for encapsulation and framing.
460 u16 ppp_crc16_table
[256] = {
461 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
462 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
463 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
464 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
465 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
466 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
467 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
468 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
469 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
470 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
471 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
472 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
473 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
474 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
475 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
476 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
477 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
478 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
479 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
480 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
481 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
482 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
483 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
484 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
485 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
486 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
487 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
488 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
489 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
490 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
491 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
492 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
494 EXPORT_SYMBOL(ppp_crc16_table
);
495 #define fcstab ppp_crc16_table /* for PPP_FCS macro */
498 * Procedure to encode the data for async serial transmission.
499 * Does octet stuffing (escaping), puts the address/control bytes
500 * on if A/C compression is disabled, and does protocol compression.
501 * Assumes ap->tpkt != 0 on entry.
502 * Returns 1 if we finished the current frame, 0 otherwise.
505 #define PUT_BYTE(ap, buf, c, islcp) do { \
506 if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\
507 *buf++ = PPP_ESCAPE; \
514 ppp_async_encode(struct asyncppp
*ap
)
516 int fcs
, i
, count
, c
, proto
;
517 unsigned char *buf
, *buflim
;
525 data
= ap
->tpkt
->data
;
526 count
= ap
->tpkt
->len
;
528 proto
= (data
[0] << 8) + data
[1];
531 * LCP packets with code values between 1 (configure-reqest)
532 * and 7 (code-reject) must be sent as though no options
533 * had been negotiated.
535 islcp
= proto
== PPP_LCP
&& 1 <= data
[2] && data
[2] <= 7;
539 async_lcp_peek(ap
, data
, count
, 0);
542 * Start of a new packet - insert the leading FLAG
543 * character if necessary.
545 if (islcp
|| flag_time
== 0
546 || jiffies
- ap
->last_xmit
>= flag_time
)
548 ap
->last_xmit
= jiffies
;
552 * Put in the address/control bytes if necessary
554 if ((ap
->flags
& SC_COMP_AC
) == 0 || islcp
) {
555 PUT_BYTE(ap
, buf
, 0xff, islcp
);
556 fcs
= PPP_FCS(fcs
, 0xff);
557 PUT_BYTE(ap
, buf
, 0x03, islcp
);
558 fcs
= PPP_FCS(fcs
, 0x03);
563 * Once we put in the last byte, we need to put in the FCS
564 * and closing flag, so make sure there is at least 7 bytes
565 * of free space in the output buffer.
567 buflim
= ap
->obuf
+ OBUFSIZE
- 6;
568 while (i
< count
&& buf
< buflim
) {
570 if (i
== 1 && c
== 0 && (ap
->flags
& SC_COMP_PROT
))
571 continue; /* compress protocol field */
572 fcs
= PPP_FCS(fcs
, c
);
573 PUT_BYTE(ap
, buf
, c
, islcp
);
578 * Remember where we are up to in this packet.
587 * We have finished the packet. Add the FCS and flag.
591 PUT_BYTE(ap
, buf
, c
, islcp
);
592 c
= (fcs
>> 8) & 0xff;
593 PUT_BYTE(ap
, buf
, c
, islcp
);
603 * Transmit-side routines.
607 * Send a packet to the peer over an async tty line.
608 * Returns 1 iff the packet was accepted.
609 * If the packet was not accepted, we will call ppp_output_wakeup
610 * at some later time.
613 ppp_async_send(struct ppp_channel
*chan
, struct sk_buff
*skb
)
615 struct asyncppp
*ap
= chan
->private;
619 if (test_and_set_bit(XMIT_FULL
, &ap
->xmit_flags
))
620 return 0; /* already full */
629 * Push as much data as possible out to the tty.
632 ppp_async_push(struct asyncppp
*ap
)
634 int avail
, sent
, done
= 0;
635 struct tty_struct
*tty
= ap
->tty
;
638 set_bit(XMIT_WAKEUP
, &ap
->xmit_flags
);
639 if (!spin_trylock_bh(&ap
->xmit_lock
))
642 if (test_and_clear_bit(XMIT_WAKEUP
, &ap
->xmit_flags
))
644 if (!tty_stuffed
&& ap
->optr
< ap
->olim
) {
645 avail
= ap
->olim
- ap
->optr
;
646 set_bit(TTY_DO_WRITE_WAKEUP
, &tty
->flags
);
647 sent
= tty
->driver
.write(tty
, 0, ap
->optr
, avail
);
649 goto flush
; /* error, e.g. loss of CD */
655 if (ap
->optr
== ap
->olim
&& ap
->tpkt
!= 0) {
656 if (ppp_async_encode(ap
)) {
657 /* finished processing ap->tpkt */
658 clear_bit(XMIT_FULL
, &ap
->xmit_flags
);
663 /* haven't made any progress */
664 spin_unlock_bh(&ap
->xmit_lock
);
665 if (!(test_bit(XMIT_WAKEUP
, &ap
->xmit_flags
)
666 || (!tty_stuffed
&& ap
->tpkt
!= 0)))
668 if (!spin_trylock_bh(&ap
->xmit_lock
))
677 clear_bit(XMIT_FULL
, &ap
->xmit_flags
);
681 spin_unlock_bh(&ap
->xmit_lock
);
686 * Flush output from our internal buffers.
687 * Called for the TCFLSH ioctl.
690 ppp_async_flush_output(struct asyncppp
*ap
)
694 spin_lock_bh(&ap
->xmit_lock
);
696 if (ap
->tpkt
!= NULL
) {
699 clear_bit(XMIT_FULL
, &ap
->xmit_flags
);
702 spin_unlock_bh(&ap
->xmit_lock
);
704 ppp_output_wakeup(&ap
->chan
);
708 * Receive-side routines.
711 /* see how many ordinary chars there are at the start of buf */
713 scan_ordinary(struct asyncppp
*ap
, const unsigned char *buf
, int count
)
717 for (i
= 0; i
< count
; ++i
) {
719 if (c
== PPP_ESCAPE
|| c
== PPP_FLAG
720 || (c
< 0x20 && (ap
->raccm
& (1 << c
)) != 0))
726 /* called when a flag is seen - do end-of-packet processing */
728 process_input_packet(struct asyncppp
*ap
)
732 unsigned int len
, fcs
, proto
;
737 if ((ap
->state
& (SC_TOSS
| SC_ESCAPE
)) || skb
== 0) {
738 ap
->state
&= ~(SC_TOSS
| SC_ESCAPE
);
748 goto err
; /* too short */
750 for (; len
> 0; --len
)
751 fcs
= PPP_FCS(fcs
, *p
++);
752 if (fcs
!= PPP_GOODFCS
)
753 goto err
; /* bad FCS */
754 skb_trim(skb
, skb
->len
- 2);
756 /* check for address/control and protocol compression */
758 if (p
[0] == PPP_ALLSTATIONS
&& p
[1] == PPP_UI
) {
759 /* chop off address/control */
762 p
= skb_pull(skb
, 2);
766 /* protocol is compressed */
767 skb_push(skb
, 1)[0] = 0;
771 proto
= (proto
<< 8) + p
[1];
772 if (proto
== PPP_LCP
)
773 async_lcp_peek(ap
, p
, skb
->len
, 1);
776 /* all OK, give it to the generic layer */
777 ppp_input(&ap
->chan
, skb
);
782 ppp_input_error(&ap
->chan
, code
);
786 input_error(struct asyncppp
*ap
, int code
)
788 ap
->state
|= SC_TOSS
;
789 ppp_input_error(&ap
->chan
, code
);
792 /* called when the tty driver has data for us. */
794 ppp_async_input(struct asyncppp
*ap
, const unsigned char *buf
,
795 char *flags
, int count
)
798 int c
, i
, j
, n
, s
, f
;
801 /* update bits used for 8-bit cleanness detection */
802 if (~ap
->rbits
& SC_RCV_BITS
) {
804 for (i
= 0; i
< count
; ++i
) {
806 if (flags
!= 0 && flags
[i
] != 0)
808 s
|= (c
& 0x80)? SC_RCV_B7_1
: SC_RCV_B7_0
;
809 c
= ((c
>> 4) ^ c
) & 0xf;
810 s
|= (0x6996 & (1 << c
))? SC_RCV_ODDP
: SC_RCV_EVNP
;
816 /* scan through and see how many chars we can do in bulk */
817 if ((ap
->state
& SC_ESCAPE
) && buf
[0] == PPP_ESCAPE
)
820 n
= scan_ordinary(ap
, buf
, count
);
823 if (flags
!= 0 && (ap
->state
& SC_TOSS
) == 0) {
824 /* check the flags to see if any char had an error */
825 for (j
= 0; j
< n
; ++j
)
826 if ((f
= flags
[j
]) != 0)
833 } else if (n
> 0 && (ap
->state
& SC_TOSS
) == 0) {
834 /* stuff the chars in the skb */
837 skb
= dev_alloc_skb(ap
->mru
+ PPP_HDRLEN
+ 2);
840 /* Try to get the payload 4-byte aligned */
841 if (buf
[0] != PPP_ALLSTATIONS
)
842 skb_reserve(skb
, 2 + (buf
[0] & 1));
845 if (n
> skb_tailroom(skb
)) {
846 /* packet overflowed MRU */
849 sp
= skb_put(skb
, n
);
851 if (ap
->state
& SC_ESCAPE
) {
853 ap
->state
&= ~SC_ESCAPE
;
863 process_input_packet(ap
);
864 } else if (c
== PPP_ESCAPE
) {
865 ap
->state
|= SC_ESCAPE
;
867 /* otherwise it's a char in the recv ACCM */
878 printk(KERN_ERR
"PPPasync: no memory (input pkt)\n");
883 * We look at LCP frames going past so that we can notice
884 * and react to the LCP configure-ack from the peer.
885 * In the situation where the peer has been sent a configure-ack
886 * already, LCP is up once it has sent its configure-ack
887 * so the immediately following packet can be sent with the
888 * configured LCP options. This allows us to process the following
889 * packet correctly without pppd needing to respond quickly.
891 * We only respond to the received configure-ack if we have just
892 * sent a configure-request, and the configure-ack contains the
893 * same data (this is checked using a 16-bit crc of the data).
895 #define CONFREQ 1 /* LCP code field values */
897 #define LCP_MRU 1 /* LCP option numbers */
898 #define LCP_ASYNCMAP 2
900 static void async_lcp_peek(struct asyncppp
*ap
, unsigned char *data
,
901 int len
, int inbound
)
903 int dlen
, fcs
, i
, code
;
906 data
+= 2; /* skip protocol bytes */
908 if (len
< 4) /* 4 = code, ID, length */
911 if (code
!= CONFACK
&& code
!= CONFREQ
)
913 dlen
= (data
[2] << 8) + data
[3];
915 return; /* packet got truncated or length is bogus */
917 if (code
== (inbound
? CONFACK
: CONFREQ
)) {
919 * sent confreq or received confack:
920 * calculate the crc of the data from the ID field on.
923 for (i
= 1; i
< dlen
; ++i
)
924 fcs
= PPP_FCS(fcs
, data
[i
]);
927 /* outbound confreq - remember the crc for later */
932 /* received confack, check the crc */
938 return; /* not interested in received confreq */
940 /* process the options in the confack */
943 /* data[0] is code, data[1] is length */
944 while (dlen
>= 2 && dlen
>= data
[1]) {
947 val
= (data
[2] << 8) + data
[3];
954 val
= (data
[2] << 24) + (data
[3] << 16)
955 + (data
[4] << 8) + data
[5];
967 void __exit
ppp_async_cleanup(void)
969 if (tty_register_ldisc(N_PPP
, NULL
) != 0)
970 printk(KERN_ERR
"failed to unregister PPP line discipline\n");
973 module_init(ppp_async_init
);
974 module_exit(ppp_async_cleanup
);