ppp_tty.c revision 1.17 1 /* $NetBSD: ppp_tty.c,v 1.17 1999/05/24 20:12:10 tron 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 #if NBPFILTER > 0
265 /* Change DLT to back none. */
266 bpf_change_type(&sc->sc_bpf, DLT_NULL, 0);
267 #endif
268
269 s = spltty();
270 if (sc->sc_outm) {
271 m_freem(sc->sc_outm);
272 sc->sc_outm = NULL;
273 }
274 if (sc->sc_m) {
275 m_freem(sc->sc_m);
276 sc->sc_m = NULL;
277 }
278 if (sc->sc_flags & SC_TIMEOUT) {
279 untimeout(ppp_timeout, (void *) sc);
280 sc->sc_flags &= ~SC_TIMEOUT;
281 }
282 splx(s);
283 }
284
285 /*
286 * Line specific (tty) read routine.
287 */
288 int
289 pppread(tp, uio, flag)
290 register struct tty *tp;
291 struct uio *uio;
292 int flag;
293 {
294 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
295 struct mbuf *m, *m0;
296 register int s;
297 int error = 0;
298
299 if (sc == NULL)
300 return 0;
301 /*
302 * Loop waiting for input, checking that nothing disasterous
303 * happens in the meantime.
304 */
305 s = spltty();
306 for (;;) {
307 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
308 splx(s);
309 return 0;
310 }
311 if (sc->sc_inq.ifq_head != NULL)
312 break;
313 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
314 && (tp->t_state & TS_ISOPEN)) {
315 splx(s);
316 return 0; /* end of file */
317 }
318 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
319 splx(s);
320 return (EWOULDBLOCK);
321 }
322 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
323 if (error) {
324 splx(s);
325 return error;
326 }
327 }
328
329 /* Pull place-holder byte out of canonical queue */
330 getc(&tp->t_canq);
331
332 /* Get the packet from the input queue */
333 IF_DEQUEUE(&sc->sc_inq, m0);
334 splx(s);
335
336 for (m = m0; m && uio->uio_resid; m = m->m_next)
337 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
338 break;
339 m_freem(m0);
340 return (error);
341 }
342
343 /*
344 * Line specific (tty) write routine.
345 */
346 int
347 pppwrite(tp, uio, flag)
348 register struct tty *tp;
349 struct uio *uio;
350 int flag;
351 {
352 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
353 struct mbuf *m, *m0, **mp;
354 struct sockaddr dst;
355 int len, error;
356
357 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
358 return 0; /* wrote 0 bytes */
359 if (tp->t_line != PPPDISC)
360 return (EINVAL);
361 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
362 return EIO;
363 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
364 uio->uio_resid < PPP_HDRLEN)
365 return (EMSGSIZE);
366 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
367 MGET(m, M_WAIT, MT_DATA);
368 if ((*mp = m) == NULL) {
369 m_freem(m0);
370 return (ENOBUFS);
371 }
372 m->m_len = 0;
373 if (uio->uio_resid >= MCLBYTES / 2)
374 MCLGET(m, M_DONTWAIT);
375 len = M_TRAILINGSPACE(m);
376 if (len > uio->uio_resid)
377 len = uio->uio_resid;
378 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
379 m_freem(m0);
380 return (error);
381 }
382 m->m_len = len;
383 }
384 dst.sa_family = AF_UNSPEC;
385 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
386 m0->m_data += PPP_HDRLEN;
387 m0->m_len -= PPP_HDRLEN;
388 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
389 }
390
391 /*
392 * Line specific (tty) ioctl routine.
393 * This discipline requires that tty device drivers call
394 * the line specific l_ioctl routine from their ioctl routines.
395 */
396 /* ARGSUSED */
397 int
398 ppptioctl(tp, cmd, data, flag, p)
399 struct tty *tp;
400 u_long cmd;
401 caddr_t data;
402 int flag;
403 struct proc *p;
404 {
405 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
406 int error, s;
407
408 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
409 return -1;
410
411 error = 0;
412 switch (cmd) {
413 case PPPIOCSASYNCMAP:
414 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
415 break;
416 sc->sc_asyncmap[0] = *(u_int *)data;
417 break;
418
419 case PPPIOCGASYNCMAP:
420 *(u_int *)data = sc->sc_asyncmap[0];
421 break;
422
423 case PPPIOCSRASYNCMAP:
424 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
425 break;
426 sc->sc_rasyncmap = *(u_int *)data;
427 break;
428
429 case PPPIOCGRASYNCMAP:
430 *(u_int *)data = sc->sc_rasyncmap;
431 break;
432
433 case PPPIOCSXASYNCMAP:
434 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
435 break;
436 s = spltty();
437 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
438 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
439 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
440 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
441 splx(s);
442 break;
443
444 case PPPIOCGXASYNCMAP:
445 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
446 break;
447
448 default:
449 error = pppioctl(sc, cmd, data, flag, p);
450 if (error == 0 && cmd == PPPIOCSMRU)
451 pppgetm(sc);
452 }
453
454 return error;
455 }
456
457 /*
458 * FCS lookup table as calculated by genfcstab.
459 */
460 static u_int16_t fcstab[256] = {
461 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
462 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
463 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
464 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
465 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
466 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
467 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
468 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
469 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
470 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
471 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
472 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
473 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
474 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
475 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
476 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
477 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
478 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
479 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
480 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
481 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
482 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
483 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
484 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
485 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
486 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
487 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
488 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
489 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
490 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
491 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
492 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
493 };
494
495 /*
496 * Calculate a new FCS given the current FCS and the new data.
497 */
498 static u_int16_t
499 pppfcs(fcs, cp, len)
500 register u_int16_t fcs;
501 register u_char *cp;
502 register int len;
503 {
504 while (len--)
505 fcs = PPP_FCS(fcs, *cp++);
506 return (fcs);
507 }
508
509 /*
510 * This gets called at splsoftnet from if_ppp.c at various times
511 * when there is data ready to be sent.
512 */
513 static void
514 pppasyncstart(sc)
515 register struct ppp_softc *sc;
516 {
517 register struct tty *tp = (struct tty *) sc->sc_devp;
518 register struct mbuf *m;
519 register int len;
520 register u_char *start, *stop, *cp;
521 int n, ndone, done, idle;
522 struct mbuf *m2;
523 int s;
524
525 idle = 0;
526 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
527 /*
528 * See if we have an existing packet partly sent.
529 * If not, get a new packet and start sending it.
530 */
531 m = sc->sc_outm;
532 if (m == NULL) {
533 /*
534 * Get another packet to be sent.
535 */
536 m = ppp_dequeue(sc);
537 if (m == NULL) {
538 idle = 1;
539 break;
540 }
541
542 /*
543 * The extra PPP_FLAG will start up a new packet, and thus
544 * will flush any accumulated garbage. We do this whenever
545 * the line may have been idle for some time.
546 */
547 if (CCOUNT(&tp->t_outq) == 0) {
548 ++sc->sc_stats.ppp_obytes;
549 (void) putc(PPP_FLAG, &tp->t_outq);
550 }
551
552 /* Calculate the FCS for the first mbuf's worth. */
553 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
554 sc->sc_if.if_lastchange = time;
555 }
556
557 for (;;) {
558 start = mtod(m, u_char *);
559 len = m->m_len;
560 stop = start + len;
561 while (len > 0) {
562 /*
563 * Find out how many bytes in the string we can
564 * handle without doing something special.
565 */
566 for (cp = start; cp < stop; cp++)
567 if (ESCAPE_P(*cp))
568 break;
569 n = cp - start;
570 if (n) {
571 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
572 ndone = n - b_to_q(start, n, &tp->t_outq);
573 len -= ndone;
574 start += ndone;
575 sc->sc_stats.ppp_obytes += ndone;
576
577 if (ndone < n)
578 break; /* packet doesn't fit */
579 }
580 /*
581 * If there are characters left in the mbuf,
582 * the first one must be special.
583 * Put it out in a different form.
584 */
585 if (len) {
586 s = spltty();
587 if (putc(PPP_ESCAPE, &tp->t_outq)) {
588 splx(s);
589 break;
590 }
591 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
592 (void) unputc(&tp->t_outq);
593 splx(s);
594 break;
595 }
596 splx(s);
597 sc->sc_stats.ppp_obytes += 2;
598 start++;
599 len--;
600 }
601 }
602
603 /*
604 * If we didn't empty this mbuf, remember where we're up to.
605 * If we emptied the last mbuf, try to add the FCS and closing
606 * flag, and if we can't, leave sc_outm pointing to m, but with
607 * m->m_len == 0, to remind us to output the FCS and flag later.
608 */
609 done = len == 0;
610 if (done && m->m_next == NULL) {
611 u_char *p, *q;
612 int c;
613 u_char endseq[8];
614
615 /*
616 * We may have to escape the bytes in the FCS.
617 */
618 p = endseq;
619 c = ~sc->sc_outfcs & 0xFF;
620 if (ESCAPE_P(c)) {
621 *p++ = PPP_ESCAPE;
622 *p++ = c ^ PPP_TRANS;
623 } else
624 *p++ = c;
625 c = (~sc->sc_outfcs >> 8) & 0xFF;
626 if (ESCAPE_P(c)) {
627 *p++ = PPP_ESCAPE;
628 *p++ = c ^ PPP_TRANS;
629 } else
630 *p++ = c;
631 *p++ = PPP_FLAG;
632
633 /*
634 * Try to output the FCS and flag. If the bytes
635 * don't all fit, back out.
636 */
637 s = spltty();
638 for (q = endseq; q < p; ++q)
639 if (putc(*q, &tp->t_outq)) {
640 done = 0;
641 for (; q > endseq; --q)
642 unputc(&tp->t_outq);
643 break;
644 }
645 splx(s);
646 if (done)
647 sc->sc_stats.ppp_obytes += q - endseq;
648 }
649
650 if (!done) {
651 /* remember where we got to */
652 m->m_data = start;
653 m->m_len = len;
654 break;
655 }
656
657 /* Finished with this mbuf; free it and move on. */
658 MFREE(m, m2);
659 m = m2;
660 if (m == NULL) {
661 /* Finished a packet */
662 break;
663 }
664 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
665 }
666
667 /*
668 * If m == NULL, we have finished a packet.
669 * If m != NULL, we've either done as much work this time
670 * as we need to, or else we've filled up the output queue.
671 */
672 sc->sc_outm = m;
673 if (m)
674 break;
675 }
676
677 /* Call pppstart to start output again if necessary. */
678 s = spltty();
679 pppstart(tp);
680
681 /*
682 * This timeout is needed for operation on a pseudo-tty,
683 * because the pty code doesn't call pppstart after it has
684 * drained the t_outq.
685 */
686 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
687 timeout(ppp_timeout, (void *) sc, 1);
688 sc->sc_flags |= SC_TIMEOUT;
689 }
690
691 splx(s);
692 }
693
694 /*
695 * This gets called when a received packet is placed on
696 * the inq, at splsoftnet.
697 */
698 static void
699 pppasyncctlp(sc)
700 struct ppp_softc *sc;
701 {
702 struct tty *tp;
703 int s;
704
705 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
706 s = spltty();
707 tp = (struct tty *) sc->sc_devp;
708 putc(0, &tp->t_canq);
709 ttwakeup(tp);
710 splx(s);
711 }
712
713 /*
714 * Start output on async tty interface. If the transmit queue
715 * has drained sufficiently, arrange for pppasyncstart to be
716 * called later at splsoftnet.
717 * Called at spltty or higher.
718 */
719 int
720 pppstart(tp)
721 register struct tty *tp;
722 {
723 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
724
725 /*
726 * If there is stuff in the output queue, send it now.
727 * We are being called in lieu of ttstart and must do what it would.
728 */
729 if (tp->t_oproc != NULL)
730 (*tp->t_oproc)(tp);
731
732 /*
733 * If the transmit queue has drained and the tty has not hung up
734 * or been disconnected from the ppp unit, then tell if_ppp.c that
735 * we need more output.
736 */
737 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
738 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
739 return 0;
740 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
741 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
742 ppp_restart(sc);
743 }
744
745 return 0;
746 }
747
748 /*
749 * Timeout routine - try to start some more output.
750 */
751 static void
752 ppp_timeout(x)
753 void *x;
754 {
755 struct ppp_softc *sc = (struct ppp_softc *) x;
756 struct tty *tp = (struct tty *) sc->sc_devp;
757 int s;
758
759 s = spltty();
760 sc->sc_flags &= ~SC_TIMEOUT;
761 pppstart(tp);
762 splx(s);
763 }
764
765 /*
766 * Allocate enough mbuf to handle current MRU.
767 */
768 static void
769 pppgetm(sc)
770 register struct ppp_softc *sc;
771 {
772 struct mbuf *m, **mp;
773 int len;
774
775 mp = &sc->sc_m;
776 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
777 if ((m = *mp) == NULL) {
778 MGETHDR(m, M_DONTWAIT, MT_DATA);
779 if (m == NULL)
780 break;
781 *mp = m;
782 MCLGET(m, M_DONTWAIT);
783 }
784 len -= M_DATASIZE(m);
785 mp = &m->m_next;
786 }
787 }
788
789 /*
790 * tty interface receiver interrupt.
791 */
792 static unsigned paritytab[8] = {
793 0x96696996, 0x69969669, 0x69969669, 0x96696996,
794 0x69969669, 0x96696996, 0x96696996, 0x69969669
795 };
796
797 int
798 pppinput(c, tp)
799 int c;
800 register struct tty *tp;
801 {
802 register struct ppp_softc *sc;
803 struct mbuf *m;
804 int ilen, s;
805
806 sc = (struct ppp_softc *) tp->t_sc;
807 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
808 return 0;
809
810 ++tk_nin;
811 ++sc->sc_stats.ppp_ibytes;
812
813 if (c & TTY_FE) {
814 /* framing error or overrun on this char - abort packet */
815 if (sc->sc_flags & SC_DEBUG)
816 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
817 goto flush;
818 }
819
820 c &= 0xff;
821
822 /*
823 * Handle software flow control of output.
824 */
825 if (tp->t_iflag & IXON) {
826 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
827 if ((tp->t_state & TS_TTSTOP) == 0) {
828 tp->t_state |= TS_TTSTOP;
829 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
830 }
831 return 0;
832 }
833 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
834 tp->t_state &= ~TS_TTSTOP;
835 if (tp->t_oproc != NULL)
836 (*tp->t_oproc)(tp);
837 return 0;
838 }
839 }
840
841 s = spltty();
842 if (c & 0x80)
843 sc->sc_flags |= SC_RCV_B7_1;
844 else
845 sc->sc_flags |= SC_RCV_B7_0;
846 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
847 sc->sc_flags |= SC_RCV_ODDP;
848 else
849 sc->sc_flags |= SC_RCV_EVNP;
850 splx(s);
851
852 if (sc->sc_flags & SC_LOG_RAWIN)
853 ppplogchar(sc, c);
854
855 if (c == PPP_FLAG) {
856 ilen = sc->sc_ilen;
857 sc->sc_ilen = 0;
858
859 if (sc->sc_rawin_count > 0)
860 ppplogchar(sc, -1);
861
862 /*
863 * If SC_ESCAPED is set, then we've seen the packet
864 * abort sequence "}~".
865 */
866 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
867 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
868 s = spltty();
869 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
870 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
871 if (sc->sc_flags & SC_DEBUG)
872 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
873 sc->sc_fcs);
874 sc->sc_if.if_ierrors++;
875 sc->sc_stats.ppp_ierrors++;
876 } else
877 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
878 splx(s);
879 return 0;
880 }
881
882 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
883 if (ilen) {
884 if (sc->sc_flags & SC_DEBUG)
885 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
886 s = spltty();
887 sc->sc_if.if_ierrors++;
888 sc->sc_stats.ppp_ierrors++;
889 sc->sc_flags |= SC_PKTLOST;
890 splx(s);
891 }
892 return 0;
893 }
894
895 /*
896 * Remove FCS trailer. Somewhat painful...
897 */
898 ilen -= 2;
899 if (--sc->sc_mc->m_len == 0) {
900 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
901 ;
902 sc->sc_mc = m;
903 }
904 sc->sc_mc->m_len--;
905
906 /* excise this mbuf chain */
907 m = sc->sc_m;
908 sc->sc_m = sc->sc_mc->m_next;
909 sc->sc_mc->m_next = NULL;
910
911 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
912 if (sc->sc_flags & SC_PKTLOST) {
913 s = spltty();
914 sc->sc_flags &= ~SC_PKTLOST;
915 splx(s);
916 }
917
918 pppgetm(sc);
919 return 0;
920 }
921
922 if (sc->sc_flags & SC_FLUSH) {
923 if (sc->sc_flags & SC_LOG_FLUSH)
924 ppplogchar(sc, c);
925 return 0;
926 }
927
928 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
929 return 0;
930
931 s = spltty();
932 if (sc->sc_flags & SC_ESCAPED) {
933 sc->sc_flags &= ~SC_ESCAPED;
934 c ^= PPP_TRANS;
935 } else if (c == PPP_ESCAPE) {
936 sc->sc_flags |= SC_ESCAPED;
937 splx(s);
938 return 0;
939 }
940 splx(s);
941
942 /*
943 * Initialize buffer on first octet received.
944 * First octet could be address or protocol (when compressing
945 * address/control).
946 * Second octet is control.
947 * Third octet is first or second (when compressing protocol)
948 * octet of protocol.
949 * Fourth octet is second octet of protocol.
950 */
951 if (sc->sc_ilen == 0) {
952 /* reset the first input mbuf */
953 if (sc->sc_m == NULL) {
954 pppgetm(sc);
955 if (sc->sc_m == NULL) {
956 if (sc->sc_flags & SC_DEBUG)
957 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
958 goto flush;
959 }
960 }
961 m = sc->sc_m;
962 m->m_len = 0;
963 m->m_data = M_DATASTART(sc->sc_m);
964 sc->sc_mc = m;
965 sc->sc_mp = mtod(m, char *);
966 sc->sc_fcs = PPP_INITFCS;
967 if (c != PPP_ALLSTATIONS) {
968 if (sc->sc_flags & SC_REJ_COMP_AC) {
969 if (sc->sc_flags & SC_DEBUG)
970 printf("%s: garbage received: 0x%x (need 0xFF)\n",
971 sc->sc_if.if_xname, c);
972 goto flush;
973 }
974 *sc->sc_mp++ = PPP_ALLSTATIONS;
975 *sc->sc_mp++ = PPP_UI;
976 sc->sc_ilen += 2;
977 m->m_len += 2;
978 }
979 }
980 if (sc->sc_ilen == 1 && c != PPP_UI) {
981 if (sc->sc_flags & SC_DEBUG)
982 printf("%s: missing UI (0x3), got 0x%x\n",
983 sc->sc_if.if_xname, c);
984 goto flush;
985 }
986 if (sc->sc_ilen == 2 && (c & 1) == 1) {
987 /* a compressed protocol */
988 *sc->sc_mp++ = 0;
989 sc->sc_ilen++;
990 sc->sc_mc->m_len++;
991 }
992 if (sc->sc_ilen == 3 && (c & 1) == 0) {
993 if (sc->sc_flags & SC_DEBUG)
994 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
995 (sc->sc_mp[-1] << 8) + c);
996 goto flush;
997 }
998
999 /* packet beyond configured mru? */
1000 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1001 if (sc->sc_flags & SC_DEBUG)
1002 printf("%s: packet too big\n", sc->sc_if.if_xname);
1003 goto flush;
1004 }
1005
1006 /* is this mbuf full? */
1007 m = sc->sc_mc;
1008 if (M_TRAILINGSPACE(m) <= 0) {
1009 if (m->m_next == NULL) {
1010 pppgetm(sc);
1011 if (m->m_next == NULL) {
1012 if (sc->sc_flags & SC_DEBUG)
1013 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1014 goto flush;
1015 }
1016 }
1017 sc->sc_mc = m = m->m_next;
1018 m->m_len = 0;
1019 m->m_data = M_DATASTART(m);
1020 sc->sc_mp = mtod(m, char *);
1021 }
1022
1023 ++m->m_len;
1024 *sc->sc_mp++ = c;
1025 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1026 return 0;
1027
1028 flush:
1029 if (!(sc->sc_flags & SC_FLUSH)) {
1030 s = spltty();
1031 sc->sc_if.if_ierrors++;
1032 sc->sc_stats.ppp_ierrors++;
1033 sc->sc_flags |= SC_FLUSH;
1034 splx(s);
1035 if (sc->sc_flags & SC_LOG_FLUSH)
1036 ppplogchar(sc, c);
1037 }
1038 return 0;
1039 }
1040
1041 #define MAX_DUMP_BYTES 128
1042
1043 static void
1044 ppplogchar(sc, c)
1045 struct ppp_softc *sc;
1046 int c;
1047 {
1048 if (c >= 0)
1049 sc->sc_rawin[sc->sc_rawin_count++] = c;
1050 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1051 || (c < 0 && sc->sc_rawin_count > 0)) {
1052 printf("%s input: ", sc->sc_if.if_xname);
1053 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1054 sc->sc_rawin_count = 0;
1055 }
1056 }
1057
1058 static void
1059 pppdumpb(b, l)
1060 u_char *b;
1061 int l;
1062 {
1063 char buf[3*MAX_DUMP_BYTES+4];
1064 char *bp = buf;
1065 static char digits[] = "0123456789abcdef";
1066
1067 while (l--) {
1068 if (bp >= buf + sizeof(buf) - 3) {
1069 *bp++ = '>';
1070 break;
1071 }
1072 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1073 *bp++ = digits[*b++ & 0xf];
1074 *bp++ = ' ';
1075 }
1076
1077 *bp = 0;
1078 printf("%s\n", buf);
1079 }
1080
1081 #endif /* NPPP > 0 */
1082