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