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