]> git.ozlabs.org Git - ppp.git/blob - NeXT/ppp_tty.c
update for recent kernel changes
[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) 1989 Carnegie Mellon University.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that the above copyright notice and this paragraph are
12  * duplicated in all such forms and that any documentation,
13  * advertising materials, and other materials related to such
14  * distribution and use acknowledge that the software was developed
15  * by Carnegie Mellon University.  The name of the
16  * University may not be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  *
22  * Drew D. Perkins
23  * Carnegie Mellon University
24  * 4910 Forbes Ave.
25  * Pittsburgh, PA 15213
26  * (412) 268-8576
27  * ddp@andrew.cmu.edu
28  *
29  * Based on:
30  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
31  *
32  * Copyright (c) 1987 Regents of the University of California.
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms are permitted
36  * provided that the above copyright notice and this paragraph are
37  * duplicated in all such forms and that any documentation,
38  * advertising materials, and other materials related to such
39  * distribution and use acknowledge that the software was developed
40  * by the University of California, Berkeley.  The name of the
41  * University may not be used to endorse or promote products derived
42  * from this software without specific prior written permission.
43  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
46  *
47  * Serial Line interface
48  *
49  * Rick Adams
50  * Center for Seismic Studies
51  * 1300 N 17th Street, Suite 1450
52  * Arlington, Virginia 22209
53  * (703)276-7900
54  * rick@seismo.ARPA
55  * seismo!rick
56  *
57  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
58  * Converted to 4.3BSD Beta by Chris Torek.
59  * Other changes made at Berkeley, based in part on code by Kirk Smith.
60  *
61  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
62  * Added VJ tcp header compression; more unified ioctls
63  *
64  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
65  * Cleaned up a lot of the mbuf-related code to fix bugs that
66  * caused system crashes and packet corruption.  Changed pppstart
67  * so that it doesn't just give up with a collision if the whole
68  * packet doesn't fit in the output ring buffer.
69  *
70  * Added priority queueing for interactive IP packets, following
71  * the model of if_sl.c, plus hooks for bpf.
72  * Paul Mackerras (paulus@cs.anu.edu.au).
73  *
74  * Rewritten for NextStep's funky kernel functions, I/O threads,
75  * and netbufs (instead of real mbufs).  Also, ifnets don't install
76  * into the kernel under NS as they do under BSD.  We have tried to
77  * make the code remain as similar to the NetBSD version without
78  * incurring too much hassle.  This code is the merge of 
79  * Philip Prindeville's <philipp@res.enst.fr>/Pete French's <pete@ohm.york.ac.uk>
80  * and Stephen Perkins'  <perkins@cps.msu.edu> independent ports.
81  *
82  */
83
84 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
85 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:59 cgd Exp */
86
87 /* #include "ppp.h" */
88 #if NUM_PPP > 0
89
90 #define KERNEL 1
91 #define KERNEL_FEATURES 1
92 #define INET 1
93
94 #include <sys/param.h>
95 #include <sys/proc.h>
96 #include <sys/user.h>
97 #include "netbuf.h"
98 #include <sys/socket.h>
99 #include <sys/ioctl.h>
100 #include <sys/file.h>
101 #include <sys/tty.h>
102 #include <sys/conf.h>
103 #include <sys/dk.h>
104 #include <sys/uio.h>
105 #include <sys/errno.h>
106 #include <machine/param.h>
107
108
109 #include <kernserv/prototypes.h>
110 /* NeXT broke spl.h in 3.2/m68k. Thanks EPS! */
111
112 #if defined(m68k)
113 #import "spl.h"
114 #else
115 #include <driverkit/generalFuncs.h>
116 #import <kernserv/machine/spl.h>
117 #endif
118
119 #include <kernserv/kern_server_types.h>
120
121 #include <net/if.h>
122 #include <net/route.h>
123
124 #ifdef VJC
125 #include <netinet/in.h>
126 #include <netinet/in_systm.h>
127 #include <netinet/ip.h>
128 #endif
129
130 #include <net/ppp_defs.h>
131 #ifdef VJC
132 #include <net/vjcompress.h>
133 #endif
134 #include <net/if_ppp.h>
135 #include "if_pppvar.h"
136
137 #include "inlines.h"
138
139 int     pppopen __P((dev_t dev, struct tty *tp));
140 void    pppclose __P((struct tty *tp));
141 int     pppread __P((struct tty *tp, struct uio *uio));
142 int     pppwrite __P((struct tty *tp, struct uio *uio));
143 int     ppptioctl __P((struct tty *tp, int cmd, void *data, int flag));
144 void    pppinput __P((int c, struct tty *tp));
145 void    pppstart __P((struct tty *tp));
146
147 /*
148  * Must return an actual netbuf_t since other protocols
149  * use this to get our buffers.
150  */
151 netbuf_t        pppgetbuf __P((netif_t));
152
153 /*
154  * Must accept an actual netbuf_t since others use this
155  * Procedure to access our output routine.
156  */
157 int             pppoutput __P((netif_t ifp, netbuf_t m, void *arg));
158
159 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
160 static void     pppasyncstart __P((struct ppp_softc *));
161 static void     pppasyncctlp __P((struct ppp_softc *));
162 static void     pppasyncrelinq __P((struct ppp_softc *));
163 static int      ppp_timeout __P((void *));
164 void            pppgetm __P((struct ppp_softc *sc));
165 static void     pppdumpb __P((u_char *b, int l));
166 void            ppplogchar __P((struct ppp_softc *, int));
167
168 extern kern_server_t instance;
169
170 /*
171  * Does c need to be escaped?
172  */
173 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
174
175 #define CCOUNT(q)       ((q)->c_cc)
176
177 #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
178
179 #include "linedisc.h"  
180
181
182 extern int ttymodem(struct tty*, int);
183 extern int ttselect(struct tty *tp, int rw);
184
185
186 static NETBUF_T
187 pppgetinbuf(netif_t ifp)
188 {
189     register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)];
190     NETBUF_T nb;
191     int len = MAX(sc->sc_mru, PPP_MTU) + sizeof (struct ifnet *) +
192 #ifdef VJC
193               VJ_HDRLEN +
194 #endif
195               PPP_HDRLEN + PPP_FCSLEN;
196     nb =  NB_ALLOC(len);
197     if (nb != NULL)
198       {
199 #ifdef VJC
200         NB_SHRINK_TOP(nb, VJ_HDRLEN + PPP_HDRLEN);
201 #else
202         NB_SHRINK_TOP(nb, PPP_HDRLEN);
203 #endif
204       }
205
206     return nb;
207 }
208
209 /*
210  * I was a bit worried about reentrancy here.  +++SJP
211  */
212
213 void
214 pppfillfreeq(void *arg)
215 {
216     struct ppp_softc *sc = (struct ppp_softc *)arg;
217     NETBUF_T nb;
218     volatile static int in = 0;
219
220     if (in)
221       return;
222     in = 1;
223
224     while(!nbq_high(&sc->sc_freeq)) {
225         nb = pppgetinbuf(sc->sc_if);
226         if (! nb) break;
227         nbq_enqueue(&sc->sc_freeq, nb);
228     }
229
230     in = 0;
231 }
232
233 /*
234  * Line specific open routine for async tty devices.
235  * Attach the given tty to the first available ppp unit.
236  */
237 /* ARGSUSED */
238 int
239 pppopen(dev, tp)
240     dev_t dev;
241     register struct tty *tp;
242 {
243     struct proc *p = curproc;           /* XXX */
244     register struct ppp_softc *sc;
245     int s;
246
247     if (! suser())
248         return EPERM;
249
250     if (tp->t_line == PPPDISC) {
251         sc = (struct ppp_softc *) tp->t_sc;
252         if (sc != NULL && sc->sc_devp == (void *) tp)
253             return (0);
254     }
255
256     if ((sc = pppalloc(p->p_pid)) == NULL)
257         return ENXIO;
258
259     if (sc->sc_relinq)
260         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
261
262     pppfillfreeq((void *) sc);   /* fill the free queue - we may block */
263
264     s = splimp();
265     sc->sc_ilen = 0;
266     sc->sc_m = NULL;
267     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
268     sc->sc_asyncmap[0] = 0xffffffff;
269     sc->sc_asyncmap[3] = 0x60000000;    /* 0x7D and 0x7E */
270     sc->sc_rasyncmap = 0;
271     sc->sc_devp = (void *) tp;
272     sc->sc_start = pppasyncstart;
273     sc->sc_ctlp = pppasyncctlp;
274     sc->sc_relinq = pppasyncrelinq;
275     sc->sc_outm = NULL;
276     pppgetm(sc);
277     if_flags_set(sc->sc_if, if_flags(sc->sc_if) | IFF_RUNNING);
278
279     tp->t_sc = (caddr_t) sc;
280     ttyflush(tp, FREAD | FWRITE);
281     splx(s);
282
283     return (0);
284 }
285
286 /*
287  * Line specific close routine.
288  * Detach the tty from the ppp unit.
289  * Mimics part of ttyclose().
290  */
291 void
292 pppclose(tp)
293     struct tty *tp;
294 {
295     register struct ppp_softc *sc;
296     int s;
297
298     ttywflush(tp);
299     s = splimp();               /* paranoid; splnet probably ok */
300     tp->t_line = 0;
301     sc = (struct ppp_softc *) tp->t_sc;
302     if (sc != NULL) {
303         tp->t_sc = NULL;
304         if (tp == (struct tty *) sc->sc_devp) {
305             pppasyncrelinq(sc);
306             pppdealloc(sc);
307         }
308     }
309     splx(s);
310     return;
311 }
312
313 /*
314  * Relinquish the interface unit to another device.
315  */
316 static void
317 pppasyncrelinq(sc)
318     struct ppp_softc *sc;
319 {
320     int s;
321
322     s = splimp();
323     if (sc->sc_outm) {
324         NB_FREE(sc->sc_outm);
325         sc->sc_outm = NULL;
326     }
327     if (sc->sc_m) {
328         NB_FREE(sc->sc_m);
329         sc->sc_m = NULL;
330     }
331     if (sc->sc_flags & SC_TIMEOUT) {
332         ns_untimeout(ppp_timeout, (void *) sc);
333         sc->sc_flags &= ~SC_TIMEOUT;
334     }
335     splx(s);
336 }
337
338 /*
339  * Line specific (tty) read routine.
340  */
341 int
342 pppread(tp, uio)
343     register struct tty *tp;
344     struct uio *uio;
345 {
346     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
347     NETBUF_T m;
348     register int s;
349     int error = 0;
350     struct nty *np = ttynty(tp);
351
352 #ifdef NEW_CLOCAL
353     if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
354         return 0;               /* end of file */
355
356 #else
357
358     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
359         return 0;               /* end of file */
360
361 #endif /* NEW_CLOCAL */
362
363     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
364         return 0;
365     s = splimp();
366     while (nbq_empty(&sc->sc_inq) && tp->t_line == PPPDISC) {
367         if (tp->t_state & (TS_ASYNC | TS_NBIO)) {
368             splx(s);
369             return (EWOULDBLOCK);
370         }
371         sleep((caddr_t)&tp->t_rawq, TTIPRI);
372     }
373     if (tp->t_line != PPPDISC) {
374         splx(s);
375         return (-1);
376     }
377
378     /* Pull place-holder byte out of canonical queue */
379     getc(&tp->t_canq);
380
381     /* Get the packet from the input queue */
382     m = nbq_dequeue(&sc->sc_inq);
383     splx(s);
384     if (nbuf == NULL){
385       if (sc->sc_flags & SC_DEBUG)
386         IOLogDbg("Read didn't get a buffer at %s %d\n", __FILE__, __LINE__);
387       return -1;
388     }
389     error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_READ, uio);
390     NB_FREE(m);
391     return (error);
392 }
393
394 /*
395  * Line specific (tty) write routine.
396  */
397 int
398 pppwrite(tp, uio)
399     register struct tty *tp;
400     struct uio *uio;
401 {
402     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
403     NETBUF_T m;
404     struct sockaddr dst;
405     int len, error;
406     struct nty *np = ttynty(tp);
407
408 #ifdef NEW_CLOCAL
409
410     if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
411         return 0;               /* wrote 0 bytes */
412
413 #else
414
415     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
416         return 0;               /* wrote 0 bytes */
417
418 #endif /* NEW_CLOCAL */
419
420     if (tp->t_line != PPPDISC)
421         return (EINVAL);
422     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
423         return EIO;
424     if (uio->uio_resid > if_mtu(sc->sc_if) + PPP_HDRLEN ||
425       uio->uio_resid < PPP_HDRLEN)
426         return (EMSGSIZE);
427     m = nb_TO_NB(pppgetbuf(sc->sc_if));
428
429     if (m == NULL){
430       if (sc->sc_flags & SC_DEBUG)
431         IOLogDbg("No buffers available for user level write()\n");
432       return(ENOBUFS);
433     }
434     NB_GROW_TOP(m, PPP_HDRLEN);
435     len = uio->uio_resid;
436     if (error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_WRITE, uio)) {
437         NB_FREE(m);
438         return error;
439     }
440     NB_SHRINK_BOT(m, NB_SIZE(m) - len);
441     dst.sa_family = AF_UNSPEC;
442     bcopy(mtod(m, u_char *), dst.sa_data, PPP_HDRLEN);
443
444     NB_SHRINK_TOP(m, PPP_HDRLEN);
445     return (pppoutput(sc->sc_if, NB_TO_nb(m), &dst));
446 }
447
448 /*
449  * Line specific (tty) ioctl routine.
450  * This discipline requires that tty device drivers call
451  * the line specific l_ioctl routine from their ioctl routines.
452  */
453 /* ARGSUSED */
454 int
455 ppptioctl(tp, cmd, data, flag)
456     struct tty *tp;
457     void *data;
458     int cmd, flag;
459 {
460     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
461     int error, s;
462
463     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
464         return -1;
465
466     error = 0;
467     switch (cmd) {
468     case PPPIOCSASYNCMAP:
469         if (! suser())
470             return EPERM;
471
472         sc->sc_asyncmap[0] = *(u_int *)data;
473         break;
474
475     case PPPIOCGASYNCMAP:
476         *(u_int *)data = sc->sc_asyncmap[0];
477         break;
478
479     case PPPIOCSRASYNCMAP:
480         if (! suser())
481             return EPERM;
482         sc->sc_rasyncmap = *(u_int *)data;
483         break;
484
485     case PPPIOCGRASYNCMAP:
486         *(u_int *)data = sc->sc_rasyncmap;
487         break;
488
489     case PPPIOCSXASYNCMAP:
490         if (! suser())
491             return EPERM;
492         s = spltty();
493         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
494         sc->sc_asyncmap[1] = 0;                 /* mustn't escape 0x20 - 0x3f */
495         sc->sc_asyncmap[2] &= ~0x40000000;      /* mustn't escape 0x5e */
496         sc->sc_asyncmap[3] |= 0x60000000;       /* must escape 0x7d, 0x7e */
497         splx(s);
498         break;
499
500     case PPPIOCGXASYNCMAP:
501         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
502         break;
503
504     default:
505         error = pppioctl(sc, cmd, data, flag);
506         if (error == 0 && cmd == PPPIOCSMRU)
507             pppgetm(sc);
508     }
509
510 #ifdef  i386
511     if (! error && (cmd & IOC_OUT)) {
512         struct uthread *_u = uthread_from_thread(current_thread());
513
514         /* third arg is destination in ioctl() call... */
515         copyout(data, (caddr_t) _u->uu_arg[2], (cmd >> 16) & IOCPARM_MASK);
516     }
517 #endif
518
519     return error;
520 }
521
522 /*
523  * FCS lookup table as calculated by genfcstab.
524  */
525 static const u_int16_t fcstab[256] = {
526         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
527         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
528         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
529         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
530         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
531         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
532         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
533         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
534         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
535         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
536         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
537         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
538         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
539         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
540         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
541         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
542         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
543         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
544         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
545         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
546         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
547         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
548         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
549         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
550         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
551         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
552         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
553         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
554         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
555         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
556         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
557         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
558 };
559
560 /*
561  * Calculate a new FCS given the current FCS and the new data.
562  */
563 static u_int16_t
564 pppfcs(fcs, cp, len)
565     register u_int16_t fcs;
566     register u_char *cp;
567     register int len;
568 {
569     while (len--)
570         fcs = PPP_FCS(fcs, *cp++);
571     return (fcs);
572 }
573
574 /*
575  * This gets called from pppoutput when a new packet is
576  * put on a queue.
577  */
578 static void
579 pppasyncstart(sc)
580     register struct ppp_softc *sc;
581 {
582     register struct tty *tp = (struct tty *) sc->sc_devp;
583     int s;
584
585     s = splimp();
586     pppstart(tp);
587     splx(s);
588 }
589
590 /*
591  * This gets called when a received packet is placed on
592  * the inq.
593  */
594 static void
595 pppasyncctlp(sc)
596     struct ppp_softc *sc;
597 {
598     struct tty *tp;
599
600     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
601     tp = (struct tty *) sc->sc_devp;
602     putc(0, &tp->t_canq);
603     ttwakeup(tp);
604 }
605
606 /*
607  * Start output on async tty interface.  Get another datagram
608  * to send from the interface queue and start sending it.
609  */
610 void
611 pppstart(tp)
612     register struct tty *tp;
613 {
614     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
615     register NETBUF_T m;
616     register int len;
617     register u_char *start, *stop, *cp;
618     int n, ndone, done, idle;
619     struct nty *np = ttynty(tp);
620
621 #ifdef NEW_CLOCAL
622
623     if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0
624
625 #else
626
627     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0 
628
629 #endif /* NEW_CLOCAL */
630
631         || sc == NULL || tp != (struct tty *) sc->sc_devp) {
632         if (tp->t_oproc != NULL)
633             (*tp->t_oproc)(tp);
634         return;
635     }
636
637     idle = 0;
638 #ifdef  OLD_MUX
639     while (CCOUNT(&tp->t_outq) == 0) {
640 #else
641     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
642 #endif
643         /*
644          * See if we have an existing packet partly sent.
645          * If not, get a new packet and start sending it.
646          */
647         m = sc->sc_outm;
648         if (m == NULL) {
649             /*
650              * Get another packet to be sent.
651              */
652             m = ppp_dequeue(sc);
653             if (m == NULL) {
654                 idle = 1;
655                 break;
656             }
657
658             /*
659              * The extra PPP_FLAG will start up a new packet, and thus
660              * will flush any accumulated garbage.  We do this whenever
661              * the line may have been idle for some time.
662              */
663             if (CCOUNT(&tp->t_outq) == 0) {
664                 ++sc->sc_bytessent;
665                 (void) putc(PPP_FLAG, &tp->t_outq);
666             }
667
668             /* Calculate the FCS for the first netbuf's worth. */
669             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), NB_SIZE(m));
670             sc->sc_outfcs ^= 0xffff;
671             
672             cp = mtod(m, u_char *) + NB_SIZE(m);
673             NB_GROW_BOT(m, PPP_FCSLEN);
674             *cp++ = sc->sc_outfcs & 0xFF;
675             *cp++ = (sc->sc_outfcs >> 8) & 0xFF;
676         }
677
678 #ifdef NETBUF_PROXY
679         m->pktinfo.fourth.tv_sec = time.tv_sec;
680         m->pktinfo.fourth.tv_usec = time.tv_usec;
681 #endif
682
683
684         start = mtod(m, u_char *);
685         len = NB_SIZE(m);
686         stop = start + len;
687         while (len > 0) {
688             /*
689              * Find out how many bytes in the string we can
690              * handle without doing something special.
691              */
692             for (cp = start; cp < stop; cp++)
693                 if (ESCAPE_P(*cp))
694                     break;
695
696             n = cp - start;
697
698             if (n) {
699                 /*
700                  * b_to_q returns the number of characters
701                  * _not_ sent
702                  *
703                  * NetBSD (0.9 or later), 4.3-Reno or similar.
704                  */
705                 ndone = n - b_to_q(start, n, &tp->t_outq);
706                 len -= ndone;
707                 start += ndone;
708                 sc->sc_bytessent += ndone;
709
710                 if (ndone < n)
711                     break;      /* packet doesn't fit */
712
713             }
714
715             /*
716              * If there are characters left in the netbuf,
717              * the first one must be special..
718              * Put it out in a different form.
719              */
720             if (len) {
721                 if (putc(PPP_ESCAPE, &tp->t_outq))
722                     break;
723                 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
724                     (void) unputc(&tp->t_outq);
725                     break;
726                 }
727                 sc->sc_bytessent += 2;
728                 start++;
729                 len--;
730 #ifdef NETBUF_PROXY
731         ++(m->pktinfo.async_esc);
732 #endif
733             }
734         }
735         /*
736          * If we didn't empty this netbuf, remember where we're up to.
737          */
738         done = len == 0;
739
740         if (!done) {
741             /* remember where we got to */
742             NB_SHRINK_TOP(m, start - mtod(m, u_char *));
743             break;      /* can't do any more at the moment */
744         }
745
746         /*
747          * Output trailing PPP flag and finish packet.
748          * We make the length zero in case the flag
749          * cannot be output immediately.
750          */
751         NB_SHRINK_TOP(m, NB_SIZE(m));
752         if (putc(PPP_FLAG, &tp->t_outq))
753             break;
754         sc->sc_bytessent++;
755
756
757 #ifdef NETBUF_PROXY
758         m->pktinfo.fifth.tv_sec = time.tv_sec;
759         m->pktinfo.fifth.tv_usec = time.tv_usec;
760 #endif
761
762
763 #if defined(NBPFILTER) && defined(NETBUF_PROXY)
764
765     /*
766      * See if bpf wants to look at the packet.  Gotta be careful
767      * here because BPF want the uncompressed packet.  For now we
768      * stash a copy that we hand off.  In the future, we may try
769      * to modify BPF to handle compressed packets instead.
770      *
771      * The BPF process point will not work for
772      * non-NETBUF_PROXY points.  In this case, we hand the packet
773      * to BPF earlier in the process (see if_ppp.c).
774      *
775      */
776
777           if (sc->sc_bpf)
778               bpf_tap(sc->sc_bpf, m, 0);
779
780 #endif
781
782         /* Finished with this netbuf; free it and move on. */
783         NB_FREE(m);
784         m = NULL;
785         incr_cnt(sc->sc_if, if_opackets);
786
787         sc->sc_outm = m;
788     }
789
790     /*
791      * If there is stuff in the output queue, send it now.
792      * We are being called in lieu of ttstart and must do what it would.
793      */
794     if (tp->t_oproc != NULL)
795         (*tp->t_oproc)(tp);
796
797     /*
798      * This timeout is needed for operation on a pseudo-tty,
799      * because the pty code doesn't call pppstart after it has
800      * drained the t_outq.
801      */
802     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
803         ns_timeout(ppp_timeout, (void *) sc, 1 * (1000000000L / HZ), CALLOUT_PRI_SOFTINT0);
804         sc->sc_flags |= SC_TIMEOUT;
805     }
806
807     return;
808 }
809
810 /*
811  * Timeout routine - try to start some more output.
812  */
813 static int
814 ppp_timeout(x)
815     void *x;
816 {
817     struct ppp_softc *sc = (struct ppp_softc *) x;
818     struct tty *tp = (struct tty *) sc->sc_devp;
819     int s;
820
821     s = splimp();
822     sc->sc_flags &= ~SC_TIMEOUT;
823     pppstart(tp);
824     splx(s);
825     return 0;
826 }
827
828 /*
829  * Allocate enough netbuf to handle current MRU.
830  *
831  * Warning Will Robinson:  pppgetm() can get called at interrupt-level!
832  */
833 void
834 pppgetm(sc)
835     register struct ppp_softc *sc;
836 {
837     int s;
838
839     s = splimp();
840     /*
841      * When the MRU is being changed, we could conceivably end up
842      * nuking a packet being received, but I doubt it, since the
843      * hand-shake is lock-step (ie. single packet).
844      */
845     if (sc->sc_m != NULL)
846         NB_FREE(sc->sc_m);
847     sc->sc_m = nbq_dequeue(&sc->sc_freeq);
848     splx(s);
849 }
850
851 /*
852  * 4.3 says this is an unused function.  However,
853  * it appears to be returning a NULL terminated string
854  * of several characters.  My guess is that the serial
855  * driver is doing a little buffering so that we don't
856  * get burdend with interrupts.
857  *
858  * This function gets called when you use the NeXT
859  * supplied serial drivers.  It does not get called
860  * with the MuX driver.  
861  *
862  * In order to expedite the work done here, we
863  * handle most things here that don't require
864  * processing of a PPP_FLAG.
865  *
866  */
867
868 void
869 ppprend(cp, n, tp)
870     unsigned char *cp;
871     int n;
872     struct tty *tp;
873 {
874
875 #ifndef OPTIMIZE_PPPREND        
876 #warning PPPREND Not optimized!!!
877   while (n--) pppinput((u_char) *cp++, tp);
878 #else
879
880
881   register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
882   register int ret;
883
884   if (sc == NULL || tp != (struct tty *) sc->sc_devp)
885     {
886       printf("Warning, bad softc structure at %s %d\n", __FILE__, __LINE__);
887       return;
888     }
889
890   /*
891    * We can handle FLUSHs, ESCAPES, and non PPP_FLAG characters
892    */
893   
894   while (n)
895     {
896       if (sc->sc_flags & SC_FLUSH)
897         {
898           do
899             {
900               if (*(cp++) == PPP_FLAG)
901                 {
902                   pppinput(PPP_FLAG, tp);
903                   --n;
904                   break;
905                 }
906               else if (sc->sc_flags & SC_LOG_FLUSH)
907                 ppplogchar(sc, *cp);
908             }
909           while(--n);
910         }
911       else if (sc->sc_ilen > 3 &&
912                (NB_SIZE(sc->sc_m) - sc->sc_ilen) > n &&
913                *cp != PPP_FLAG &&
914                *cp != PPP_ESCAPE)        /* Dont really handle escapes properly...should */
915         {
916           unsigned char* cp1 = cp;
917           if (sc->sc_flags & SC_ESCAPED)
918             {
919               sc->sc_flags &= ~SC_ESCAPED;
920               *cp ^= PPP_TRANS;
921             }
922           
923           do
924             {
925               sc->sc_fcs = PPP_FCS(sc->sc_fcs, *(cp++));
926               if (sc->sc_flags & SC_LOG_RAWIN)
927                 ppplogchar(sc, *cp);
928               
929             } while(--n && *cp != PPP_FLAG && *cp != PPP_ESCAPE);
930           
931           
932           bcopy(cp1, sc->sc_mp, (cp-cp1));
933           
934           sc->sc_bytesrcvd += (cp - cp1);
935           sc->sc_ilen += (cp-cp1);
936           sc->sc_mp += (cp-cp1);
937           
938         }
939       else
940         {
941           --n;
942           pppinput(*(cp++), tp);
943         }
944     }
945   
946 #endif /* OPTIMIZE_PPPREND */
947 }
948
949 /*
950  * tty interface receiver interrupt.
951  */
952 static const unsigned paritytab[8] = {
953     0x96696996, 0x69969669, 0x69969669, 0x96696996,
954     0x69969669, 0x96696996, 0x96696996, 0x69969669
955 };
956
957 void
958 pppinput(c, tp)
959     int c;
960     register struct tty *tp;
961 {
962     register struct ppp_softc *sc;
963     NETBUF_T m;
964     int ilen, s;
965
966     sc = (struct ppp_softc *) tp->t_sc;
967     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
968         return;
969
970     ++tk_nin;
971     ++sc->sc_bytesrcvd;
972
973     if (c & TTY_FE) {
974         /* framing error or overrun on this char - abort packet */
975         IOLogDbg("ppp%d: bad char 0x%x\n", if_unit(sc->sc_if), c);
976         goto flush;
977     }
978
979     c &= 0xff;
980
981     if (c & 0x80)
982         sc->sc_flags |= SC_RCV_B7_1;
983     else
984         sc->sc_flags |= SC_RCV_B7_0;
985     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
986         sc->sc_flags |= SC_RCV_ODDP;
987     else
988         sc->sc_flags |= SC_RCV_EVNP;
989
990     if (sc->sc_flags & SC_LOG_RAWIN)
991         ppplogchar(sc, c);
992
993     if (c == PPP_FLAG) {
994
995       if (sc->sc_ilen == 0)
996         return;
997
998         ilen = sc->sc_ilen;
999         sc->sc_ilen = 0;
1000
1001         if (sc->sc_rawin_count > 0)
1002             ppplogchar(sc, -1);
1003
1004         /*
1005          * From the RFC:
1006          *  Each Control Escape octet is also
1007          *  removed, and the following octet is exclusive-or'd with hexadecimal
1008          *  0x20, unless it is the Flag Sequence (which aborts a frame).
1009          *
1010          * So, if SC_ESCAPED is set, then we've seen the packet
1011          * abort sequence "}~".
1012          */
1013         if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) ||
1014             ((ilen > 0) && (sc->sc_fcs != PPP_GOODFCS)))
1015           {
1016             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1017             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0)
1018               {
1019                 IOLog("ppp%d: bad fcs 0x%04x\n", if_unit(sc->sc_if), sc->sc_fcs);
1020                 incr_cnt(sc->sc_if, if_ierrors);
1021               }
1022             else
1023               {
1024                 IOLog("ppp%d: bad packet flushed...\n", if_unit(sc->sc_if));
1025                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1026               }
1027             return;
1028           }
1029         
1030         if (ilen < (PPP_HDRLEN + PPP_FCSLEN))
1031           {
1032             if (ilen)
1033               {
1034                 IOLogDbg("ppp%d: too short (%d)\n", if_unit(sc->sc_if), ilen);
1035                 incr_cnt(sc->sc_if, if_ierrors);
1036                 sc->sc_flags |= SC_PKTLOST;
1037               }
1038             return;
1039           }
1040         
1041 #ifdef NETBUF_PROXY
1042         sc->sc_m->pktinfo.second.tv_sec = time.tv_sec;
1043         sc->sc_m->pktinfo.second.tv_usec = time.tv_usec;
1044         sc->sc_m->pktinfo.size1 = ilen;
1045 #endif
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 #ifdef NETBUF_PROXY
1089         ++(sc->sc_m->pktinfo.async_esc);
1090 #endif
1091         return;
1092     }
1093
1094     /*
1095      * Initialize buffer on first octet received.
1096      * First octet could be address or protocol (when compressing
1097      * address/control).
1098      * Second octet is control.
1099      * Third octet is first or second (when compressing protocol)
1100      * octet of protocol.
1101      * Fourth octet is second octet of protocol.
1102      */
1103     if (sc->sc_ilen == 0) {
1104
1105         /* reset the input netbuf */
1106         if (sc->sc_m == NULL) {
1107             pppgetm(sc);
1108             if (sc->sc_m == NULL) {
1109                 /*
1110                  * We schedule a call here as pppindrain will
1111                  * not get scheduled and we need the free buffers
1112                  */
1113                 IOLog("ppp%d: no input netbufs!\n", if_unit(sc->sc_if));
1114                 (void)pppsched(pppfillfreeq, sc);
1115                 goto flush;
1116             }
1117         }
1118         m = sc->sc_m;
1119         sc->sc_mp = mtod(m, char *);
1120         sc->sc_fcs = PPP_INITFCS;
1121
1122 #ifdef NETBUF_PROXY
1123         m->pktinfo.first.tv_sec = time.tv_sec;
1124         m->pktinfo.first.tv_usec = time.tv_usec;
1125         m->pktinfo.flags |= NBFLAG_INCOMING;
1126 #endif
1127         if (c != PPP_ALLSTATIONS) {
1128             if (sc->sc_flags & SC_REJ_COMP_AC) {
1129                 IOLogDbg("ppp%d: garbage received: 0x%02x (need 0x%02x)\n",
1130                            if_unit(sc->sc_if), c, PPP_ALLSTATIONS);
1131                 goto flush;
1132             }
1133             *sc->sc_mp++ = PPP_ALLSTATIONS;
1134             *sc->sc_mp++ = PPP_UI;
1135             sc->sc_ilen += 2;
1136 #ifdef NETBUF_PROXY
1137             m->pktinfo.flags |= NBFLAG_AC;
1138 #endif      
1139         }
1140     }
1141
1142
1143     if (sc->sc_ilen == 1 && c != PPP_UI) {
1144         IOLogDbg("ppp%d: missing UI (0x%02x), got 0x%02x\n",
1145                    if_unit(sc->sc_if), PPP_UI, c);
1146         goto flush;
1147     }
1148
1149     if (sc->sc_ilen == 2 && (c & 1) == 1) {
1150         /* a compressed protocol */
1151         *sc->sc_mp++ = 0;
1152         sc->sc_ilen++;
1153 #ifdef NETBUF_PROXY
1154             m->pktinfo.flags |= NBFLAG_PC;
1155 #endif      
1156     }
1157
1158     if (sc->sc_ilen == 3 && (c & 1) == 0) {
1159         IOLogDbg("ppp%d: bad protocol %x\n", if_unit(sc->sc_if),
1160                    (sc->sc_mp[-1] << 8) + c);
1161         goto flush;
1162     }
1163
1164     /* packet beyond configured mru? */
1165     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1166         IOLogDbg("ppp%d: packet too big (%d bytes)\n", if_unit(sc->sc_if),
1167                 sc->sc_ilen);
1168         goto flush;
1169     }
1170
1171     /* ilen was incremented above... */
1172     *sc->sc_mp++ = c;
1173     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1174     return;
1175
1176  flush:
1177     if (!(sc->sc_flags & SC_FLUSH)) {
1178         incr_cnt(sc->sc_if, if_ierrors);
1179         sc->sc_flags |= SC_FLUSH;
1180         if (sc->sc_flags & SC_LOG_FLUSH)
1181             ppplogchar(sc, c);
1182     }
1183     return;
1184 }
1185
1186 int
1187 install_ppp_ld(void)
1188 {
1189     return tty_ld_install(PPPDISC, NORMAL_LDISC, pppopen,
1190                           pppclose, pppread, pppwrite, ppptioctl,
1191                           pppinput, ppprend, pppstart, ttymodem,
1192                           ttselect);
1193 }
1194
1195 #define MAX_DUMP_BYTES  128
1196
1197 void
1198 ppplogchar(sc, c)
1199     struct ppp_softc *sc;
1200     int c;
1201 {
1202     if (c >= 0)
1203         sc->sc_rawin[sc->sc_rawin_count++] = c;
1204     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1205         || c < 0 && sc->sc_rawin_count > 0) {
1206         IOLog("ppp%d input:\n", if_unit(sc->sc_if));
1207         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1208         sc->sc_rawin_count = 0;
1209     }
1210 }
1211
1212 static void
1213 pppdumpb(b, l)
1214     u_char *b;
1215     int l;
1216 {
1217     char buf[3*MAX_DUMP_BYTES+4];
1218     char *bp = buf;
1219     static char digits[] = "0123456789abcdef";
1220
1221     while (l--) {
1222         if (bp >= buf + sizeof(buf) - 3) {
1223             *bp++ = '>';
1224             break;
1225         }
1226         *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1227         *bp++ = digits[*b++ & 0xf];
1228         *bp++ = ' ';
1229     }
1230
1231     *bp = 0;
1232     IOLog("%s\n", buf);
1233 }
1234 #endif  /* NUM_PPP > 0 */