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