ppp_tty.c revision 1.14.4.1 1 /* $NetBSD: ppp_tty.c,v 1.14.4.1 1998/12/11 04:53:06 kenh 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 #define VJC
83 #define PPP_COMPRESS
84
85 #include <sys/param.h>
86 #include <sys/proc.h>
87 #include <sys/mbuf.h>
88 #include <sys/dkstat.h>
89 #include <sys/socket.h>
90 #include <sys/ioctl.h>
91 #include <sys/file.h>
92 #include <sys/tty.h>
93 #include <sys/kernel.h>
94 #include <sys/conf.h>
95 #include <sys/vnode.h>
96 #include <sys/systm.h>
97
98 #include <net/if.h>
99 #include <net/if_types.h>
100
101 #ifdef VJC
102 #include <netinet/in.h>
103 #include <netinet/in_systm.h>
104 #include <netinet/ip.h>
105 #include <net/slcompress.h>
106 #endif
107
108 #ifdef PPP_FILTER
109 #include <net/bpf.h>
110 #endif
111 #include <net/ppp_defs.h>
112 #include <net/if_ppp.h>
113 #include <net/if_pppvar.h>
114
115 int pppopen __P((dev_t dev, struct tty *tp));
116 int pppclose __P((struct tty *tp, int flag));
117 int pppread __P((struct tty *tp, struct uio *uio, int flag));
118 int pppwrite __P((struct tty *tp, struct uio *uio, int flag));
119 int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
120 struct proc *));
121 int pppinput __P((int c, struct tty *tp));
122 int pppstart __P((struct tty *tp));
123
124 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
125 static void pppasyncstart __P((struct ppp_softc *));
126 static void pppasyncctlp __P((struct ppp_softc *));
127 static void pppasyncrelinq __P((struct ppp_softc *));
128 static void ppp_timeout __P((void *));
129 static void pppgetm __P((struct ppp_softc *sc));
130 static void pppdumpb __P((u_char *b, int l));
131 static void ppplogchar __P((struct ppp_softc *, int));
132
133 /*
134 * Some useful mbuf macros not in mbuf.h.
135 */
136 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
137
138 #define M_DATASTART(m) \
139 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
140 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
141
142 #define M_DATASIZE(m) \
143 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
144 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
145
146 /*
147 * Does c need to be escaped?
148 */
149 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
150
151 /*
152 * Procedures for using an async tty interface for PPP.
153 */
154
155 /* This is a NetBSD-1.0 or later kernel. */
156 #define CCOUNT(q) ((q)->c_cc)
157
158 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */
159 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
160
161 /*
162 * Line specific open routine for async tty devices.
163 * Attach the given tty to the first available ppp unit.
164 * Called from device open routine or ttioctl.
165 */
166 /* ARGSUSED */
167 int
168 pppopen(dev, tp)
169 dev_t dev;
170 register struct tty *tp;
171 {
172 struct proc *p = curproc; /* XXX */
173 register struct ppp_softc *sc;
174 int error, s;
175
176 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
177 return (error);
178
179 s = spltty();
180
181 if (tp->t_line == PPPDISC) {
182 sc = (struct ppp_softc *) tp->t_sc;
183 if (sc != NULL && sc->sc_devp == (void *) tp) {
184 splx(s);
185 return (0);
186 }
187 }
188
189 if ((sc = pppalloc(p->p_pid)) == NULL) {
190 splx(s);
191 return ENXIO;
192 }
193
194 if (sc->sc_relinq)
195 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
196
197 sc->sc_ilen = 0;
198 sc->sc_m = NULL;
199 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
200 sc->sc_asyncmap[0] = 0xffffffff;
201 sc->sc_asyncmap[3] = 0x60000000;
202 sc->sc_rasyncmap = 0;
203 sc->sc_devp = (void *) tp;
204 sc->sc_start = pppasyncstart;
205 sc->sc_ctlp = pppasyncctlp;
206 sc->sc_relinq = pppasyncrelinq;
207 sc->sc_outm = NULL;
208 pppgetm(sc);
209 #ifdef _HAS_IF_ALLOC
210 sc->sc_if->if_flags |= IFF_RUNNING;
211 sc->sc_if->if_baudrate = tp->t_ospeed;
212 #else
213 sc->sc_if.if_flags |= IFF_RUNNING;
214 sc->sc_if.if_baudrate = tp->t_ospeed;
215 #endif
216
217 tp->t_sc = (caddr_t) sc;
218 ttyflush(tp, FREAD | FWRITE);
219
220 splx(s);
221 return (0);
222 }
223
224 /*
225 * Line specific close routine, called from device close routine
226 * and from ttioctl.
227 * Detach the tty from the ppp unit.
228 * Mimics part of ttyclose().
229 */
230 int
231 pppclose(tp, flag)
232 struct tty *tp;
233 int flag;
234 {
235 register struct ppp_softc *sc;
236 int s;
237
238 s = spltty();
239 ttyflush(tp, FREAD|FWRITE);
240 tp->t_line = 0;
241 sc = (struct ppp_softc *) tp->t_sc;
242 if (sc != NULL) {
243 tp->t_sc = NULL;
244 if (tp == (struct tty *) sc->sc_devp) {
245 pppasyncrelinq(sc);
246 pppdealloc(sc);
247 }
248 }
249 splx(s);
250 return 0;
251 }
252
253 /*
254 * Relinquish the interface unit to another device.
255 */
256 static void
257 pppasyncrelinq(sc)
258 struct ppp_softc *sc;
259 {
260 int s;
261
262 s = spltty();
263 if (sc->sc_outm) {
264 m_freem(sc->sc_outm);
265 sc->sc_outm = NULL;
266 }
267 if (sc->sc_m) {
268 m_freem(sc->sc_m);
269 sc->sc_m = NULL;
270 }
271 if (sc->sc_flags & SC_TIMEOUT) {
272 untimeout(ppp_timeout, (void *) sc);
273 sc->sc_flags &= ~SC_TIMEOUT;
274 }
275 splx(s);
276 }
277
278 /*
279 * Line specific (tty) read routine.
280 */
281 int
282 pppread(tp, uio, flag)
283 register struct tty *tp;
284 struct uio *uio;
285 int flag;
286 {
287 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
288 struct mbuf *m, *m0;
289 register int s;
290 int error = 0;
291
292 if (sc == NULL)
293 return 0;
294 /*
295 * Loop waiting for input, checking that nothing disasterous
296 * happens in the meantime.
297 */
298 s = spltty();
299 for (;;) {
300 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
301 splx(s);
302 return 0;
303 }
304 if (sc->sc_inq.ifq_head != NULL)
305 break;
306 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
307 && (tp->t_state & TS_ISOPEN)) {
308 splx(s);
309 return 0; /* end of file */
310 }
311 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
312 splx(s);
313 return (EWOULDBLOCK);
314 }
315 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
316 if (error) {
317 splx(s);
318 return error;
319 }
320 }
321
322 /* Pull place-holder byte out of canonical queue */
323 getc(&tp->t_canq);
324
325 /* Get the packet from the input queue */
326 IF_DEQUEUE(&sc->sc_inq, m0);
327 splx(s);
328
329 for (m = m0; m && uio->uio_resid; m = m->m_next)
330 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
331 break;
332 m_freem(m0);
333 return (error);
334 }
335
336 /*
337 * Line specific (tty) write routine.
338 */
339 int
340 pppwrite(tp, uio, flag)
341 register struct tty *tp;
342 struct uio *uio;
343 int flag;
344 {
345 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
346 #ifdef _HAS_IF_ALLOC
347 struct ifnet *ifp = sc->sc_if;
348 #else
349 struct ifnet *ifp = &sc->sc_if;
350 #endif
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 > ifp->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 ((*ifp->if_output)(ifp, 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 #ifdef _HAS_IF_ALLOC
553 sc->sc_if->if_lastchange = time;
554 #else
555 sc->sc_if.if_lastchange = time;
556 #endif
557 }
558
559 for (;;) {
560 start = mtod(m, u_char *);
561 len = m->m_len;
562 stop = start + len;
563 while (len > 0) {
564 /*
565 * Find out how many bytes in the string we can
566 * handle without doing something special.
567 */
568 for (cp = start; cp < stop; cp++)
569 if (ESCAPE_P(*cp))
570 break;
571 n = cp - start;
572 if (n) {
573 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
574 ndone = n - b_to_q(start, n, &tp->t_outq);
575 len -= ndone;
576 start += ndone;
577 sc->sc_stats.ppp_obytes += ndone;
578
579 if (ndone < n)
580 break; /* packet doesn't fit */
581 }
582 /*
583 * If there are characters left in the mbuf,
584 * the first one must be special.
585 * Put it out in a different form.
586 */
587 if (len) {
588 s = spltty();
589 if (putc(PPP_ESCAPE, &tp->t_outq)) {
590 splx(s);
591 break;
592 }
593 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
594 (void) unputc(&tp->t_outq);
595 splx(s);
596 break;
597 }
598 splx(s);
599 sc->sc_stats.ppp_obytes += 2;
600 start++;
601 len--;
602 }
603 }
604
605 /*
606 * If we didn't empty this mbuf, remember where we're up to.
607 * If we emptied the last mbuf, try to add the FCS and closing
608 * flag, and if we can't, leave sc_outm pointing to m, but with
609 * m->m_len == 0, to remind us to output the FCS and flag later.
610 */
611 done = len == 0;
612 if (done && m->m_next == NULL) {
613 u_char *p, *q;
614 int c;
615 u_char endseq[8];
616
617 /*
618 * We may have to escape the bytes in the FCS.
619 */
620 p = endseq;
621 c = ~sc->sc_outfcs & 0xFF;
622 if (ESCAPE_P(c)) {
623 *p++ = PPP_ESCAPE;
624 *p++ = c ^ PPP_TRANS;
625 } else
626 *p++ = c;
627 c = (~sc->sc_outfcs >> 8) & 0xFF;
628 if (ESCAPE_P(c)) {
629 *p++ = PPP_ESCAPE;
630 *p++ = c ^ PPP_TRANS;
631 } else
632 *p++ = c;
633 *p++ = PPP_FLAG;
634
635 /*
636 * Try to output the FCS and flag. If the bytes
637 * don't all fit, back out.
638 */
639 s = spltty();
640 for (q = endseq; q < p; ++q)
641 if (putc(*q, &tp->t_outq)) {
642 done = 0;
643 for (; q > endseq; --q)
644 unputc(&tp->t_outq);
645 break;
646 }
647 splx(s);
648 if (done)
649 sc->sc_stats.ppp_obytes += q - endseq;
650 }
651
652 if (!done) {
653 /* remember where we got to */
654 m->m_data = start;
655 m->m_len = len;
656 break;
657 }
658
659 /* Finished with this mbuf; free it and move on. */
660 MFREE(m, m2);
661 m = m2;
662 if (m == NULL) {
663 /* Finished a packet */
664 break;
665 }
666 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
667 }
668
669 /*
670 * If m == NULL, we have finished a packet.
671 * If m != NULL, we've either done as much work this time
672 * as we need to, or else we've filled up the output queue.
673 */
674 sc->sc_outm = m;
675 if (m)
676 break;
677 }
678
679 /* Call pppstart to start output again if necessary. */
680 s = spltty();
681 pppstart(tp);
682
683 /*
684 * This timeout is needed for operation on a pseudo-tty,
685 * because the pty code doesn't call pppstart after it has
686 * drained the t_outq.
687 */
688 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
689 timeout(ppp_timeout, (void *) sc, 1);
690 sc->sc_flags |= SC_TIMEOUT;
691 }
692
693 splx(s);
694 }
695
696 /*
697 * This gets called when a received packet is placed on
698 * the inq, at splsoftnet.
699 */
700 static void
701 pppasyncctlp(sc)
702 struct ppp_softc *sc;
703 {
704 struct tty *tp;
705 int s;
706
707 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
708 s = spltty();
709 tp = (struct tty *) sc->sc_devp;
710 putc(0, &tp->t_canq);
711 ttwakeup(tp);
712 splx(s);
713 }
714
715 /*
716 * Start output on async tty interface. If the transmit queue
717 * has drained sufficiently, arrange for pppasyncstart to be
718 * called later at splsoftnet.
719 * Called at spltty or higher.
720 */
721 int
722 pppstart(tp)
723 register struct tty *tp;
724 {
725 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
726
727 /*
728 * If there is stuff in the output queue, send it now.
729 * We are being called in lieu of ttstart and must do what it would.
730 */
731 if (tp->t_oproc != NULL)
732 (*tp->t_oproc)(tp);
733
734 /*
735 * If the transmit queue has drained and the tty has not hung up
736 * or been disconnected from the ppp unit, then tell if_ppp.c that
737 * we need more output.
738 */
739 if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
740 && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
741 return 0;
742 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
743 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
744 ppp_restart(sc);
745 }
746
747 return 0;
748 }
749
750 /*
751 * Timeout routine - try to start some more output.
752 */
753 static void
754 ppp_timeout(x)
755 void *x;
756 {
757 struct ppp_softc *sc = (struct ppp_softc *) x;
758 struct tty *tp = (struct tty *) sc->sc_devp;
759 int s;
760
761 s = spltty();
762 sc->sc_flags &= ~SC_TIMEOUT;
763 pppstart(tp);
764 splx(s);
765 }
766
767 /*
768 * Allocate enough mbuf to handle current MRU.
769 */
770 static void
771 pppgetm(sc)
772 register struct ppp_softc *sc;
773 {
774 struct mbuf *m, **mp;
775 int len;
776
777 mp = &sc->sc_m;
778 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
779 if ((m = *mp) == NULL) {
780 MGETHDR(m, M_DONTWAIT, MT_DATA);
781 if (m == NULL)
782 break;
783 *mp = m;
784 MCLGET(m, M_DONTWAIT);
785 }
786 len -= M_DATASIZE(m);
787 mp = &m->m_next;
788 }
789 }
790
791 /*
792 * tty interface receiver interrupt.
793 */
794 static unsigned paritytab[8] = {
795 0x96696996, 0x69969669, 0x69969669, 0x96696996,
796 0x69969669, 0x96696996, 0x96696996, 0x69969669
797 };
798
799 int
800 pppinput(c, tp)
801 int c;
802 register struct tty *tp;
803 {
804 register struct ppp_softc *sc;
805 register struct ifnet *ifp;
806 struct mbuf *m;
807 int ilen, s;
808
809 sc = (struct ppp_softc *) tp->t_sc;
810 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
811 return 0;
812
813 #ifdef _HAS_IF_ALLOC
814 ifp = sc->sc_if;
815 #else
816 ifp = &sc->sc_if;
817 #endif
818
819 ++tk_nin;
820 ++sc->sc_stats.ppp_ibytes;
821
822 if (c & TTY_FE) {
823 /* framing error or overrun on this char - abort packet */
824 if (sc->sc_flags & SC_DEBUG)
825 printf("%s: bad char %x\n", ifp->if_xname, c);
826 goto flush;
827 }
828
829 c &= 0xff;
830
831 /*
832 * Handle software flow control of output.
833 */
834 if (tp->t_iflag & IXON) {
835 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
836 if ((tp->t_state & TS_TTSTOP) == 0) {
837 tp->t_state |= TS_TTSTOP;
838 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
839 }
840 return 0;
841 }
842 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
843 tp->t_state &= ~TS_TTSTOP;
844 if (tp->t_oproc != NULL)
845 (*tp->t_oproc)(tp);
846 return 0;
847 }
848 }
849
850 s = spltty();
851 if (c & 0x80)
852 sc->sc_flags |= SC_RCV_B7_1;
853 else
854 sc->sc_flags |= SC_RCV_B7_0;
855 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
856 sc->sc_flags |= SC_RCV_ODDP;
857 else
858 sc->sc_flags |= SC_RCV_EVNP;
859 splx(s);
860
861 if (sc->sc_flags & SC_LOG_RAWIN)
862 ppplogchar(sc, c);
863
864 if (c == PPP_FLAG) {
865 ilen = sc->sc_ilen;
866 sc->sc_ilen = 0;
867
868 if (sc->sc_rawin_count > 0)
869 ppplogchar(sc, -1);
870
871 /*
872 * If SC_ESCAPED is set, then we've seen the packet
873 * abort sequence "}~".
874 */
875 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
876 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
877 s = spltty();
878 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
879 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
880 if (sc->sc_flags & SC_DEBUG)
881 printf("%s: bad fcs %x\n", ifp->if_xname,
882 sc->sc_fcs);
883 ifp->if_ierrors++;
884 sc->sc_stats.ppp_ierrors++;
885 } else
886 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
887 splx(s);
888 return 0;
889 }
890
891 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
892 if (ilen) {
893 if (sc->sc_flags & SC_DEBUG)
894 printf("%s: too short (%d)\n", ifp->if_xname, ilen);
895 s = spltty();
896 ifp->if_ierrors++;
897 sc->sc_stats.ppp_ierrors++;
898 sc->sc_flags |= SC_PKTLOST;
899 splx(s);
900 }
901 return 0;
902 }
903
904 /*
905 * Remove FCS trailer. Somewhat painful...
906 */
907 ilen -= 2;
908 if (--sc->sc_mc->m_len == 0) {
909 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
910 ;
911 sc->sc_mc = m;
912 }
913 sc->sc_mc->m_len--;
914
915 /* excise this mbuf chain */
916 m = sc->sc_m;
917 sc->sc_m = sc->sc_mc->m_next;
918 sc->sc_mc->m_next = NULL;
919
920 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
921 if (sc->sc_flags & SC_PKTLOST) {
922 s = spltty();
923 sc->sc_flags &= ~SC_PKTLOST;
924 splx(s);
925 }
926
927 pppgetm(sc);
928 return 0;
929 }
930
931 if (sc->sc_flags & SC_FLUSH) {
932 if (sc->sc_flags & SC_LOG_FLUSH)
933 ppplogchar(sc, c);
934 return 0;
935 }
936
937 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
938 return 0;
939
940 s = spltty();
941 if (sc->sc_flags & SC_ESCAPED) {
942 sc->sc_flags &= ~SC_ESCAPED;
943 c ^= PPP_TRANS;
944 } else if (c == PPP_ESCAPE) {
945 sc->sc_flags |= SC_ESCAPED;
946 splx(s);
947 return 0;
948 }
949 splx(s);
950
951 /*
952 * Initialize buffer on first octet received.
953 * First octet could be address or protocol (when compressing
954 * address/control).
955 * Second octet is control.
956 * Third octet is first or second (when compressing protocol)
957 * octet of protocol.
958 * Fourth octet is second octet of protocol.
959 */
960 if (sc->sc_ilen == 0) {
961 /* reset the first input mbuf */
962 if (sc->sc_m == NULL) {
963 pppgetm(sc);
964 if (sc->sc_m == NULL) {
965 if (sc->sc_flags & SC_DEBUG)
966 printf("%s: no input mbufs!\n", ifp->if_xname);
967 goto flush;
968 }
969 }
970 m = sc->sc_m;
971 m->m_len = 0;
972 m->m_data = M_DATASTART(sc->sc_m);
973 sc->sc_mc = m;
974 sc->sc_mp = mtod(m, char *);
975 sc->sc_fcs = PPP_INITFCS;
976 if (c != PPP_ALLSTATIONS) {
977 if (sc->sc_flags & SC_REJ_COMP_AC) {
978 if (sc->sc_flags & SC_DEBUG)
979 printf("%s: garbage received: 0x%x (need 0xFF)\n",
980 ifp->if_xname, c);
981 goto flush;
982 }
983 *sc->sc_mp++ = PPP_ALLSTATIONS;
984 *sc->sc_mp++ = PPP_UI;
985 sc->sc_ilen += 2;
986 m->m_len += 2;
987 }
988 }
989 if (sc->sc_ilen == 1 && c != PPP_UI) {
990 if (sc->sc_flags & SC_DEBUG)
991 printf("%s: missing UI (0x3), got 0x%x\n",
992 ifp->if_xname, c);
993 goto flush;
994 }
995 if (sc->sc_ilen == 2 && (c & 1) == 1) {
996 /* a compressed protocol */
997 *sc->sc_mp++ = 0;
998 sc->sc_ilen++;
999 sc->sc_mc->m_len++;
1000 }
1001 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1002 if (sc->sc_flags & SC_DEBUG)
1003 printf("%s: bad protocol %x\n", ifp->if_xname,
1004 (sc->sc_mp[-1] << 8) + c);
1005 goto flush;
1006 }
1007
1008 /* packet beyond configured mru? */
1009 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1010 if (sc->sc_flags & SC_DEBUG)
1011 printf("%s: packet too big\n", ifp->if_xname);
1012 goto flush;
1013 }
1014
1015 /* is this mbuf full? */
1016 m = sc->sc_mc;
1017 if (M_TRAILINGSPACE(m) <= 0) {
1018 if (m->m_next == NULL) {
1019 pppgetm(sc);
1020 if (m->m_next == NULL) {
1021 if (sc->sc_flags & SC_DEBUG)
1022 printf("%s: too few input mbufs!\n", ifp->if_xname);
1023 goto flush;
1024 }
1025 }
1026 sc->sc_mc = m = m->m_next;
1027 m->m_len = 0;
1028 m->m_data = M_DATASTART(m);
1029 sc->sc_mp = mtod(m, char *);
1030 }
1031
1032 ++m->m_len;
1033 *sc->sc_mp++ = c;
1034 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1035 return 0;
1036
1037 flush:
1038 if (!(sc->sc_flags & SC_FLUSH)) {
1039 s = spltty();
1040 ifp->if_ierrors++;
1041 sc->sc_stats.ppp_ierrors++;
1042 sc->sc_flags |= SC_FLUSH;
1043 splx(s);
1044 if (sc->sc_flags & SC_LOG_FLUSH)
1045 ppplogchar(sc, c);
1046 }
1047 return 0;
1048 }
1049
1050 #define MAX_DUMP_BYTES 128
1051
1052 static void
1053 ppplogchar(sc, c)
1054 struct ppp_softc *sc;
1055 int c;
1056 {
1057 if (c >= 0)
1058 sc->sc_rawin[sc->sc_rawin_count++] = c;
1059 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1060 || (c < 0 && sc->sc_rawin_count > 0)) {
1061 #ifdef _HAS_IF_ALLOC
1062 printf("%s input: ", sc->sc_if->if_xname);
1063 #else
1064 printf("%s input: ", sc->sc_if.if_xname);
1065 #endif
1066 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1067 sc->sc_rawin_count = 0;
1068 }
1069 }
1070
1071 static void
1072 pppdumpb(b, l)
1073 u_char *b;
1074 int l;
1075 {
1076 char buf[3*MAX_DUMP_BYTES+4];
1077 char *bp = buf;
1078 static char digits[] = "0123456789abcdef";
1079
1080 while (l--) {
1081 if (bp >= buf + sizeof(buf) - 3) {
1082 *bp++ = '>';
1083 break;
1084 }
1085 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1086 *bp++ = digits[*b++ & 0xf];
1087 *bp++ = ' ';
1088 }
1089
1090 *bp = 0;
1091 printf("%s\n", buf);
1092 }
1093
1094 #endif /* NPPP > 0 */
1095