1 /* $ID: ppp_tty.c,v 1.4 1994/12/13 03:42:17 paulus Exp paulus $ */
4 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
7 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 * Carnegie Mellon University
48 * Pittsburgh, PA 15213
53 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
55 * Copyright (c) 1987 Regents of the University of California.
56 * All rights reserved.
58 * Redistribution and use in source and binary forms are permitted
59 * provided that the above copyright notice and this paragraph are
60 * duplicated in all such forms and that any documentation,
61 * advertising materials, and other materials related to such
62 * distribution and use acknowledge that the software was developed
63 * by the University of California, Berkeley. The name of the
64 * University may not be used to endorse or promote products derived
65 * from this software without specific prior written permission.
66 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
67 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
68 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
70 * Serial Line interface
73 * Center for Seismic Studies
74 * 1300 N 17th Street, Suite 1450
75 * Arlington, Virginia 22209
80 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
81 * Converted to 4.3BSD Beta by Chris Torek.
82 * Other changes made at Berkeley, based in part on code by Kirk Smith.
84 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
85 * Added VJ tcp header compression; more unified ioctls
87 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
88 * Cleaned up a lot of the mbuf-related code to fix bugs that
89 * caused system crashes and packet corruption. Changed pppstart
90 * so that it doesn't just give up with a collision if the whole
91 * packet doesn't fit in the output ring buffer.
93 * Added priority queueing for interactive IP packets, following
94 * the model of if_sl.c, plus hooks for bpf.
95 * Paul Mackerras (paulus@cs.anu.edu.au).
97 * Rewritten for NextStep's funky kernel functions, I/O threads,
98 * and netbufs (instead of real mbufs). Also, ifnets don't install
99 * into the kernel under NS as they do under BSD. We have tried to
100 * make the code remain as similar to the NetBSD version without
101 * incurring too much hassle. This code is the merge of
102 * Philip Prindeville's <philipp@res.enst.fr>/Pete French's <pete@ohm.york.ac.uk>
103 * and Stephen Perkins' <perkins@cps.msu.edu> independent ports.
107 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
108 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:59 cgd Exp */
110 /* #include "ppp.h" */
114 #define KERNEL_FEATURES 1
119 #include <kernserv/lock.h>
121 #include <kern/lock.h>
122 #endif /* NS_TARGET */
123 #endif /* NS_TARGET */
125 #include <sys/param.h>
127 typedef simple_lock_data_t lock_data_t
; /* XXX */
128 #endif /* NS_TARGET */
129 #include <sys/proc.h>
130 #include <sys/user.h>
132 #include <sys/socket.h>
133 #include <sys/ioctl.h>
134 #include <sys/file.h>
136 #include <sys/conf.h>
139 #include <sys/errno.h>
140 #if !(NS_TARGET >= 40)
141 /* XXX what happened to this header file? */
142 #include <machine/param.h>
145 #include <kernserv/prototypes.h>
146 /* NeXT broke spl.h in 3.2/m68k. Thanks EPS! */
151 #include <driverkit/generalFuncs.h>
152 #import <kernserv/machine/spl.h>
155 #include <kernserv/kern_server_types.h>
158 #include <net/route.h>
161 #include <netinet/in.h>
162 #include <netinet/in_systm.h>
163 #include <netinet/ip.h>
166 #include <net/ppp_defs.h>
168 #include <net/vjcompress.h>
170 #include <net/if_ppp.h>
171 #include "if_pppvar.h"
175 int pppopen
__P((dev_t dev
, struct tty
*tp
));
176 void pppclose
__P((struct tty
*tp
));
177 int pppread
__P((struct tty
*tp
, struct uio
*uio
));
178 int pppwrite
__P((struct tty
*tp
, struct uio
*uio
));
179 int ppptioctl
__P((struct tty
*tp
, int cmd
, void *data
, int flag
));
180 void pppinput
__P((int c
, struct tty
*tp
));
181 void pppstart
__P((struct tty
*tp
));
184 * Must return an actual netbuf_t since other protocols
185 * use this to get our buffers.
187 netbuf_t pppgetbuf
__P((netif_t
));
190 * Must accept an actual netbuf_t since others use this
191 * Procedure to access our output routine.
193 int pppoutput
__P((netif_t ifp
, netbuf_t m
, void *arg
));
195 static u_int16_t pppfcs
__P((u_int16_t fcs
, u_char
*cp
, int len
));
196 static void pppasyncstart
__P((struct ppp_softc
*));
197 static void pppasyncctlp
__P((struct ppp_softc
*));
198 static void pppasyncrelinq
__P((struct ppp_softc
*));
199 static int ppp_timeout
__P((void *));
200 void pppgetm
__P((struct ppp_softc
*sc
));
201 static void pppdumpb
__P((u_char
*b
, int l
));
202 void ppplogchar
__P((struct ppp_softc
*, int));
204 extern kern_server_t instance
;
207 * Does c need to be escaped?
209 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
211 #define CCOUNT(q) ((q)->c_cc)
213 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
215 #include "linedisc.h"
218 extern int ttymodem(struct tty
*, int);
219 extern int ttselect(struct tty
*tp
, int rw
);
223 pppgetinbuf(netif_t ifp
)
225 register struct ppp_softc
*sc
= &ppp_softc
[if_unit(ifp
)];
227 int len
= MAX(sc
->sc_mru
, PPP_MTU
) + sizeof (struct ifnet
*) +
231 PPP_HDRLEN
+ PPP_FCSLEN
;
236 NB_SHRINK_TOP(nb
, VJ_HDRLEN
+ PPP_HDRLEN
);
238 NB_SHRINK_TOP(nb
, PPP_HDRLEN
);
246 * I was a bit worried about reentrancy here. +++SJP
250 pppfillfreeq(void *arg
)
252 struct ppp_softc
*sc
= (struct ppp_softc
*)arg
;
254 volatile static int in
= 0;
260 while(!nbq_high(&sc
->sc_freeq
)) {
261 nb
= pppgetinbuf(sc
->sc_if
);
263 nbq_enqueue(&sc
->sc_freeq
, nb
);
270 * Line specific open routine for async tty devices.
271 * Attach the given tty to the first available ppp unit.
277 register struct tty
*tp
;
279 struct proc
*p
= curproc
; /* XXX */
280 register struct ppp_softc
*sc
;
286 if (tp
->t_line
== PPPDISC
) {
287 sc
= (struct ppp_softc
*) tp
->t_sc
;
288 if (sc
!= NULL
&& sc
->sc_devp
== (void *) tp
)
292 if ((sc
= pppalloc(p
->p_pid
)) == NULL
)
296 (*sc
->sc_relinq
)(sc
); /* get previous owner to relinquish the unit */
298 pppfillfreeq((void *) sc
); /* fill the free queue - we may block */
303 bzero(sc
->sc_asyncmap
, sizeof(sc
->sc_asyncmap
));
304 sc
->sc_asyncmap
[0] = 0xffffffff;
305 sc
->sc_asyncmap
[3] = 0x60000000; /* 0x7D and 0x7E */
306 sc
->sc_rasyncmap
= 0;
307 sc
->sc_devp
= (void *) tp
;
308 sc
->sc_start
= pppasyncstart
;
309 sc
->sc_ctlp
= pppasyncctlp
;
310 sc
->sc_relinq
= pppasyncrelinq
;
313 if_flags_set(sc
->sc_if
, if_flags(sc
->sc_if
) | IFF_RUNNING
);
315 tp
->t_sc
= (caddr_t
) sc
;
316 ttyflush(tp
, FREAD
| FWRITE
);
323 * Line specific close routine.
324 * Detach the tty from the ppp unit.
325 * Mimics part of ttyclose().
331 register struct ppp_softc
*sc
;
335 s
= splimp(); /* paranoid; splnet probably ok */
337 sc
= (struct ppp_softc
*) tp
->t_sc
;
340 if (tp
== (struct tty
*) sc
->sc_devp
) {
350 * Relinquish the interface unit to another device.
354 struct ppp_softc
*sc
;
360 NB_FREE(sc
->sc_outm
);
367 if (sc
->sc_flags
& SC_TIMEOUT
) {
368 ns_untimeout(ppp_timeout
, (void *) sc
);
369 sc
->sc_flags
&= ~SC_TIMEOUT
;
375 * Line specific (tty) read routine.
379 register struct tty
*tp
;
382 register struct ppp_softc
*sc
= (struct ppp_softc
*)tp
->t_sc
;
386 struct nty
*np
= ttynty(tp
);
389 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (np
->t_pflags
& TP_CLOCAL
) == 0)
390 return 0; /* end of file */
394 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_flags
& CLOCAL
) == 0)
395 return 0; /* end of file */
397 #endif /* NEW_CLOCAL */
399 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
402 while (nbq_empty(&sc
->sc_inq
) && tp
->t_line
== PPPDISC
) {
403 if (tp
->t_state
& (TS_ASYNC
| TS_NBIO
)) {
405 return (EWOULDBLOCK
);
407 sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
409 if (tp
->t_line
!= PPPDISC
) {
414 /* Pull place-holder byte out of canonical queue */
417 /* Get the packet from the input queue */
418 m
= nbq_dequeue(&sc
->sc_inq
);
421 if (sc
->sc_flags
& SC_DEBUG
)
422 IOLogDbg("Read didn't get a buffer at %s %d\n", __FILE__
, __LINE__
);
425 error
= uiomove(NB_MAP(m
), NB_SIZE(m
), UIO_READ
, uio
);
431 * Line specific (tty) write routine.
435 register struct tty
*tp
;
438 register struct ppp_softc
*sc
= (struct ppp_softc
*)tp
->t_sc
;
442 struct nty
*np
= ttynty(tp
);
446 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (np
->t_pflags
& TP_CLOCAL
) == 0)
447 return 0; /* wrote 0 bytes */
451 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_flags
& CLOCAL
) == 0)
452 return 0; /* wrote 0 bytes */
454 #endif /* NEW_CLOCAL */
456 if (tp
->t_line
!= PPPDISC
)
458 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
460 if (uio
->uio_resid
> if_mtu(sc
->sc_if
) + PPP_HDRLEN
||
461 uio
->uio_resid
< PPP_HDRLEN
)
463 m
= nb_TO_NB(pppgetbuf(sc
->sc_if
));
466 if (sc
->sc_flags
& SC_DEBUG
)
467 IOLogDbg("No buffers available for user level write()\n");
470 NB_GROW_TOP(m
, PPP_HDRLEN
);
471 len
= uio
->uio_resid
;
472 if (error
= uiomove(NB_MAP(m
), NB_SIZE(m
), UIO_WRITE
, uio
)) {
476 NB_SHRINK_BOT(m
, NB_SIZE(m
) - len
);
477 dst
.sa_family
= AF_UNSPEC
;
478 bcopy(mtod(m
, u_char
*), dst
.sa_data
, PPP_HDRLEN
);
480 NB_SHRINK_TOP(m
, PPP_HDRLEN
);
481 return (pppoutput(sc
->sc_if
, NB_TO_nb(m
), &dst
));
485 * Line specific (tty) ioctl routine.
486 * This discipline requires that tty device drivers call
487 * the line specific l_ioctl routine from their ioctl routines.
491 ppptioctl(tp
, cmd
, data
, flag
)
496 struct ppp_softc
*sc
= (struct ppp_softc
*) tp
->t_sc
;
499 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
504 case PPPIOCSASYNCMAP
:
508 sc
->sc_asyncmap
[0] = *(u_int
*)data
;
511 case PPPIOCGASYNCMAP
:
512 *(u_int
*)data
= sc
->sc_asyncmap
[0];
515 case PPPIOCSRASYNCMAP
:
518 sc
->sc_rasyncmap
= *(u_int
*)data
;
521 case PPPIOCGRASYNCMAP
:
522 *(u_int
*)data
= sc
->sc_rasyncmap
;
525 case PPPIOCSXASYNCMAP
:
529 bcopy(data
, sc
->sc_asyncmap
, sizeof(sc
->sc_asyncmap
));
530 sc
->sc_asyncmap
[1] = 0; /* mustn't escape 0x20 - 0x3f */
531 sc
->sc_asyncmap
[2] &= ~0x40000000; /* mustn't escape 0x5e */
532 sc
->sc_asyncmap
[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
536 case PPPIOCGXASYNCMAP
:
537 bcopy(sc
->sc_asyncmap
, data
, sizeof(sc
->sc_asyncmap
));
541 error
= pppioctl(sc
, cmd
, data
, flag
);
542 if (error
== 0 && cmd
== PPPIOCSMRU
)
547 if (! error
&& (cmd
& IOC_OUT
)) {
548 struct uthread
*_u
= uthread_from_thread(current_thread());
550 /* third arg is destination in ioctl() call... */
551 copyout(data
, (caddr_t
) _u
->uu_arg
[2], (cmd
>> 16) & IOCPARM_MASK
);
559 * FCS lookup table as calculated by genfcstab.
561 static const u_int16_t fcstab
[256] = {
562 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
563 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
564 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
565 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
566 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
567 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
568 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
569 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
570 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
571 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
572 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
573 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
574 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
575 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
576 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
577 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
578 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
579 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
580 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
581 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
582 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
583 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
584 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
585 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
586 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
587 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
588 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
589 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
590 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
591 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
592 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
593 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
597 * Calculate a new FCS given the current FCS and the new data.
601 register u_int16_t fcs
;
606 fcs
= PPP_FCS(fcs
, *cp
++);
611 * This gets called from pppoutput when a new packet is
616 register struct ppp_softc
*sc
;
618 register struct tty
*tp
= (struct tty
*) sc
->sc_devp
;
627 * This gets called when a received packet is placed on
632 struct ppp_softc
*sc
;
636 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
637 tp
= (struct tty
*) sc
->sc_devp
;
638 putc(0, &tp
->t_canq
);
643 * Start output on async tty interface. Get another datagram
644 * to send from the interface queue and start sending it.
648 register struct tty
*tp
;
650 register struct ppp_softc
*sc
= (struct ppp_softc
*) tp
->t_sc
;
653 register u_char
*start
, *stop
, *cp
;
654 int n
, ndone
, done
, idle
;
655 struct nty
*np
= ttynty(tp
);
659 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (np
->t_pflags
& TP_CLOCAL
) == 0
663 if ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_flags
& CLOCAL
) == 0
665 #endif /* NEW_CLOCAL */
667 || sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
) {
668 if (tp
->t_oproc
!= NULL
)
675 while (CCOUNT(&tp
->t_outq
) == 0) {
677 while (CCOUNT(&tp
->t_outq
) < PPP_HIWAT
) {
680 * See if we have an existing packet partly sent.
681 * If not, get a new packet and start sending it.
686 * Get another packet to be sent.
695 * The extra PPP_FLAG will start up a new packet, and thus
696 * will flush any accumulated garbage. We do this whenever
697 * the line may have been idle for some time.
699 if (CCOUNT(&tp
->t_outq
) == 0) {
701 (void) putc(PPP_FLAG
, &tp
->t_outq
);
704 /* Calculate the FCS for the first netbuf's worth. */
705 sc
->sc_outfcs
= pppfcs(PPP_INITFCS
, mtod(m
, u_char
*), NB_SIZE(m
));
706 sc
->sc_outfcs
^= 0xffff;
708 cp
= mtod(m
, u_char
*) + NB_SIZE(m
);
709 NB_GROW_BOT(m
, PPP_FCSLEN
);
710 *cp
++ = sc
->sc_outfcs
& 0xFF;
711 *cp
++ = (sc
->sc_outfcs
>> 8) & 0xFF;
714 start
= mtod(m
, u_char
*);
719 * Find out how many bytes in the string we can
720 * handle without doing something special.
722 for (cp
= start
; cp
< stop
; cp
++)
730 * b_to_q returns the number of characters
733 * NetBSD (0.9 or later), 4.3-Reno or similar.
735 ndone
= n
- b_to_q(start
, n
, &tp
->t_outq
);
738 sc
->sc_bytessent
+= ndone
;
741 break; /* packet doesn't fit */
746 * If there are characters left in the netbuf,
747 * the first one must be special..
748 * Put it out in a different form.
751 if (putc(PPP_ESCAPE
, &tp
->t_outq
))
753 if (putc(*start
^ PPP_TRANS
, &tp
->t_outq
)) {
754 (void) unputc(&tp
->t_outq
);
757 sc
->sc_bytessent
+= 2;
763 * If we didn't empty this netbuf, remember where we're up to.
768 /* remember where we got to */
769 NB_SHRINK_TOP(m
, start
- mtod(m
, u_char
*));
770 break; /* can't do any more at the moment */
774 * Output trailing PPP flag and finish packet.
775 * We make the length zero in case the flag
776 * cannot be output immediately.
778 NB_SHRINK_TOP(m
, NB_SIZE(m
));
779 if (putc(PPP_FLAG
, &tp
->t_outq
))
784 /* Finished with this netbuf; free it and move on. */
787 incr_cnt(sc
->sc_if
, if_opackets
);
793 * If there is stuff in the output queue, send it now.
794 * We are being called in lieu of ttstart and must do what it would.
796 if (tp
->t_oproc
!= NULL
)
800 * This timeout is needed for operation on a pseudo-tty,
801 * because the pty code doesn't call pppstart after it has
802 * drained the t_outq.
804 if (!idle
&& (sc
->sc_flags
& SC_TIMEOUT
) == 0) {
806 timeout(ppp_timeout
, (void *) sc
, 1);
808 ns_timeout(ppp_timeout
, (void *) sc
, 1 * (1000000000L / HZ
), CALLOUT_PRI_SOFTINT0
);
809 #endif /*NS_TARGET */
810 sc
->sc_flags
|= SC_TIMEOUT
;
817 * Timeout routine - try to start some more output.
823 struct ppp_softc
*sc
= (struct ppp_softc
*) x
;
824 struct tty
*tp
= (struct tty
*) sc
->sc_devp
;
828 sc
->sc_flags
&= ~SC_TIMEOUT
;
835 * Allocate enough netbuf to handle current MRU.
837 * Warning Will Robinson: pppgetm() can get called at interrupt-level!
841 register struct ppp_softc
*sc
;
847 * When the MRU is being changed, we could conceivably end up
848 * nuking a packet being received, but I doubt it, since the
849 * hand-shake is lock-step (ie. single packet).
851 if (sc
->sc_m
!= NULL
)
853 sc
->sc_m
= nbq_dequeue(&sc
->sc_freeq
);
858 * 4.3 says this is an unused function. However,
859 * it appears to be returning a NULL terminated string
860 * of several characters. My guess is that the serial
861 * driver is doing a little buffering so that we don't
862 * get burdend with interrupts.
864 * This function gets called when you use the NeXT
865 * supplied serial drivers. It does not get called
866 * with the MuX driver.
868 * In order to expedite the work done here, we
869 * handle most things here that don't require
870 * processing of a PPP_FLAG.
881 #ifndef OPTIMIZE_PPPREND
882 #warning PPPREND Not optimized!!!
883 while (n
--) pppinput((u_char
) *cp
++, tp
);
887 register struct ppp_softc
*sc
= (struct ppp_softc
*)tp
->t_sc
;
890 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
892 printf("Warning, bad softc structure at %s %d\n", __FILE__
, __LINE__
);
897 * We can handle FLUSHs, ESCAPES, and non PPP_FLAG characters
902 if (sc
->sc_flags
& SC_FLUSH
)
906 if (*(cp
++) == PPP_FLAG
)
908 pppinput(PPP_FLAG
, tp
);
912 else if (sc
->sc_flags
& SC_LOG_FLUSH
)
917 else if (sc
->sc_ilen
> 3 &&
918 (NB_SIZE(sc
->sc_m
) - sc
->sc_ilen
) > n
&&
920 *cp
!= PPP_ESCAPE
) /* Dont really handle escapes properly...should */
922 unsigned char* cp1
= cp
;
923 if (sc
->sc_flags
& SC_ESCAPED
)
925 sc
->sc_flags
&= ~SC_ESCAPED
;
931 sc
->sc_fcs
= PPP_FCS(sc
->sc_fcs
, *(cp
++));
932 if (sc
->sc_flags
& SC_LOG_RAWIN
)
935 } while(--n
&& *cp
!= PPP_FLAG
&& *cp
!= PPP_ESCAPE
);
938 bcopy(cp1
, sc
->sc_mp
, (cp
-cp1
));
940 sc
->sc_bytesrcvd
+= (cp
- cp1
);
941 sc
->sc_ilen
+= (cp
-cp1
);
942 sc
->sc_mp
+= (cp
-cp1
);
948 pppinput(*(cp
++), tp
);
952 #endif /* OPTIMIZE_PPPREND */
956 * tty interface receiver interrupt.
958 static const unsigned paritytab
[8] = {
959 0x96696996, 0x69969669, 0x69969669, 0x96696996,
960 0x69969669, 0x96696996, 0x96696996, 0x69969669
966 register struct tty
*tp
;
968 register struct ppp_softc
*sc
;
972 sc
= (struct ppp_softc
*) tp
->t_sc
;
973 if (sc
== NULL
|| tp
!= (struct tty
*) sc
->sc_devp
)
980 /* framing error or overrun on this char - abort packet */
981 IOLogDbg("ppp%d: bad char 0x%x\n", if_unit(sc
->sc_if
), c
);
988 sc
->sc_flags
|= SC_RCV_B7_1
;
990 sc
->sc_flags
|= SC_RCV_B7_0
;
991 if (paritytab
[c
>> 5] & (1 << (c
& 0x1F)))
992 sc
->sc_flags
|= SC_RCV_ODDP
;
994 sc
->sc_flags
|= SC_RCV_EVNP
;
996 if (sc
->sc_flags
& SC_LOG_RAWIN
)
1001 if (sc
->sc_ilen
== 0)
1007 if (sc
->sc_rawin_count
> 0)
1012 * Each Control Escape octet is also
1013 * removed, and the following octet is exclusive-or'd with hexadecimal
1014 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1016 * So, if SC_ESCAPED is set, then we've seen the packet
1017 * abort sequence "}~".
1019 if ((sc
->sc_flags
& (SC_FLUSH
| SC_ESCAPED
)) ||
1020 ((ilen
> 0) && (sc
->sc_fcs
!= PPP_GOODFCS
)))
1022 sc
->sc_flags
|= SC_PKTLOST
; /* note the dropped packet */
1023 if ((sc
->sc_flags
& (SC_FLUSH
| SC_ESCAPED
)) == 0)
1025 IOLog("ppp%d: bad fcs 0x%04x\n", if_unit(sc
->sc_if
), sc
->sc_fcs
);
1026 incr_cnt(sc
->sc_if
, if_ierrors
);
1030 IOLog("ppp%d: bad packet flushed...\n", if_unit(sc
->sc_if
));
1031 sc
->sc_flags
&= ~(SC_FLUSH
| SC_ESCAPED
);
1036 if (ilen
< (PPP_HDRLEN
+ PPP_FCSLEN
))
1040 IOLogDbg("ppp%d: too short (%d)\n", if_unit(sc
->sc_if
), ilen
);
1041 incr_cnt(sc
->sc_if
, if_ierrors
);
1042 sc
->sc_flags
|= SC_PKTLOST
;
1048 * Remove FCS trailer. Set packet length...
1051 NB_SHRINK_BOT(sc
->sc_m
, NB_SIZE(sc
->sc_m
) - ilen
);
1053 /* excise this netbuf */
1057 ppppktin(sc
, m
, sc
->sc_flags
& SC_PKTLOST
);
1058 sc
->sc_flags
&= ~SC_PKTLOST
;
1064 if (sc
->sc_flags
& SC_FLUSH
) {
1065 if (sc
->sc_flags
& SC_LOG_FLUSH
)
1072 * On reception, prior to FCS computation, each octet with value less
1073 * than hexadecimal 0x20 is checked. If it is flagged in the receiving
1074 * ACCM, it is simply removed (it may have been inserted by intervening
1075 * data communications equipment). Each Control Escape octet is also
1076 * removed, and the following octet is exclusive-or'd with hexadecimal
1077 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1079 if (c
< 0x20 && (sc
->sc_rasyncmap
& (1 << c
))) {
1083 if (sc
->sc_flags
& SC_ESCAPED
) {
1084 sc
->sc_flags
&= ~SC_ESCAPED
;
1086 } else if (c
== PPP_ESCAPE
) {
1087 sc
->sc_flags
|= SC_ESCAPED
;
1092 * Initialize buffer on first octet received.
1093 * First octet could be address or protocol (when compressing
1095 * Second octet is control.
1096 * Third octet is first or second (when compressing protocol)
1097 * octet of protocol.
1098 * Fourth octet is second octet of protocol.
1100 if (sc
->sc_ilen
== 0) {
1102 /* reset the input netbuf */
1103 if (sc
->sc_m
== NULL
) {
1105 if (sc
->sc_m
== NULL
) {
1107 * We schedule a call here as pppindrain will
1108 * not get scheduled and we need the free buffers
1110 IOLog("ppp%d: no input netbufs!\n", if_unit(sc
->sc_if
));
1111 (void)pppsched(pppfillfreeq
, sc
);
1116 sc
->sc_mp
= mtod(m
, char *);
1117 sc
->sc_fcs
= PPP_INITFCS
;
1119 if (c
!= PPP_ALLSTATIONS
) {
1120 if (sc
->sc_flags
& SC_REJ_COMP_AC
) {
1121 IOLogDbg("ppp%d: garbage received: 0x%02x (need 0x%02x)\n",
1122 if_unit(sc
->sc_if
), c
, PPP_ALLSTATIONS
);
1125 *sc
->sc_mp
++ = PPP_ALLSTATIONS
;
1126 *sc
->sc_mp
++ = PPP_UI
;
1132 if (sc
->sc_ilen
== 1 && c
!= PPP_UI
) {
1133 IOLogDbg("ppp%d: missing UI (0x%02x), got 0x%02x\n",
1134 if_unit(sc
->sc_if
), PPP_UI
, c
);
1138 if (sc
->sc_ilen
== 2 && (c
& 1) == 1) {
1139 /* a compressed protocol */
1144 if (sc
->sc_ilen
== 3 && (c
& 1) == 0) {
1145 IOLogDbg("ppp%d: bad protocol %x\n", if_unit(sc
->sc_if
),
1146 (sc
->sc_mp
[-1] << 8) + c
);
1150 /* packet beyond configured mru? */
1151 if (++sc
->sc_ilen
> sc
->sc_mru
+ PPP_HDRLEN
+ PPP_FCSLEN
) {
1152 IOLogDbg("ppp%d: packet too big (%d bytes)\n", if_unit(sc
->sc_if
),
1157 /* ilen was incremented above... */
1159 sc
->sc_fcs
= PPP_FCS(sc
->sc_fcs
, c
);
1163 if (!(sc
->sc_flags
& SC_FLUSH
)) {
1164 incr_cnt(sc
->sc_if
, if_ierrors
);
1165 sc
->sc_flags
|= SC_FLUSH
;
1166 if (sc
->sc_flags
& SC_LOG_FLUSH
)
1173 install_ppp_ld(void)
1175 return tty_ld_install(PPPDISC
, NORMAL_LDISC
, pppopen
,
1176 pppclose
, pppread
, pppwrite
, ppptioctl
,
1177 pppinput
, ppprend
, pppstart
, ttymodem
,
1181 #define MAX_DUMP_BYTES 128
1185 struct ppp_softc
*sc
;
1189 sc
->sc_rawin
[sc
->sc_rawin_count
++] = c
;
1190 if (sc
->sc_rawin_count
>= sizeof(sc
->sc_rawin
)
1191 || c
< 0 && sc
->sc_rawin_count
> 0) {
1192 IOLog("ppp%d input:\n", if_unit(sc
->sc_if
));
1193 pppdumpb(sc
->sc_rawin
, sc
->sc_rawin_count
);
1194 sc
->sc_rawin_count
= 0;
1203 char buf
[3*MAX_DUMP_BYTES
+4];
1205 static char digits
[] = "0123456789abcdef";
1208 if (bp
>= buf
+ sizeof(buf
) - 3) {
1212 *bp
++ = digits
[*b
>> 4]; /* convert byte to ascii hex */
1213 *bp
++ = digits
[*b
++ & 0xf];
1220 #endif /* NUM_PPP > 0 */