]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/ppp_tty.c
This commit was generated by cvs2svn to compensate for changes in r155420,
[FreeBSD/FreeBSD.git] / sys / net / ppp_tty.c
1 /*
2  * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
3  *             tty devices.
4  */
5 /*-
6  * Copyright (c) 1989 Carnegie Mellon University.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by Carnegie Mellon University.  The name of the
15  * University may not be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * Drew D. Perkins
22  * Carnegie Mellon University
23  * 4910 Forbes Ave.
24  * Pittsburgh, PA 15213
25  * (412) 268-8576
26  * ddp@andrew.cmu.edu
27  *
28  * Based on:
29  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
30  *
31  * Copyright (c) 1987 Regents of the University of California.
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms are permitted
35  * provided that the above copyright notice and this paragraph are
36  * duplicated in all such forms and that any documentation,
37  * advertising materials, and other materials related to such
38  * distribution and use acknowledge that the software was developed
39  * by the University of California, Berkeley.  The name of the
40  * University may not be used to endorse or promote products derived
41  * from this software without specific prior written permission.
42  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
43  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
44  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
45  *
46  * Serial Line interface
47  *
48  * Rick Adams
49  * Center for Seismic Studies
50  * 1300 N 17th Street, Suite 1450
51  * Arlington, Virginia 22209
52  * (703)276-7900
53  * rick@seismo.ARPA
54  * seismo!rick
55  *
56  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
57  * Converted to 4.3BSD Beta by Chris Torek.
58  * Other changes made at Berkeley, based in part on code by Kirk Smith.
59  *
60  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
61  * Added VJ tcp header compression; more unified ioctls
62  *
63  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
64  * Cleaned up a lot of the mbuf-related code to fix bugs that
65  * caused system crashes and packet corruption.  Changed pppstart
66  * so that it doesn't just give up with a "collision" if the whole
67  * packet doesn't fit in the output ring buffer.
68  *
69  * Added priority queueing for interactive IP packets, following
70  * the model of if_sl.c, plus hooks for bpf.
71  * Paul Mackerras (paulus@cs.anu.edu.au).
72  */
73
74 /* $FreeBSD$ */
75
76 #include "opt_ppp.h"            /* XXX for ppp_defs.h */
77
78 #define VJC                     /* XXX for ppp_defs.h */
79
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/proc.h>
83 #include <sys/mbuf.h>
84 #include <sys/socket.h>
85 #include <sys/fcntl.h>
86 #include <sys/tty.h>
87 #include <sys/conf.h>
88 #include <sys/uio.h>
89
90 #ifdef PPP_FILTER
91 #include <net/bpf.h>
92 #endif
93 #include <net/if_ppp.h>
94 #include <net/if_pppvar.h>
95
96 static int      pppopen(struct cdev *dev, struct tty *tp);
97 static int      pppclose(struct tty *tp, int flag);
98 static int      pppread(struct tty *tp, struct uio *uio, int flag);
99 static int      pppwrite(struct tty *tp, struct uio *uio, int flag);
100 static int      ppptioctl(struct tty *tp, u_long cmd, caddr_t data,
101                                         int flag, struct thread *td);
102 static int      pppinput(int c, struct tty *tp);
103 static int      pppstart(struct tty *tp);
104
105 static u_short  pppfcs(u_short fcs, u_char *cp, int len);
106 static void     pppasyncstart(struct ppp_softc *);
107 static void     pppasyncctlp(struct ppp_softc *);
108 static void     pppasyncrelinq(struct ppp_softc *);
109 static void     pppasyncsetmtu(struct ppp_softc *);
110 static void     ppp_timeout(void *);
111 static void     pppgetm(struct ppp_softc *sc);
112 static void     ppplogchar(struct ppp_softc *, int);
113
114 /* XXX called from if_ppp.c - layering violation */
115 void            pppasyncattach(void *);
116 void            pppasyncdetach(void);
117
118 /*
119  * Some useful mbuf macros not in mbuf.h.
120  */
121 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
122
123 #define M_DATASTART(m)  \
124         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
125             (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
126
127 #define M_DATASIZE(m)   \
128         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
129             (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
130
131 /*
132  * Does c need to be escaped?
133  */
134 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
135
136 /*
137  * Procedures for using an async tty interface for PPP.
138  */
139
140 /* This is a FreeBSD-2.X kernel. */
141 #define CCOUNT(q)       ((q)->c_cc)
142 #define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
143 #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
144
145 /*
146  * Define the PPP line discipline.
147  */
148
149 static struct linesw pppdisc = {
150         pppopen,        pppclose,       pppread,        pppwrite,
151         ppptioctl,      pppinput,       pppstart,       ttymodem
152 };
153
154 void
155 pppasyncattach(dummy)
156     void *dummy;
157 {
158     ldisc_register(PPPDISC, &pppdisc);
159 }
160
161 void
162 pppasyncdetach()
163 {
164     ldisc_deregister(PPPDISC);
165 }
166
167 /*
168  * Line specific open routine for async tty devices.
169  * Attach the given tty to the first available ppp unit.
170  * Called from device open routine or ttioctl() at >= splsofttty()
171  */
172 /* ARGSUSED */
173 static int
174 pppopen(dev, tp)
175     struct cdev *dev;
176     register struct tty *tp;
177 {
178     struct thread *td = curthread;              /* XXX */
179     register struct ppp_softc *sc;
180     int error, s;
181
182     if ((error = suser(td)) != 0)
183         return (error);
184
185     s = spltty();
186
187     tp->t_hotchar = PPP_FLAG;
188
189     if ((sc = pppalloc(td->td_proc->p_pid)) == NULL) {
190         splx(s);
191         return ENXIO;
192     }
193
194     if (sc->sc_relinq)
195         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
196
197     sc->sc_ilen = 0;
198     sc->sc_m = NULL;
199     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
200     sc->sc_asyncmap[0] = 0xffffffff;
201     sc->sc_asyncmap[3] = 0x60000000;
202     sc->sc_rasyncmap = 0;
203     sc->sc_devp = (void *) tp;
204     sc->sc_start = pppasyncstart;
205     sc->sc_ctlp = pppasyncctlp;
206     sc->sc_relinq = pppasyncrelinq;
207     sc->sc_setmtu = pppasyncsetmtu;
208     sc->sc_outm = NULL;
209     pppgetm(sc);
210     PPP2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
211     getmicrotime(&PPP2IFP(sc)->if_lastchange);
212     PPP2IFP(sc)->if_baudrate = tp->t_ospeed;
213
214     tp->t_hotchar = PPP_FLAG;
215     tp->t_lsc = sc;
216     ttyflush(tp, FREAD | FWRITE);
217
218     /*
219      * Pre-allocate cblocks to the "just right" amount.  The 1 byte t_canq
220      * allocation helps avoid the need for select and/or FIONREAD.
221      * We also pass 1 byte tokens through t_canq...
222      */
223     clist_alloc_cblocks(&tp->t_canq, 1, 1);
224     clist_alloc_cblocks(&tp->t_outq, PPP2IFP(sc)->if_mtu + PPP_HIWAT,
225                         PPP2IFP(sc)->if_mtu + PPP_HIWAT);
226     clist_alloc_cblocks(&tp->t_rawq, 0, 0);
227
228     splx(s);
229
230     return (0);
231 }
232
233 /*
234  * Line specific close routine, called from device close routine
235  * and from ttioctl at >= splsofttty().
236  * Detach the tty from the ppp unit.
237  * Mimics part of tty_close().
238  */
239 static int
240 pppclose(tp, flag)
241     struct tty *tp;
242     int flag;
243 {
244     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
245     int s;
246
247     s = spltty();
248     ttyflush(tp, FREAD | FWRITE);
249     clist_free_cblocks(&tp->t_canq);
250     clist_free_cblocks(&tp->t_outq);
251     if (sc != NULL) {
252             pppasyncrelinq(sc);
253             pppdealloc(sc);
254     }
255     splx(s);
256     return 0;
257 }
258
259 /*
260  * Relinquish the interface unit to another device.
261  */
262 static void
263 pppasyncrelinq(sc)
264     struct ppp_softc *sc;
265 {
266     int s;
267
268     s = spltty();
269     if (sc->sc_outm) {
270         m_freem(sc->sc_outm);
271         sc->sc_outm = NULL;
272     }
273     if (sc->sc_m) {
274         m_freem(sc->sc_m);
275         sc->sc_m = NULL;
276     }
277     if (sc->sc_flags & SC_TIMEOUT) {
278         untimeout(ppp_timeout, (void *) sc, sc->sc_ch);
279         sc->sc_flags &= ~SC_TIMEOUT;
280     }
281     splx(s);
282 }
283
284 /*
285  * This gets called from the upper layer to notify a mtu change
286  */
287 static void
288 pppasyncsetmtu(sc)
289 register struct ppp_softc *sc;
290 {
291     register struct tty *tp = (struct tty *) sc->sc_devp;
292     int s;
293
294     s = spltty();
295     if (tp != NULL)
296         clist_alloc_cblocks(&tp->t_outq, PPP2IFP(sc)->if_mtu + PPP_HIWAT,
297                              PPP2IFP(sc)->if_mtu + PPP_HIWAT);
298     splx(s);
299 }
300
301 /*
302  * Line specific (tty) read routine.
303  * called at zero spl from the device driver in the response to user-level
304  * reads on the tty file descriptor (ie: pppd).
305  */
306 static int
307 pppread(tp, uio, flag)
308     register struct tty *tp;
309     struct uio *uio;
310     int flag;
311 {
312     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
313     struct mbuf *m, *m0;
314     register int s;
315     int error = 0;
316
317     if (sc == NULL)
318         return 0;
319     /*
320      * Loop waiting for input, checking that nothing disasterous
321      * happens in the meantime.
322      */
323     s = spltty();
324     for (;;) {
325         if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
326             splx(s);
327             return 0;
328         }
329         if (sc->sc_inq.ifq_head != NULL)
330             break;
331         if ((tp->t_state & TS_CONNECTED) == 0) {
332             splx(s);
333             return 0;           /* end of file */
334         }
335         if (tp->t_state & TS_ASYNC || flag & O_NONBLOCK) {
336             splx(s);
337             return (EWOULDBLOCK);
338         }
339         error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0);
340         if (error) {
341             splx(s);
342             return error;
343         }
344     }
345
346     /* Pull place-holder byte out of canonical queue */
347     getc(&tp->t_canq);
348
349     /* Get the packet from the input queue */
350     IF_DEQUEUE(&sc->sc_inq, m0);
351     splx(s);
352
353     for (m = m0; m && uio->uio_resid; m = m->m_next)
354         if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
355             break;
356     m_freem(m0);
357     return (error);
358 }
359
360 /*
361  * Line specific (tty) write routine.
362  * called at zero spl from the device driver in the response to user-level
363  * writes on the tty file descriptor (ie: pppd).
364  */
365 static int
366 pppwrite(tp, uio, flag)
367     register struct tty *tp;
368     struct uio *uio;
369     int flag;
370 {
371     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
372     struct mbuf *m;
373     struct sockaddr dst;
374     int error, s;
375
376     if ((tp->t_state & TS_CONNECTED) == 0)
377         return 0;               /* wrote 0 bytes */
378     if (tp->t_line != PPPDISC)
379         return (EINVAL);
380     if (sc == NULL)
381         return EIO;
382     if (uio->uio_resid > PPP2IFP(sc)->if_mtu + PPP_HDRLEN ||
383         uio->uio_resid < PPP_HDRLEN)
384         return (EMSGSIZE);
385
386     s = spltty();
387     if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, 0)) == NULL) {
388         splx(s);
389         return (ENOBUFS);
390     }
391
392     dst.sa_family = AF_UNSPEC;
393     bcopy(mtod(m, u_char *), dst.sa_data, PPP_HDRLEN);
394     m->m_data += PPP_HDRLEN;
395     m->m_len -= PPP_HDRLEN;
396
397     /* call the upper layer to "transmit" it... */
398     error = pppoutput(PPP2IFP(sc), m, &dst, NULL);
399     splx(s);
400     return (error);
401 }
402
403 /*
404  * Line specific (tty) ioctl routine.
405  * This discipline requires that tty device drivers call
406  * the line specific l_ioctl routine from their ioctl routines.
407  */
408 /* ARGSUSED */
409 static int
410 ppptioctl(tp, cmd, data, flag, td)
411     struct tty *tp;
412     u_long cmd;
413     caddr_t data;
414     int flag;
415     struct thread *td;
416 {
417     struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
418     int error, s;
419
420     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
421         return (ENOIOCTL);
422
423     error = 0;
424     switch (cmd) {
425     case PPPIOCSASYNCMAP:
426         if ((error = suser(td)) != 0)
427             break;
428         sc->sc_asyncmap[0] = *(u_int *)data;
429         break;
430
431     case PPPIOCGASYNCMAP:
432         *(u_int *)data = sc->sc_asyncmap[0];
433         break;
434
435     case PPPIOCSRASYNCMAP:
436         if ((error = suser(td)) != 0)
437             break;
438         sc->sc_rasyncmap = *(u_int *)data;
439         break;
440
441     case PPPIOCGRASYNCMAP:
442         *(u_int *)data = sc->sc_rasyncmap;
443         break;
444
445     case PPPIOCSXASYNCMAP:
446         if ((error = suser(td)) != 0)
447             break;
448         s = spltty();
449         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
450         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
451         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
452         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
453         splx(s);
454         break;
455
456     case PPPIOCGXASYNCMAP:
457         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
458         break;
459
460     default:
461         error = pppioctl(sc, cmd, data, flag, td);
462         if (error == 0 && cmd == PPPIOCSMRU)
463             pppgetm(sc);
464     }
465
466     return error;
467 }
468
469 /*
470  * FCS lookup table as calculated by genfcstab.
471  */
472 static u_short fcstab[256] = {
473         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
474         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
475         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
476         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
477         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
478         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
479         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
480         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
481         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
482         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
483         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
484         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
485         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
486         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
487         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
488         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
489         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
490         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
491         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
492         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
493         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
494         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
495         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
496         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
497         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
498         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
499         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
500         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
501         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
502         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
503         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
504         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
505 };
506
507 /*
508  * Calculate a new FCS given the current FCS and the new data.
509  */
510 static u_short
511 pppfcs(u_short fcs, u_char *cp, int len)
512 {
513     while (len--)
514         fcs = PPP_FCS(fcs, *cp++);
515     return (fcs);
516 }
517
518 /*
519  * This gets called at splsoftnet from if_ppp.c at various times
520  * when there is data ready to be sent.
521  */
522 static void
523 pppasyncstart(sc)
524     register struct ppp_softc *sc;
525 {
526     register struct tty *tp = (struct tty *) sc->sc_devp;
527     register struct mbuf *m;
528     register int len;
529     register u_char *start, *stop, *cp;
530     int n, ndone, done, idle;
531     int s;
532
533     idle = 0;
534     /* XXX assumes atomic access to *tp although we're not at spltty(). */
535     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
536         /*
537          * See if we have an existing packet partly sent.
538          * If not, get a new packet and start sending it.
539          */
540         m = sc->sc_outm;
541         if (m == NULL) {
542             /*
543              * Get another packet to be sent.
544              */
545             m = ppp_dequeue(sc);
546             if (m == NULL) {
547                 idle = 1;
548                 break;
549             }
550
551             /*
552              * The extra PPP_FLAG will start up a new packet, and thus
553              * will flush any accumulated garbage.  We do this whenever
554              * the line may have been idle for some time.
555              */
556             /* XXX as above. */
557             if (CCOUNT(&tp->t_outq) == 0) {
558                 ++sc->sc_stats.ppp_obytes;
559                 (void) putc(PPP_FLAG, &tp->t_outq);
560             }
561
562             /* Calculate the FCS for the first mbuf's worth. */
563             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
564             getmicrotime(&PPP2IFP(sc)->if_lastchange);
565         }
566
567         for (;;) {
568             start = mtod(m, u_char *);
569             len = m->m_len;
570             stop = start + len;
571             while (len > 0) {
572                 /*
573                  * Find out how many bytes in the string we can
574                  * handle without doing something special.
575                  */
576                 for (cp = start; cp < stop; cp++)
577                     if (ESCAPE_P(*cp))
578                         break;
579                 n = cp - start;
580                 if (n) {
581                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
582                     ndone = n - b_to_q(start, n, &tp->t_outq);
583                     len -= ndone;
584                     start += ndone;
585                     sc->sc_stats.ppp_obytes += ndone;
586
587                     if (ndone < n)
588                         break;  /* packet doesn't fit */
589                 }
590                 /*
591                  * If there are characters left in the mbuf,
592                  * the first one must be special.
593                  * Put it out in a different form.
594                  */
595                 if (len) {
596                     s = spltty();
597                     if (putc(PPP_ESCAPE, &tp->t_outq)) {
598                         splx(s);
599                         break;
600                     }
601                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
602                         (void) unputc(&tp->t_outq);
603                         splx(s);
604                         break;
605                     }
606                     splx(s);
607                     sc->sc_stats.ppp_obytes += 2;
608                     start++;
609                     len--;
610                 }
611             }
612
613             /*
614              * If we didn't empty this mbuf, remember where we're up to.
615              * If we emptied the last mbuf, try to add the FCS and closing
616              * flag, and if we can't, leave sc_outm pointing to m, but with
617              * m->m_len == 0, to remind us to output the FCS and flag later.
618              */
619             done = len == 0;
620             if (done && m->m_next == NULL) {
621                 u_char *p, *q;
622                 int c;
623                 u_char endseq[8];
624
625                 /*
626                  * We may have to escape the bytes in the FCS.
627                  */
628                 p = endseq;
629                 c = ~sc->sc_outfcs & 0xFF;
630                 if (ESCAPE_P(c)) {
631                     *p++ = PPP_ESCAPE;
632                     *p++ = c ^ PPP_TRANS;
633                 } else
634                     *p++ = c;
635                 c = (~sc->sc_outfcs >> 8) & 0xFF;
636                 if (ESCAPE_P(c)) {
637                     *p++ = PPP_ESCAPE;
638                     *p++ = c ^ PPP_TRANS;
639                 } else
640                     *p++ = c;
641                 *p++ = PPP_FLAG;
642
643                 /*
644                  * Try to output the FCS and flag.  If the bytes
645                  * don't all fit, back out.
646                  */
647                 s = spltty();
648                 for (q = endseq; q < p; ++q)
649                     if (putc(*q, &tp->t_outq)) {
650                         done = 0;
651                         for (; q > endseq; --q)
652                             unputc(&tp->t_outq);
653                         break;
654                     }
655                 splx(s);
656                 if (done)
657                     sc->sc_stats.ppp_obytes += q - endseq;
658             }
659
660             if (!done) {
661                 /* remember where we got to */
662                 m->m_data = start;
663                 m->m_len = len;
664                 break;
665             }
666
667             /* Finished with this mbuf; free it and move on. */
668             m = m_free(m);
669             if (m == NULL) {
670                 /* Finished a packet */
671                 break;
672             }
673             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
674         }
675
676         /*
677          * If m == NULL, we have finished a packet.
678          * If m != NULL, we've either done as much work this time
679          * as we need to, or else we've filled up the output queue.
680          */
681         sc->sc_outm = m;
682         if (m)
683             break;
684     }
685
686     /* Call pppstart to start output again if necessary. */
687     s = spltty();
688     pppstart(tp);
689
690     /*
691      * This timeout is needed for operation on a pseudo-tty,
692      * because the pty code doesn't call pppstart after it has
693      * drained the t_outq.
694      */
695     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
696         sc->sc_ch = timeout(ppp_timeout, (void *) sc, 1);
697         sc->sc_flags |= SC_TIMEOUT;
698     }
699
700     splx(s);
701 }
702
703 /*
704  * This gets called when a received packet is placed on
705  * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
706  */
707 static void
708 pppasyncctlp(sc)
709     struct ppp_softc *sc;
710 {
711     struct tty *tp;
712     int s;
713
714     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
715     s = spltty();
716     tp = (struct tty *) sc->sc_devp;
717     putc(0, &tp->t_canq);
718     ttwakeup(tp);
719     splx(s);
720 }
721
722 /*
723  * Start output on async tty interface.  If the transmit queue
724  * has drained sufficiently, arrange for pppasyncstart to be
725  * called later at splsoftnet.
726  * Called at spltty or higher.
727  */
728 static int
729 pppstart(tp)
730     register struct tty *tp;
731 {
732     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
733
734     /*
735      * Call output process whether or not there is any output.
736      * We are being called in lieu of ttstart and must do what it would.
737      */
738     tt_oproc(tp);
739
740     /*
741      * If the transmit queue has drained and the tty has not hung up
742      * or been disconnected from the ppp unit, then tell if_ppp.c that
743      * we need more output.
744      */
745     if (CCOUNT(&tp->t_outq) < PPP_LOWAT
746         && !((tp->t_state & TS_CONNECTED) == 0)
747         && sc != NULL) {
748         ppp_restart(sc);
749     }
750
751     return 0;
752 }
753
754 /*
755  * Timeout routine - try to start some more output.
756  */
757 static void
758 ppp_timeout(x)
759     void *x;
760 {
761     struct ppp_softc *sc = (struct ppp_softc *) x;
762     struct tty *tp = (struct tty *) sc->sc_devp;
763     int s;
764
765     s = spltty();
766     sc->sc_flags &= ~SC_TIMEOUT;
767     pppstart(tp);
768     splx(s);
769 }
770
771 /*
772  * Allocate enough mbuf to handle current MRU.
773  */
774 static void
775 pppgetm(sc)
776     register struct ppp_softc *sc;
777 {
778     struct mbuf *m, **mp;
779     int len;
780
781     mp = &sc->sc_m;
782     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
783         if ((m = *mp) == NULL) {
784             MGETHDR(m, M_DONTWAIT, MT_DATA);
785             if (m == NULL)
786                 break;
787             *mp = m;
788             MCLGET(m, M_DONTWAIT);
789         }
790         len -= M_DATASIZE(m);
791         mp = &m->m_next;
792     }
793 }
794
795 /*
796  * tty interface receiver interrupt.
797  */
798 static unsigned paritytab[8] = {
799     0x96696996, 0x69969669, 0x69969669, 0x96696996,
800     0x69969669, 0x96696996, 0x96696996, 0x69969669
801 };
802
803 /*
804  * Called when character is available from device driver.
805  * Only guaranteed to be at splsofttty() or spltty()
806  * This is safe to be called while the upper half's netisr is preempted.
807  */
808 static int
809 pppinput(c, tp)
810     int c;
811     register struct tty *tp;
812 {
813     register struct ppp_softc *sc;
814     struct mbuf *m;
815     int ilen, s;
816
817     sc = (struct ppp_softc *)tp->t_lsc;
818     if (sc == NULL)
819         return 0;
820
821     ++tk_nin;
822     ++sc->sc_stats.ppp_ibytes;
823
824     if ((tp->t_state & TS_CONNECTED) == 0) {
825         if (sc->sc_flags & SC_DEBUG)
826             if_printf(PPP2IFP(sc), "no carrier\n");
827         goto flush;
828     }
829
830     if (c & TTY_ERRORMASK) {
831         /* framing error or overrun on this char - abort packet */
832         if (sc->sc_flags & SC_DEBUG)
833             if_printf(PPP2IFP(sc), "line error %x\n", c & TTY_ERRORMASK);
834         goto flush;
835     }
836
837     c &= TTY_CHARMASK;
838
839     /*
840      * Handle software flow control of output.
841      */
842     if (tp->t_iflag & IXON) {
843         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
844             if ((tp->t_state & TS_TTSTOP) == 0) {
845                 tp->t_state |= TS_TTSTOP;
846                 tt_stop(tp, 0);
847             }
848             return 0;
849         }
850         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
851             tp->t_state &= ~TS_TTSTOP;
852             tt_oproc(tp);
853             return 0;
854         }
855     }
856
857     s = spltty();
858     if (c & 0x80)
859         sc->sc_flags |= SC_RCV_B7_1;
860     else
861         sc->sc_flags |= SC_RCV_B7_0;
862     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
863         sc->sc_flags |= SC_RCV_ODDP;
864     else
865         sc->sc_flags |= SC_RCV_EVNP;
866     splx(s);
867
868     if (sc->sc_flags & SC_LOG_RAWIN)
869         ppplogchar(sc, c);
870
871     if (c == PPP_FLAG) {
872         ilen = sc->sc_ilen;
873         sc->sc_ilen = 0;
874
875         if (sc->sc_rawin_count > 0) 
876             ppplogchar(sc, -1);
877
878         /*
879          * If SC_ESCAPED is set, then we've seen the packet
880          * abort sequence "}~".
881          */
882         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
883             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
884             s = spltty();
885             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
886             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
887                 if (sc->sc_flags & SC_DEBUG)
888                     if_printf(PPP2IFP(sc), "bad fcs %x, pkt len %d\n",
889                            sc->sc_fcs, ilen);
890                 PPP2IFP(sc)->if_ierrors++;
891                 sc->sc_stats.ppp_ierrors++;
892             } else
893                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
894             splx(s);
895             return 0;
896         }
897
898         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
899             if (ilen) {
900                 if (sc->sc_flags & SC_DEBUG)
901                     if_printf(PPP2IFP(sc), "too short (%d)\n", ilen);
902                 s = spltty();
903                 PPP2IFP(sc)->if_ierrors++;
904                 sc->sc_stats.ppp_ierrors++;
905                 sc->sc_flags |= SC_PKTLOST;
906                 splx(s);
907             }
908             return 0;
909         }
910
911         /*
912          * Remove FCS trailer.  Somewhat painful...
913          */
914         ilen -= 2;
915         if (--sc->sc_mc->m_len == 0) {
916             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
917                 ;
918             sc->sc_mc = m;
919         }
920         sc->sc_mc->m_len--;
921
922         /* excise this mbuf chain */
923         m = sc->sc_m;
924         sc->sc_m = sc->sc_mc->m_next;
925         sc->sc_mc->m_next = NULL;
926
927         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
928         if (sc->sc_flags & SC_PKTLOST) {
929             s = spltty();
930             sc->sc_flags &= ~SC_PKTLOST;
931             splx(s);
932         }
933
934         pppgetm(sc);
935         return 0;
936     }
937
938     if (sc->sc_flags & SC_FLUSH) {
939         if (sc->sc_flags & SC_LOG_FLUSH)
940             ppplogchar(sc, c);
941         return 0;
942     }
943
944     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
945         return 0;
946
947     s = spltty();
948     if (sc->sc_flags & SC_ESCAPED) {
949         sc->sc_flags &= ~SC_ESCAPED;
950         c ^= PPP_TRANS;
951     } else if (c == PPP_ESCAPE) {
952         sc->sc_flags |= SC_ESCAPED;
953         splx(s);
954         return 0;
955     }
956     splx(s);
957
958     /*
959      * Initialize buffer on first octet received.
960      * First octet could be address or protocol (when compressing
961      * address/control).
962      * Second octet is control.
963      * Third octet is first or second (when compressing protocol)
964      * octet of protocol.
965      * Fourth octet is second octet of protocol.
966      */
967     if (sc->sc_ilen == 0) {
968         /* reset the first input mbuf */
969         if (sc->sc_m == NULL) {
970             pppgetm(sc);
971             if (sc->sc_m == NULL) {
972                 if (sc->sc_flags & SC_DEBUG)
973                     if_printf(PPP2IFP(sc), "no input mbufs!\n");
974                 goto flush;
975             }
976         }
977         m = sc->sc_m;
978         m->m_len = 0;
979         m->m_data = M_DATASTART(sc->sc_m);
980         sc->sc_mc = m;
981         sc->sc_mp = mtod(m, char *);
982         sc->sc_fcs = PPP_INITFCS;
983         if (c != PPP_ALLSTATIONS) {
984             if (sc->sc_flags & SC_REJ_COMP_AC) {
985                 if (sc->sc_flags & SC_DEBUG)
986                     if_printf(PPP2IFP(sc),
987                               "garbage received: 0x%x (need 0xFF)\n", c);
988                 goto flush;
989             }
990             *sc->sc_mp++ = PPP_ALLSTATIONS;
991             *sc->sc_mp++ = PPP_UI;
992             sc->sc_ilen += 2;
993             m->m_len += 2;
994         }
995     }
996     if (sc->sc_ilen == 1 && c != PPP_UI) {
997         if (sc->sc_flags & SC_DEBUG)
998             if_printf(PPP2IFP(sc), "missing UI (0x3), got 0x%x\n", c);
999         goto flush;
1000     }
1001     if (sc->sc_ilen == 2 && (c & 1) == 1) {
1002         /* a compressed protocol */
1003         *sc->sc_mp++ = 0;
1004         sc->sc_ilen++;
1005         sc->sc_mc->m_len++;
1006     }
1007     if (sc->sc_ilen == 3 && (c & 1) == 0) {
1008         if (sc->sc_flags & SC_DEBUG)
1009             if_printf(PPP2IFP(sc), "bad protocol %x\n",
1010                       (sc->sc_mp[-1] << 8) + c);
1011         goto flush;
1012     }
1013
1014     /* packet beyond configured mru? */
1015     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1016         if (sc->sc_flags & SC_DEBUG)
1017             if_printf(PPP2IFP(sc), "packet too big\n");
1018         goto flush;
1019     }
1020
1021     /* is this mbuf full? */
1022     m = sc->sc_mc;
1023     if (M_TRAILINGSPACE(m) <= 0) {
1024         if (m->m_next == NULL) {
1025             pppgetm(sc);
1026             if (m->m_next == NULL) {
1027                 if (sc->sc_flags & SC_DEBUG)
1028                     if_printf(PPP2IFP(sc), "too few input mbufs!\n");
1029                 goto flush;
1030             }
1031         }
1032         sc->sc_mc = m = m->m_next;
1033         m->m_len = 0;
1034         m->m_data = M_DATASTART(m);
1035         sc->sc_mp = mtod(m, char *);
1036     }
1037
1038     ++m->m_len;
1039     *sc->sc_mp++ = c;
1040     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1041     return 0;
1042
1043  flush:
1044     if (!(sc->sc_flags & SC_FLUSH)) {
1045         s = spltty();
1046         PPP2IFP(sc)->if_ierrors++;
1047         sc->sc_stats.ppp_ierrors++;
1048         sc->sc_flags |= SC_FLUSH;
1049         splx(s);
1050         if (sc->sc_flags & SC_LOG_FLUSH)
1051             ppplogchar(sc, c);
1052     }
1053     return 0;
1054 }
1055
1056 #define MAX_DUMP_BYTES  128
1057
1058 static void
1059 ppplogchar(sc, c)
1060     struct ppp_softc *sc;
1061     int c;
1062 {
1063     if (c >= 0)
1064         sc->sc_rawin[sc->sc_rawin_count++] = c;
1065     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1066         || (c < 0 && sc->sc_rawin_count > 0)) {
1067         printf("%s input: %*D", PPP2IFP(sc)->if_xname,
1068                 sc->sc_rawin_count, sc->sc_rawin, " ");
1069         sc->sc_rawin_count = 0;
1070     }
1071 }