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