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