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