]> git.ozlabs.org Git - ppp.git/blob - NeXT/ppp_tty.c
Add extra baud rates >= 1Mbaud.
[ppp.git] / NeXT / ppp_tty.c
1 /*      $ID: ppp_tty.c,v 1.4 1994/12/13 03:42:17 paulus Exp paulus $    */
2
3 /*
4  * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5  *             tty devices.
6  *
7  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
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
19  *    distribution.
20  *
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
27  *      5000 Forbes Avenue
28  *      Pittsburgh, PA  15213-3890
29  *      (412) 268-4387, fax: (412) 268-7395
30  *      tech-transfer@andrew.cmu.edu
31  *
32  * 4. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by Computing Services
35  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36  *
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.
44  *
45  * Drew D. Perkins
46  * Carnegie Mellon University
47  * 4910 Forbes Ave.
48  * Pittsburgh, PA 15213
49  * (412) 268-8576
50  * ddp@andrew.cmu.edu
51  *
52  * Based on:
53  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
54  *
55  * Copyright (c) 1987 Regents of the University of California.
56  * All rights reserved.
57  *
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.
69  *
70  * Serial Line interface
71  *
72  * Rick Adams
73  * Center for Seismic Studies
74  * 1300 N 17th Street, Suite 1450
75  * Arlington, Virginia 22209
76  * (703)276-7900
77  * rick@seismo.ARPA
78  * seismo!rick
79  *
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.
83  *
84  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
85  * Added VJ tcp header compression; more unified ioctls
86  *
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.
92  *
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).
96  *
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.
104  *
105  */
106
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 */
109
110 /* #include "ppp.h" */
111 #if NUM_PPP > 0
112
113 #define KERNEL 1
114 #define KERNEL_FEATURES 1
115 #define INET 1
116
117 #if NS_TARGET >= 40
118 #if NS_TARGET >= 41
119 #include <kernserv/lock.h>
120 #else
121 #include <kern/lock.h>
122 #endif /* NS_TARGET */
123 #endif /* NS_TARGET */
124
125 #include <sys/param.h>
126 #if NS_TARGET >= 41
127 typedef simple_lock_data_t lock_data_t;         /* XXX */
128 #endif /* NS_TARGET */
129 #include <sys/proc.h>
130 #include <sys/user.h>
131 #include "netbuf.h"
132 #include <sys/socket.h>
133 #include <sys/ioctl.h>
134 #include <sys/file.h>
135 #include <sys/tty.h>
136 #include <sys/conf.h>
137 #include <sys/dk.h>
138 #include <sys/uio.h>
139 #include <sys/errno.h>
140 #if !(NS_TARGET >= 40)
141 /*  XXX what happened to this header file? */
142 #include <machine/param.h>
143 #endif
144
145 #include <kernserv/prototypes.h>
146 /* NeXT broke spl.h in 3.2/m68k. Thanks EPS! */
147
148 #if defined(m68k)
149 #import "spl.h"
150 #else
151 #include <driverkit/generalFuncs.h>
152 #import <kernserv/machine/spl.h>
153 #endif
154
155 #include <kernserv/kern_server_types.h>
156
157 #include <net/if.h>
158 #include <net/route.h>
159
160 #ifdef VJC
161 #include <netinet/in.h>
162 #include <netinet/in_systm.h>
163 #include <netinet/ip.h>
164 #endif
165
166 #include <net/ppp_defs.h>
167 #ifdef VJC
168 #include <net/vjcompress.h>
169 #endif
170 #include <net/if_ppp.h>
171 #include "if_pppvar.h"
172
173 #include "inlines.h"
174
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));
182
183 /*
184  * Must return an actual netbuf_t since other protocols
185  * use this to get our buffers.
186  */
187 netbuf_t        pppgetbuf __P((netif_t));
188
189 /*
190  * Must accept an actual netbuf_t since others use this
191  * Procedure to access our output routine.
192  */
193 int             pppoutput __P((netif_t ifp, netbuf_t m, void *arg));
194
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));
203
204 extern kern_server_t instance;
205
206 /*
207  * Does c need to be escaped?
208  */
209 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
210
211 #define CCOUNT(q)       ((q)->c_cc)
212
213 #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
214
215 #include "linedisc.h"  
216
217
218 extern int ttymodem(struct tty*, int);
219 extern int ttselect(struct tty *tp, int rw);
220
221
222 static NETBUF_T
223 pppgetinbuf(netif_t ifp)
224 {
225     register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)];
226     NETBUF_T nb;
227     int len = MAX(sc->sc_mru, PPP_MTU) + sizeof (struct ifnet *) +
228 #ifdef VJC
229               VJ_HDRLEN +
230 #endif
231               PPP_HDRLEN + PPP_FCSLEN;
232     nb =  NB_ALLOC(len);
233     if (nb != NULL)
234       {
235 #ifdef VJC
236         NB_SHRINK_TOP(nb, VJ_HDRLEN + PPP_HDRLEN);
237 #else
238         NB_SHRINK_TOP(nb, PPP_HDRLEN);
239 #endif
240       }
241
242     return nb;
243 }
244
245 /*
246  * I was a bit worried about reentrancy here.  +++SJP
247  */
248
249 void
250 pppfillfreeq(void *arg)
251 {
252     struct ppp_softc *sc = (struct ppp_softc *)arg;
253     NETBUF_T nb;
254     volatile static int in = 0;
255
256     if (in)
257       return;
258     in = 1;
259
260     while(!nbq_high(&sc->sc_freeq)) {
261         nb = pppgetinbuf(sc->sc_if);
262         if (! nb) break;
263         nbq_enqueue(&sc->sc_freeq, nb);
264     }
265
266     in = 0;
267 }
268
269 /*
270  * Line specific open routine for async tty devices.
271  * Attach the given tty to the first available ppp unit.
272  */
273 /* ARGSUSED */
274 int
275 pppopen(dev, tp)
276     dev_t dev;
277     register struct tty *tp;
278 {
279     struct proc *p = curproc;           /* XXX */
280     register struct ppp_softc *sc;
281     int s;
282
283     if (! suser())
284         return EPERM;
285
286     if (tp->t_line == PPPDISC) {
287         sc = (struct ppp_softc *) tp->t_sc;
288         if (sc != NULL && sc->sc_devp == (void *) tp)
289             return (0);
290     }
291
292     if ((sc = pppalloc(p->p_pid)) == NULL)
293         return ENXIO;
294
295     if (sc->sc_relinq)
296         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
297
298     pppfillfreeq((void *) sc);   /* fill the free queue - we may block */
299
300     s = splimp();
301     sc->sc_ilen = 0;
302     sc->sc_m = NULL;
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;
311     sc->sc_outm = NULL;
312     pppgetm(sc);
313     if_flags_set(sc->sc_if, if_flags(sc->sc_if) | IFF_RUNNING);
314
315     tp->t_sc = (caddr_t) sc;
316     ttyflush(tp, FREAD | FWRITE);
317     splx(s);
318
319     return (0);
320 }
321
322 /*
323  * Line specific close routine.
324  * Detach the tty from the ppp unit.
325  * Mimics part of ttyclose().
326  */
327 void
328 pppclose(tp)
329     struct tty *tp;
330 {
331     register struct ppp_softc *sc;
332     int s;
333
334     ttywflush(tp);
335     s = splimp();               /* paranoid; splnet probably ok */
336     tp->t_line = 0;
337     sc = (struct ppp_softc *) tp->t_sc;
338     if (sc != NULL) {
339         tp->t_sc = NULL;
340         if (tp == (struct tty *) sc->sc_devp) {
341             pppasyncrelinq(sc);
342             pppdealloc(sc);
343         }
344     }
345     splx(s);
346     return;
347 }
348
349 /*
350  * Relinquish the interface unit to another device.
351  */
352 static void
353 pppasyncrelinq(sc)
354     struct ppp_softc *sc;
355 {
356     int s;
357
358     s = splimp();
359     if (sc->sc_outm) {
360         NB_FREE(sc->sc_outm);
361         sc->sc_outm = NULL;
362     }
363     if (sc->sc_m) {
364         NB_FREE(sc->sc_m);
365         sc->sc_m = NULL;
366     }
367     if (sc->sc_flags & SC_TIMEOUT) {
368         ns_untimeout(ppp_timeout, (void *) sc);
369         sc->sc_flags &= ~SC_TIMEOUT;
370     }
371     splx(s);
372 }
373
374 /*
375  * Line specific (tty) read routine.
376  */
377 int
378 pppread(tp, uio)
379     register struct tty *tp;
380     struct uio *uio;
381 {
382     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
383     NETBUF_T m;
384     register int s;
385     int error = 0;
386     struct nty *np = ttynty(tp);
387
388 #ifdef NEW_CLOCAL
389     if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
390         return 0;               /* end of file */
391
392 #else
393
394     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
395         return 0;               /* end of file */
396
397 #endif /* NEW_CLOCAL */
398
399     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
400         return 0;
401     s = splimp();
402     while (nbq_empty(&sc->sc_inq) && tp->t_line == PPPDISC) {
403         if (tp->t_state & (TS_ASYNC | TS_NBIO)) {
404             splx(s);
405             return (EWOULDBLOCK);
406         }
407         sleep((caddr_t)&tp->t_rawq, TTIPRI);
408     }
409     if (tp->t_line != PPPDISC) {
410         splx(s);
411         return (-1);
412     }
413
414     /* Pull place-holder byte out of canonical queue */
415     getc(&tp->t_canq);
416
417     /* Get the packet from the input queue */
418     m = nbq_dequeue(&sc->sc_inq);
419     splx(s);
420     if (nbuf == NULL){
421       if (sc->sc_flags & SC_DEBUG)
422         IOLogDbg("Read didn't get a buffer at %s %d\n", __FILE__, __LINE__);
423       return -1;
424     }
425     error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_READ, uio);
426     NB_FREE(m);
427     return (error);
428 }
429
430 /*
431  * Line specific (tty) write routine.
432  */
433 int
434 pppwrite(tp, uio)
435     register struct tty *tp;
436     struct uio *uio;
437 {
438     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
439     NETBUF_T m;
440     struct sockaddr dst;
441     int len, error;
442     struct nty *np = ttynty(tp);
443
444 #ifdef NEW_CLOCAL
445
446     if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
447         return 0;               /* wrote 0 bytes */
448
449 #else
450
451     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
452         return 0;               /* wrote 0 bytes */
453
454 #endif /* NEW_CLOCAL */
455
456     if (tp->t_line != PPPDISC)
457         return (EINVAL);
458     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
459         return EIO;
460     if (uio->uio_resid > if_mtu(sc->sc_if) + PPP_HDRLEN ||
461       uio->uio_resid < PPP_HDRLEN)
462         return (EMSGSIZE);
463     m = nb_TO_NB(pppgetbuf(sc->sc_if));
464
465     if (m == NULL){
466       if (sc->sc_flags & SC_DEBUG)
467         IOLogDbg("No buffers available for user level write()\n");
468       return(ENOBUFS);
469     }
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)) {
473         NB_FREE(m);
474         return error;
475     }
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);
479
480     NB_SHRINK_TOP(m, PPP_HDRLEN);
481     return (pppoutput(sc->sc_if, NB_TO_nb(m), &dst));
482 }
483
484 /*
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.
488  */
489 /* ARGSUSED */
490 int
491 ppptioctl(tp, cmd, data, flag)
492     struct tty *tp;
493     void *data;
494     int cmd, flag;
495 {
496     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
497     int error, s;
498
499     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
500         return -1;
501
502     error = 0;
503     switch (cmd) {
504     case PPPIOCSASYNCMAP:
505         if (! suser())
506             return EPERM;
507
508         sc->sc_asyncmap[0] = *(u_int *)data;
509         break;
510
511     case PPPIOCGASYNCMAP:
512         *(u_int *)data = sc->sc_asyncmap[0];
513         break;
514
515     case PPPIOCSRASYNCMAP:
516         if (! suser())
517             return EPERM;
518         sc->sc_rasyncmap = *(u_int *)data;
519         break;
520
521     case PPPIOCGRASYNCMAP:
522         *(u_int *)data = sc->sc_rasyncmap;
523         break;
524
525     case PPPIOCSXASYNCMAP:
526         if (! suser())
527             return EPERM;
528         s = spltty();
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 */
533         splx(s);
534         break;
535
536     case PPPIOCGXASYNCMAP:
537         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
538         break;
539
540     default:
541         error = pppioctl(sc, cmd, data, flag);
542         if (error == 0 && cmd == PPPIOCSMRU)
543             pppgetm(sc);
544     }
545
546 #ifdef  i386
547     if (! error && (cmd & IOC_OUT)) {
548         struct uthread *_u = uthread_from_thread(current_thread());
549
550         /* third arg is destination in ioctl() call... */
551         copyout(data, (caddr_t) _u->uu_arg[2], (cmd >> 16) & IOCPARM_MASK);
552     }
553 #endif
554
555     return error;
556 }
557
558 /*
559  * FCS lookup table as calculated by genfcstab.
560  */
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
594 };
595
596 /*
597  * Calculate a new FCS given the current FCS and the new data.
598  */
599 static u_int16_t
600 pppfcs(fcs, cp, len)
601     register u_int16_t fcs;
602     register u_char *cp;
603     register int len;
604 {
605     while (len--)
606         fcs = PPP_FCS(fcs, *cp++);
607     return (fcs);
608 }
609
610 /*
611  * This gets called from pppoutput when a new packet is
612  * put on a queue.
613  */
614 static void
615 pppasyncstart(sc)
616     register struct ppp_softc *sc;
617 {
618     register struct tty *tp = (struct tty *) sc->sc_devp;
619     int s;
620
621     s = splimp();
622     pppstart(tp);
623     splx(s);
624 }
625
626 /*
627  * This gets called when a received packet is placed on
628  * the inq.
629  */
630 static void
631 pppasyncctlp(sc)
632     struct ppp_softc *sc;
633 {
634     struct tty *tp;
635
636     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
637     tp = (struct tty *) sc->sc_devp;
638     putc(0, &tp->t_canq);
639     ttwakeup(tp);
640 }
641
642 /*
643  * Start output on async tty interface.  Get another datagram
644  * to send from the interface queue and start sending it.
645  */
646 void
647 pppstart(tp)
648     register struct tty *tp;
649 {
650     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
651     register NETBUF_T m;
652     register int len;
653     register u_char *start, *stop, *cp;
654     int n, ndone, done, idle;
655     struct nty *np = ttynty(tp);
656
657 #ifdef NEW_CLOCAL
658
659     if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0
660
661 #else
662
663     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0 
664
665 #endif /* NEW_CLOCAL */
666
667         || sc == NULL || tp != (struct tty *) sc->sc_devp) {
668         if (tp->t_oproc != NULL)
669             (*tp->t_oproc)(tp);
670         return;
671     }
672
673     idle = 0;
674 #ifdef  OLD_MUX
675     while (CCOUNT(&tp->t_outq) == 0) {
676 #else
677     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
678 #endif
679         /*
680          * See if we have an existing packet partly sent.
681          * If not, get a new packet and start sending it.
682          */
683         m = sc->sc_outm;
684         if (m == NULL) {
685             /*
686              * Get another packet to be sent.
687              */
688             m = ppp_dequeue(sc);
689             if (m == NULL) {
690                 idle = 1;
691                 break;
692             }
693
694             /*
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.
698              */
699             if (CCOUNT(&tp->t_outq) == 0) {
700                 ++sc->sc_bytessent;
701                 (void) putc(PPP_FLAG, &tp->t_outq);
702             }
703
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;
707             
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;
712         }
713
714         start = mtod(m, u_char *);
715         len = NB_SIZE(m);
716         stop = start + len;
717         while (len > 0) {
718             /*
719              * Find out how many bytes in the string we can
720              * handle without doing something special.
721              */
722             for (cp = start; cp < stop; cp++)
723                 if (ESCAPE_P(*cp))
724                     break;
725
726             n = cp - start;
727
728             if (n) {
729                 /*
730                  * b_to_q returns the number of characters
731                  * _not_ sent
732                  *
733                  * NetBSD (0.9 or later), 4.3-Reno or similar.
734                  */
735                 ndone = n - b_to_q(start, n, &tp->t_outq);
736                 len -= ndone;
737                 start += ndone;
738                 sc->sc_bytessent += ndone;
739
740                 if (ndone < n)
741                     break;      /* packet doesn't fit */
742
743             }
744
745             /*
746              * If there are characters left in the netbuf,
747              * the first one must be special..
748              * Put it out in a different form.
749              */
750             if (len) {
751                 if (putc(PPP_ESCAPE, &tp->t_outq))
752                     break;
753                 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
754                     (void) unputc(&tp->t_outq);
755                     break;
756                 }
757                 sc->sc_bytessent += 2;
758                 start++;
759                 len--;
760             }
761         }
762         /*
763          * If we didn't empty this netbuf, remember where we're up to.
764          */
765         done = len == 0;
766
767         if (!done) {
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 */
771         }
772
773         /*
774          * Output trailing PPP flag and finish packet.
775          * We make the length zero in case the flag
776          * cannot be output immediately.
777          */
778         NB_SHRINK_TOP(m, NB_SIZE(m));
779         if (putc(PPP_FLAG, &tp->t_outq))
780             break;
781         sc->sc_bytessent++;
782
783
784         /* Finished with this netbuf; free it and move on. */
785         NB_FREE(m);
786         m = NULL;
787         incr_cnt(sc->sc_if, if_opackets);
788
789         sc->sc_outm = m;
790     }
791
792     /*
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.
795      */
796     if (tp->t_oproc != NULL)
797         (*tp->t_oproc)(tp);
798
799     /*
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.
803      */
804     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
805 #if NS_TARGET >= 40
806         timeout(ppp_timeout, (void *) sc, 1);
807 #else
808         ns_timeout(ppp_timeout, (void *) sc, 1 * (1000000000L / HZ), CALLOUT_PRI_SOFTINT0);
809 #endif /*NS_TARGET */
810         sc->sc_flags |= SC_TIMEOUT;
811     }
812
813     return;
814 }
815
816 /*
817  * Timeout routine - try to start some more output.
818  */
819 static int
820 ppp_timeout(x)
821     void *x;
822 {
823     struct ppp_softc *sc = (struct ppp_softc *) x;
824     struct tty *tp = (struct tty *) sc->sc_devp;
825     int s;
826
827     s = splimp();
828     sc->sc_flags &= ~SC_TIMEOUT;
829     pppstart(tp);
830     splx(s);
831     return 0;
832 }
833
834 /*
835  * Allocate enough netbuf to handle current MRU.
836  *
837  * Warning Will Robinson:  pppgetm() can get called at interrupt-level!
838  */
839 void
840 pppgetm(sc)
841     register struct ppp_softc *sc;
842 {
843     int s;
844
845     s = splimp();
846     /*
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).
850      */
851     if (sc->sc_m != NULL)
852         NB_FREE(sc->sc_m);
853     sc->sc_m = nbq_dequeue(&sc->sc_freeq);
854     splx(s);
855 }
856
857 /*
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.
863  *
864  * This function gets called when you use the NeXT
865  * supplied serial drivers.  It does not get called
866  * with the MuX driver.  
867  *
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.
871  *
872  */
873
874 void
875 ppprend(cp, n, tp)
876     unsigned char *cp;
877     int n;
878     struct tty *tp;
879 {
880
881 #ifndef OPTIMIZE_PPPREND        
882 #warning PPPREND Not optimized!!!
883   while (n--) pppinput((u_char) *cp++, tp);
884 #else
885
886
887   register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
888   register int ret;
889
890   if (sc == NULL || tp != (struct tty *) sc->sc_devp)
891     {
892       printf("Warning, bad softc structure at %s %d\n", __FILE__, __LINE__);
893       return;
894     }
895
896   /*
897    * We can handle FLUSHs, ESCAPES, and non PPP_FLAG characters
898    */
899   
900   while (n)
901     {
902       if (sc->sc_flags & SC_FLUSH)
903         {
904           do
905             {
906               if (*(cp++) == PPP_FLAG)
907                 {
908                   pppinput(PPP_FLAG, tp);
909                   --n;
910                   break;
911                 }
912               else if (sc->sc_flags & SC_LOG_FLUSH)
913                 ppplogchar(sc, *cp);
914             }
915           while(--n);
916         }
917       else if (sc->sc_ilen > 3 &&
918                (NB_SIZE(sc->sc_m) - sc->sc_ilen) > n &&
919                *cp != PPP_FLAG &&
920                *cp != PPP_ESCAPE)        /* Dont really handle escapes properly...should */
921         {
922           unsigned char* cp1 = cp;
923           if (sc->sc_flags & SC_ESCAPED)
924             {
925               sc->sc_flags &= ~SC_ESCAPED;
926               *cp ^= PPP_TRANS;
927             }
928           
929           do
930             {
931               sc->sc_fcs = PPP_FCS(sc->sc_fcs, *(cp++));
932               if (sc->sc_flags & SC_LOG_RAWIN)
933                 ppplogchar(sc, *cp);
934               
935             } while(--n && *cp != PPP_FLAG && *cp != PPP_ESCAPE);
936           
937           
938           bcopy(cp1, sc->sc_mp, (cp-cp1));
939           
940           sc->sc_bytesrcvd += (cp - cp1);
941           sc->sc_ilen += (cp-cp1);
942           sc->sc_mp += (cp-cp1);
943           
944         }
945       else
946         {
947           --n;
948           pppinput(*(cp++), tp);
949         }
950     }
951   
952 #endif /* OPTIMIZE_PPPREND */
953 }
954
955 /*
956  * tty interface receiver interrupt.
957  */
958 static const unsigned paritytab[8] = {
959     0x96696996, 0x69969669, 0x69969669, 0x96696996,
960     0x69969669, 0x96696996, 0x96696996, 0x69969669
961 };
962
963 void
964 pppinput(c, tp)
965     int c;
966     register struct tty *tp;
967 {
968     register struct ppp_softc *sc;
969     NETBUF_T m;
970     int ilen, s;
971
972     sc = (struct ppp_softc *) tp->t_sc;
973     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
974         return;
975
976     ++tk_nin;
977     ++sc->sc_bytesrcvd;
978
979     if (c & TTY_FE) {
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);
982         goto flush;
983     }
984
985     c &= 0xff;
986
987     if (c & 0x80)
988         sc->sc_flags |= SC_RCV_B7_1;
989     else
990         sc->sc_flags |= SC_RCV_B7_0;
991     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
992         sc->sc_flags |= SC_RCV_ODDP;
993     else
994         sc->sc_flags |= SC_RCV_EVNP;
995
996     if (sc->sc_flags & SC_LOG_RAWIN)
997         ppplogchar(sc, c);
998
999     if (c == PPP_FLAG) {
1000
1001       if (sc->sc_ilen == 0)
1002         return;
1003
1004         ilen = sc->sc_ilen;
1005         sc->sc_ilen = 0;
1006
1007         if (sc->sc_rawin_count > 0)
1008             ppplogchar(sc, -1);
1009
1010         /*
1011          * From the RFC:
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).
1015          *
1016          * So, if SC_ESCAPED is set, then we've seen the packet
1017          * abort sequence "}~".
1018          */
1019         if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) ||
1020             ((ilen > 0) && (sc->sc_fcs != PPP_GOODFCS)))
1021           {
1022             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1023             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0)
1024               {
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);
1027               }
1028             else
1029               {
1030                 IOLog("ppp%d: bad packet flushed...\n", if_unit(sc->sc_if));
1031                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1032               }
1033             return;
1034           }
1035         
1036         if (ilen < (PPP_HDRLEN + PPP_FCSLEN))
1037           {
1038             if (ilen)
1039               {
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;
1043               }
1044             return;
1045           }
1046         
1047         /*
1048          * Remove FCS trailer.  Set packet length...
1049          */
1050         ilen -= PPP_FCSLEN;
1051         NB_SHRINK_BOT(sc->sc_m, NB_SIZE(sc->sc_m) - ilen);
1052
1053         /* excise this netbuf */
1054         m = sc->sc_m;
1055         sc->sc_m = NULL;
1056
1057         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1058         sc->sc_flags &= ~SC_PKTLOST;
1059
1060         pppgetm(sc);
1061         return;
1062     }
1063
1064     if (sc->sc_flags & SC_FLUSH) {
1065         if (sc->sc_flags & SC_LOG_FLUSH)
1066             ppplogchar(sc, c);
1067         return;
1068     }
1069
1070 /*
1071  * From the RFC:
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).
1078  */
1079     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
1080         return;
1081     }
1082
1083     if (sc->sc_flags & SC_ESCAPED) {
1084         sc->sc_flags &= ~SC_ESCAPED;
1085         c ^= PPP_TRANS;
1086     } else if (c == PPP_ESCAPE) {
1087         sc->sc_flags |= SC_ESCAPED;
1088         return;
1089     }
1090
1091     /*
1092      * Initialize buffer on first octet received.
1093      * First octet could be address or protocol (when compressing
1094      * address/control).
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.
1099      */
1100     if (sc->sc_ilen == 0) {
1101
1102         /* reset the input netbuf */
1103         if (sc->sc_m == NULL) {
1104             pppgetm(sc);
1105             if (sc->sc_m == NULL) {
1106                 /*
1107                  * We schedule a call here as pppindrain will
1108                  * not get scheduled and we need the free buffers
1109                  */
1110                 IOLog("ppp%d: no input netbufs!\n", if_unit(sc->sc_if));
1111                 (void)pppsched(pppfillfreeq, sc);
1112                 goto flush;
1113             }
1114         }
1115         m = sc->sc_m;
1116         sc->sc_mp = mtod(m, char *);
1117         sc->sc_fcs = PPP_INITFCS;
1118
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);
1123                 goto flush;
1124             }
1125             *sc->sc_mp++ = PPP_ALLSTATIONS;
1126             *sc->sc_mp++ = PPP_UI;
1127             sc->sc_ilen += 2;
1128         }
1129     }
1130
1131
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);
1135         goto flush;
1136     }
1137
1138     if (sc->sc_ilen == 2 && (c & 1) == 1) {
1139         /* a compressed protocol */
1140         *sc->sc_mp++ = 0;
1141         sc->sc_ilen++;
1142     }
1143
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);
1147         goto flush;
1148     }
1149
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),
1153                 sc->sc_ilen);
1154         goto flush;
1155     }
1156
1157     /* ilen was incremented above... */
1158     *sc->sc_mp++ = c;
1159     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1160     return;
1161
1162  flush:
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)
1167             ppplogchar(sc, c);
1168     }
1169     return;
1170 }
1171
1172 int
1173 install_ppp_ld(void)
1174 {
1175     return tty_ld_install(PPPDISC, NORMAL_LDISC, pppopen,
1176                           pppclose, pppread, pppwrite, ppptioctl,
1177                           pppinput, ppprend, pppstart, ttymodem,
1178                           ttselect);
1179 }
1180
1181 #define MAX_DUMP_BYTES  128
1182
1183 void
1184 ppplogchar(sc, c)
1185     struct ppp_softc *sc;
1186     int c;
1187 {
1188     if (c >= 0)
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;
1195     }
1196 }
1197
1198 static void
1199 pppdumpb(b, l)
1200     u_char *b;
1201     int l;
1202 {
1203     char buf[3*MAX_DUMP_BYTES+4];
1204     char *bp = buf;
1205     static char digits[] = "0123456789abcdef";
1206
1207     while (l--) {
1208         if (bp >= buf + sizeof(buf) - 3) {
1209             *bp++ = '>';
1210             break;
1211         }
1212         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1213         *bp++ = digits[*b++ & 0xf];
1214         *bp++ = ' ';
1215     }
1216
1217     *bp = 0;
1218     IOLog("%s\n", buf);
1219 }
1220 #endif  /* NUM_PPP > 0 */