1 /* $OpenBSD: ppp_tty.c,v 1.55 2024/08/17 09:52:11 denis 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/socket.h>
105 #include <sys/timeout.h>
106 #include <sys/ioctl.h>
107 #include <sys/fcntl.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 #include <sys/rwlock.h>
114 #include <sys/pool.h>
115
116 #include <net/if.h>
117 #include <net/if_var.h>
118
119 #ifdef VJC
120 #include <netinet/in.h>
121 #include <netinet/ip.h>
122 #include <net/slcompress.h>
123 #endif
124
125 #include <net/bpf.h>
126 #include <net/ppp_defs.h>
127 #include <net/if_ppp.h>
128 #include <net/if_pppvar.h>
129
130 int pppstart_internal(struct tty *tp, int);
131
132 u_int16_t pppfcs(u_int16_t fcs, u_char *cp, int len);
133 void pppasyncstart(struct ppp_softc *);
134 void pppasyncctlp(struct ppp_softc *);
135 void pppasyncrelinq(struct ppp_softc *);
136 void ppp_timeout(void *);
137 void ppppkt(struct ppp_softc *sc);
138 void pppdumpb(u_char *b, int l);
139 void ppplogchar(struct ppp_softc *, int);
140
141 struct rwlock ppp_pkt_init = RWLOCK_INITIALIZER("ppppktini");
142 struct pool ppp_pkts;
143
144 #define PKT_MAXLEN(_sc) ((_sc)->sc_mru + PPP_HDRLEN + PPP_FCSLEN)
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 /*
159 * Line specific open routine for async tty devices.
160 * Attach the given tty to the first available ppp unit.
161 * Called from device open routine or ttioctl.
162 */
163 int
pppopen(dev_t dev,struct tty * tp,struct proc * p)164 pppopen(dev_t dev, struct tty *tp, struct proc *p)
165 {
166 struct ppp_softc *sc;
167 int error, s;
168
169 if ((error = suser(p)) != 0)
170 return (error);
171
172 rw_enter_write(&ppp_pkt_init);
173 if (ppp_pkts.pr_size == 0) {
174 extern const struct kmem_pa_mode kp_dma_contig;
175
176 pool_init(&ppp_pkts, sizeof(struct ppp_pkt), 0,
177 IPL_TTY, 0, "ppppkts", NULL); /* IPL_SOFTTTY */
178 pool_set_constraints(&ppp_pkts, &kp_dma_contig);
179 }
180 rw_exit_write(&ppp_pkt_init);
181
182 s = spltty();
183
184 if (tp->t_line == PPPDISC) {
185 sc = (struct ppp_softc *) tp->t_sc;
186 if (sc != NULL && sc->sc_devp == (void *) tp) {
187 splx(s);
188 return (0);
189 }
190 }
191
192 if ((sc = pppalloc(p->p_p->ps_pid)) == NULL) {
193 splx(s);
194 return ENXIO;
195 }
196
197 if (sc->sc_relinq)
198 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
199
200 timeout_set(&sc->sc_timo, ppp_timeout, sc);
201 sc->sc_ilen = 0;
202 sc->sc_pkt = NULL;
203 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
204 sc->sc_asyncmap[0] = 0xffffffff;
205 sc->sc_asyncmap[3] = 0x60000000;
206 sc->sc_rasyncmap = 0;
207 sc->sc_devp = (void *) tp;
208 sc->sc_start = pppasyncstart;
209 sc->sc_ctlp = pppasyncctlp;
210 sc->sc_relinq = pppasyncrelinq;
211 sc->sc_outm = NULL;
212 ppppkt(sc);
213 sc->sc_if.if_flags |= IFF_RUNNING;
214 sc->sc_if.if_baudrate = tp->t_ospeed;
215
216 tp->t_sc = (caddr_t) sc;
217 ttyflush(tp, FREAD | FWRITE);
218
219 splx(s);
220 return (0);
221 }
222
223 /*
224 * Line specific close routine, called from device close routine
225 * and from ttioctl.
226 * Detach the tty from the ppp unit.
227 * Mimics part of ttyclose().
228 */
229 int
pppclose(struct tty * tp,int flag,struct proc * p)230 pppclose(struct tty *tp, int flag, struct proc *p)
231 {
232 struct ppp_softc *sc;
233 int s;
234
235 s = spltty();
236 ttyflush(tp, FREAD|FWRITE);
237 tp->t_line = 0;
238 sc = (struct ppp_softc *) tp->t_sc;
239 if (sc != NULL) {
240 tp->t_sc = NULL;
241 if (tp == (struct tty *) sc->sc_devp) {
242 pppasyncrelinq(sc);
243 pppdealloc(sc);
244 }
245 }
246 splx(s);
247 return 0;
248 }
249
250 /*
251 * Relinquish the interface unit to another device.
252 */
253 void
pppasyncrelinq(struct ppp_softc * sc)254 pppasyncrelinq(struct ppp_softc *sc)
255 {
256 int s;
257
258 KERNEL_LOCK();
259 s = spltty();
260 m_freem(sc->sc_outm);
261 sc->sc_outm = NULL;
262
263 if (sc->sc_pkt != NULL) {
264 ppp_pkt_free(sc->sc_pkt);
265 sc->sc_pkt = sc->sc_pktc = NULL;
266 }
267 if (sc->sc_flags & SC_TIMEOUT) {
268 timeout_del(&sc->sc_timo);
269 sc->sc_flags &= ~SC_TIMEOUT;
270 }
271 splx(s);
272 KERNEL_UNLOCK();
273 }
274
275 /*
276 * Line specific (tty) read routine.
277 */
278 int
pppread(struct tty * tp,struct uio * uio,int flag)279 pppread(struct tty *tp, struct uio *uio, int flag)
280 {
281 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
282 struct mbuf *m, *m0;
283 int s;
284 int error = 0;
285
286 if (sc == NULL)
287 return 0;
288 /*
289 * Loop waiting for input, checking that nothing disastrous
290 * happens in the meantime.
291 */
292 s = spltty();
293 for (;;) {
294 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
295 splx(s);
296 return 0;
297 }
298 /* Get the packet from the input queue */
299 m0 = mq_dequeue(&sc->sc_inq);
300 if (m0 != NULL)
301 break;
302 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
303 && (tp->t_state & TS_ISOPEN)) {
304 splx(s);
305 return 0; /* end of file */
306 }
307 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
308 splx(s);
309 return (EWOULDBLOCK);
310 }
311 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin);
312 if (error) {
313 splx(s);
314 return error;
315 }
316 }
317
318 /* Pull place-holder byte out of canonical queue */
319 getc(&tp->t_canq);
320 splx(s);
321
322 for (m = m0; m && uio->uio_resid; m = m->m_next)
323 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
324 break;
325 m_freem(m0);
326 return (error);
327 }
328
329 /*
330 * Line specific (tty) write routine.
331 */
332 int
pppwrite(struct tty * tp,struct uio * uio,int flag)333 pppwrite(struct tty *tp, struct uio *uio, int flag)
334 {
335 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
336 struct mbuf *m, *m0, **mp;
337 struct sockaddr dst;
338 u_int len;
339 int error;
340
341 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
342 return 0; /* wrote 0 bytes */
343 if (tp->t_line != PPPDISC)
344 return (EINVAL);
345 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
346 return EIO;
347 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
348 uio->uio_resid < PPP_HDRLEN)
349 return (EMSGSIZE);
350 for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
351 if (mp == &m0) {
352 MGETHDR(m, M_WAIT, MT_DATA);
353 m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN;
354 m->m_pkthdr.ph_ifidx = 0;
355 } else
356 MGET(m, M_WAIT, MT_DATA);
357 *mp = m;
358 m->m_len = 0;
359 if (uio->uio_resid >= MCLBYTES / 2)
360 MCLGET(m, M_DONTWAIT);
361 len = m_trailingspace(m);
362 if (len > uio->uio_resid)
363 len = uio->uio_resid;
364 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
365 m_freem(m0);
366 return (error);
367 }
368 m->m_len = len;
369 }
370 dst.sa_family = AF_UNSPEC;
371 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
372 m0->m_data += PPP_HDRLEN;
373 m0->m_len -= PPP_HDRLEN;
374 m0->m_pkthdr.ph_rtableid = sc->sc_if.if_rdomain;
375 return sc->sc_if.if_output(&sc->sc_if, m0, &dst, NULL);
376 }
377
378 /*
379 * Line specific (tty) ioctl routine.
380 * This discipline requires that tty device drivers call
381 * the line specific l_ioctl routine from their ioctl routines.
382 */
383 int
ppptioctl(struct tty * tp,u_long cmd,caddr_t data,int flag,struct proc * p)384 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
385 {
386 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
387 int error, s;
388
389 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
390 return -1;
391
392 error = 0;
393 switch (cmd) {
394 case PPPIOCSASYNCMAP:
395 if ((error = suser(p)) != 0)
396 break;
397 sc->sc_asyncmap[0] = *(u_int *)data;
398 break;
399
400 case PPPIOCGASYNCMAP:
401 *(u_int *)data = sc->sc_asyncmap[0];
402 break;
403
404 case PPPIOCSRASYNCMAP:
405 if ((error = suser(p)) != 0)
406 break;
407 sc->sc_rasyncmap = *(u_int *)data;
408 break;
409
410 case PPPIOCGRASYNCMAP:
411 *(u_int *)data = sc->sc_rasyncmap;
412 break;
413
414 case PPPIOCSXASYNCMAP:
415 if ((error = suser(p)) != 0)
416 break;
417 s = spltty();
418 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
419 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
420 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
421 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
422 splx(s);
423 break;
424
425 case PPPIOCGXASYNCMAP:
426 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
427 break;
428
429 default:
430 NET_LOCK();
431 error = pppioctl(sc, cmd, data, flag, p);
432 NET_UNLOCK();
433 if (error == 0 && cmd == PPPIOCSMRU)
434 ppppkt(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 u_int16_t
pppfcs(u_int16_t fcs,u_char * cp,int len)482 pppfcs(u_int16_t fcs, u_char *cp, int len)
483 {
484 while (len--)
485 fcs = PPP_FCS(fcs, *cp++);
486 return (fcs);
487 }
488
489 /*
490 * This gets called from pppoutput when a new packet is
491 * put on a queue.
492 */
493 void
pppasyncstart(struct ppp_softc * sc)494 pppasyncstart(struct ppp_softc *sc)
495 {
496 struct tty *tp = (struct tty *) sc->sc_devp;
497 struct mbuf *m;
498 int len;
499 u_char *start, *stop, *cp;
500 int n, ndone, done, idle;
501 struct mbuf *m2;
502 int s;
503
504 KERNEL_LOCK();
505 idle = 0;
506 while (CCOUNT(&tp->t_outq) < tp->t_hiwat) {
507 /*
508 * See if we have an existing packet partly sent.
509 * If not, get a new packet and start sending it.
510 */
511 m = sc->sc_outm;
512 if (m == NULL) {
513 /*
514 * Get another packet to be sent.
515 */
516 m = ppp_dequeue(sc);
517 if (m == NULL) {
518 idle = 1;
519 break;
520 }
521
522 /*
523 * The extra PPP_FLAG will start up a new packet, and thus
524 * will flush any accumulated garbage. We do this whenever
525 * the line may have been idle for some time.
526 */
527 if (CCOUNT(&tp->t_outq) == 0) {
528 ++sc->sc_stats.ppp_obytes;
529 (void) putc(PPP_FLAG, &tp->t_outq);
530 }
531
532 /* Calculate the FCS for the first mbuf's worth. */
533 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
534 }
535
536 for (;;) {
537 start = mtod(m, u_char *);
538 len = m->m_len;
539 stop = start + len;
540 while (len > 0) {
541 /*
542 * Find out how many bytes in the string we can
543 * handle without doing something special.
544 */
545 for (cp = start; cp < stop; cp++)
546 if (ESCAPE_P(*cp))
547 break;
548 n = cp - start;
549 if (n) {
550 /* NetBSD (0.9 or later), 4.3-Reno or similar. */
551 ndone = n - b_to_q(start, n, &tp->t_outq);
552 len -= ndone;
553 start += ndone;
554 sc->sc_stats.ppp_obytes += ndone;
555
556 if (ndone < n)
557 break; /* packet doesn't fit */
558 }
559 /*
560 * If there are characters left in the mbuf,
561 * the first one must be special.
562 * Put it out in a different form.
563 */
564 if (len) {
565 s = spltty();
566 if (putc(PPP_ESCAPE, &tp->t_outq)) {
567 splx(s);
568 break;
569 }
570 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
571 (void) unputc(&tp->t_outq);
572 splx(s);
573 break;
574 }
575 splx(s);
576 sc->sc_stats.ppp_obytes += 2;
577 start++;
578 len--;
579 }
580 }
581
582 /*
583 * If we didn't empty this mbuf, remember where we're up to.
584 * If we emptied the last mbuf, try to add the FCS and closing
585 * flag, and if we can't, leave sc_outm pointing to m, but with
586 * m->m_len == 0, to remind us to output the FCS and flag later.
587 */
588 done = len == 0;
589 if (done && m->m_next == NULL) {
590 u_char *p, *q;
591 int c;
592 u_char endseq[8];
593
594 /*
595 * We may have to escape the bytes in the FCS.
596 */
597 p = endseq;
598 c = ~sc->sc_outfcs & 0xFF;
599 if (ESCAPE_P(c)) {
600 *p++ = PPP_ESCAPE;
601 *p++ = c ^ PPP_TRANS;
602 } else
603 *p++ = c;
604 c = (~sc->sc_outfcs >> 8) & 0xFF;
605 if (ESCAPE_P(c)) {
606 *p++ = PPP_ESCAPE;
607 *p++ = c ^ PPP_TRANS;
608 } else
609 *p++ = c;
610 *p++ = PPP_FLAG;
611
612 /*
613 * Try to output the FCS and flag. If the bytes
614 * don't all fit, back out.
615 */
616 s = spltty();
617 for (q = endseq; q < p; ++q)
618 if (putc(*q, &tp->t_outq)) {
619 done = 0;
620 for (; q > endseq; --q)
621 unputc(&tp->t_outq);
622 break;
623 }
624 splx(s);
625 if (done)
626 sc->sc_stats.ppp_obytes += q - endseq;
627 }
628
629 if (!done) {
630 /* remember where we got to */
631 m->m_data = start;
632 m->m_len = len;
633 break;
634 }
635
636 /* Finished with this mbuf; free it and move on. */
637 m2 = m_free(m);
638 m = m2;
639 if (m == NULL) {
640 /* Finished a packet */
641 break;
642 }
643 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
644 }
645
646 /*
647 * If m == NULL, we have finished a packet.
648 * If m != NULL, we've either done as much work this time
649 * as we need to, or else we've filled up the output queue.
650 */
651 sc->sc_outm = m;
652 if (m)
653 break;
654 }
655
656 /* Call pppstart to start output again if necessary. */
657 s = spltty();
658 pppstart_internal(tp, 0);
659
660 /*
661 * This timeout is needed for operation on a pseudo-tty,
662 * because the pty code doesn't call pppstart after it has
663 * drained the t_outq.
664 */
665 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
666 timeout_add(&sc->sc_timo, 1);
667 sc->sc_flags |= SC_TIMEOUT;
668 }
669
670 splx(s);
671 KERNEL_UNLOCK();
672 }
673
674 /*
675 * This gets called when a received packet is placed on
676 * the inq.
677 */
678 void
pppasyncctlp(struct ppp_softc * sc)679 pppasyncctlp(struct ppp_softc *sc)
680 {
681 struct tty *tp;
682 int s;
683
684 KERNEL_LOCK();
685 /* Put a placeholder byte in canq for ttpoll()/ttnread(). */
686 s = spltty();
687 tp = (struct tty *) sc->sc_devp;
688 putc(0, &tp->t_canq);
689 ttwakeup(tp);
690 splx(s);
691 KERNEL_UNLOCK();
692 }
693
694 /*
695 * Start output on async tty interface. If the transmit queue
696 * has drained sufficiently, arrange for pppasyncstart to be
697 * called later.
698 */
699 int
pppstart_internal(struct tty * tp,int force)700 pppstart_internal(struct tty *tp, int force)
701 {
702 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
703
704 /*
705 * If there is stuff in the output queue, send it now.
706 * We are being called in lieu of ttstart and must do what it would.
707 */
708 if (tp->t_oproc != NULL)
709 (*tp->t_oproc)(tp);
710
711 /*
712 * If the transmit queue has drained and the tty has not hung up
713 * or been disconnected from the ppp unit, then tell if_ppp.c that
714 * we need more output.
715 */
716 if ((CCOUNT(&tp->t_outq) < tp->t_lowat || force)
717 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
718 && sc != NULL && tp == (struct tty *) sc->sc_devp) {
719 ppp_restart(sc);
720 }
721
722 return 0;
723 }
724
725 int
pppstart(struct tty * tp)726 pppstart(struct tty *tp)
727 {
728 return pppstart_internal(tp, 0);
729 }
730
731 /*
732 * Timeout routine - try to start some more output.
733 */
734 void
ppp_timeout(void * x)735 ppp_timeout(void *x)
736 {
737 struct ppp_softc *sc = (struct ppp_softc *) x;
738 struct tty *tp = (struct tty *) sc->sc_devp;
739 int s;
740
741 s = spltty();
742 sc->sc_flags &= ~SC_TIMEOUT;
743 pppstart_internal(tp, 1);
744 splx(s);
745 }
746
747 /*
748 * Allocate enough mbuf to handle current MRU.
749 */
750 void
ppppkt(struct ppp_softc * sc)751 ppppkt(struct ppp_softc *sc)
752 {
753 struct ppp_pkt **pktp, *pkt;
754 int len;
755 int s;
756
757 s = spltty();
758 pktp = &sc->sc_pkt;
759 for (len = PKT_MAXLEN(sc); len > 0; len -= sizeof(pkt->p_buf)) {
760 pkt = *pktp;
761 if (pkt == NULL) {
762 pkt = pool_get(&ppp_pkts, PR_NOWAIT);
763 if (pkt == NULL)
764 break;
765 PKT_NEXT(pkt) = NULL;
766 PKT_PREV(pkt) = *pktp;
767 PKT_LEN(pkt) = 0;
768 *pktp = pkt;
769 }
770 pktp = &PKT_NEXT(pkt);
771 }
772 splx(s);
773 }
774
775 void
ppp_pkt_free(struct ppp_pkt * pkt)776 ppp_pkt_free(struct ppp_pkt *pkt)
777 {
778 struct ppp_pkt *next;
779
780 while (pkt != NULL) {
781 next = PKT_NEXT(pkt);
782 pool_put(&ppp_pkts, pkt);
783 pkt = next;
784 }
785 }
786
787 /*
788 * tty interface receiver interrupt.
789 */
790 static unsigned int paritytab[8] = {
791 0x96696996, 0x69969669, 0x69969669, 0x96696996,
792 0x69969669, 0x96696996, 0x96696996, 0x69969669
793 };
794
795 int
pppinput(int c,struct tty * tp)796 pppinput(int c, struct tty *tp)
797 {
798 struct ppp_softc *sc;
799 struct ppp_pkt *pkt;
800 int ilen, s;
801
802 sc = (struct ppp_softc *) tp->t_sc;
803 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
804 return 0;
805
806 ++tk_nin;
807 ++sc->sc_stats.ppp_ibytes;
808
809 if (c & TTY_FE) {
810 /* framing error or overrun on this char - abort packet */
811 if (sc->sc_flags & SC_DEBUG)
812 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
813 goto flush;
814 }
815
816 c &= 0xff;
817
818 /*
819 * Handle software flow control of output.
820 */
821 if (tp->t_iflag & IXON) {
822 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
823 if ((tp->t_state & TS_TTSTOP) == 0) {
824 tp->t_state |= TS_TTSTOP;
825 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
826 }
827 return 0;
828 }
829 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
830 tp->t_state &= ~TS_TTSTOP;
831 if (tp->t_oproc != NULL)
832 (*tp->t_oproc)(tp);
833 return 0;
834 }
835 }
836
837 s = spltty();
838 if (c & 0x80)
839 sc->sc_flags |= SC_RCV_B7_1;
840 else
841 sc->sc_flags |= SC_RCV_B7_0;
842 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
843 sc->sc_flags |= SC_RCV_ODDP;
844 else
845 sc->sc_flags |= SC_RCV_EVNP;
846 splx(s);
847
848 if (sc->sc_flags & SC_LOG_RAWIN)
849 ppplogchar(sc, c);
850
851 if (c == PPP_FLAG) {
852 ilen = sc->sc_ilen;
853 sc->sc_ilen = 0;
854
855 if (sc->sc_rawin_count > 0)
856 ppplogchar(sc, -1);
857
858 /*
859 * If SC_ESCAPED is set, then we've seen the packet
860 * abort sequence "}~".
861 */
862 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
863 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
864 s = spltty();
865 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
866 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
867 if (sc->sc_flags & SC_DEBUG)
868 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
869 sc->sc_fcs);
870 sc->sc_if.if_ierrors++;
871 sc->sc_stats.ppp_ierrors++;
872 } else
873 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
874 splx(s);
875 return 0;
876 }
877
878 if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
879 if (ilen) {
880 if (sc->sc_flags & SC_DEBUG)
881 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
882 s = spltty();
883 sc->sc_if.if_ierrors++;
884 sc->sc_stats.ppp_ierrors++;
885 sc->sc_flags |= SC_PKTLOST;
886 splx(s);
887 }
888 return 0;
889 }
890
891 /*
892 * Remove FCS trailer.
893 */
894 ilen -= 2;
895 pkt = sc->sc_pktc;
896 if (--PKT_LEN(pkt) == 0) {
897 pkt = PKT_PREV(pkt);
898 sc->sc_pktc = pkt;
899 }
900 PKT_LEN(pkt)--;
901
902 /* excise this mbuf chain */
903 pkt = sc->sc_pkt;
904 sc->sc_pkt = sc->sc_pktc = PKT_NEXT(sc->sc_pktc);
905 PKT_NEXT(pkt) = NULL;
906
907 ppppktin(sc, pkt, sc->sc_flags & SC_PKTLOST);
908 if (sc->sc_flags & SC_PKTLOST) {
909 s = spltty();
910 sc->sc_flags &= ~SC_PKTLOST;
911 splx(s);
912 }
913
914 ppppkt(sc);
915 return 0;
916 }
917
918 if (sc->sc_flags & SC_FLUSH) {
919 if (sc->sc_flags & SC_LOG_FLUSH)
920 ppplogchar(sc, c);
921 return 0;
922 }
923
924 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
925 return 0;
926
927 s = spltty();
928 if (sc->sc_flags & SC_ESCAPED) {
929 sc->sc_flags &= ~SC_ESCAPED;
930 c ^= PPP_TRANS;
931 } else if (c == PPP_ESCAPE) {
932 sc->sc_flags |= SC_ESCAPED;
933 splx(s);
934 return 0;
935 }
936 splx(s);
937
938 /*
939 * Initialize buffer on first octet received.
940 * First octet could be address or protocol (when compressing
941 * address/control).
942 * Second octet is control.
943 * Third octet is first or second (when compressing protocol)
944 * octet of protocol.
945 * Fourth octet is second octet of protocol.
946 */
947 if (sc->sc_ilen == 0) {
948 /* reset the first input mbuf */
949 if (sc->sc_pkt == NULL) {
950 ppppkt(sc);
951 if (sc->sc_pkt == NULL) {
952 if (sc->sc_flags & SC_DEBUG)
953 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
954 goto flush;
955 }
956 }
957 pkt = sc->sc_pkt;
958 PKT_LEN(pkt) = 0;
959 sc->sc_pktc = pkt;
960 sc->sc_pktp = pkt->p_buf;
961 sc->sc_fcs = PPP_INITFCS;
962 if (c != PPP_ALLSTATIONS) {
963 if (sc->sc_flags & SC_REJ_COMP_AC) {
964 if (sc->sc_flags & SC_DEBUG)
965 printf("%s: garbage received: 0x%x (need 0xFF)\n",
966 sc->sc_if.if_xname, c);
967 goto flush;
968 }
969 *sc->sc_pktp++ = PPP_ALLSTATIONS;
970 *sc->sc_pktp++ = PPP_UI;
971 sc->sc_ilen += 2;
972 PKT_LEN(pkt) += 2;
973 }
974 }
975 if (sc->sc_ilen == 1 && c != PPP_UI) {
976 if (sc->sc_flags & SC_DEBUG)
977 printf("%s: missing UI (0x3), got 0x%x\n",
978 sc->sc_if.if_xname, c);
979 goto flush;
980 }
981 if (sc->sc_ilen == 2 && (c & 1) == 1) {
982 /* a compressed protocol */
983 *sc->sc_pktp++ = 0;
984 sc->sc_ilen++;
985 PKT_LEN(sc->sc_pktc)++;
986 }
987 if (sc->sc_ilen == 3 && (c & 1) == 0) {
988 if (sc->sc_flags & SC_DEBUG)
989 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
990 (sc->sc_pktp[-1] << 8) + c);
991 goto flush;
992 }
993
994 /* packet beyond configured mru? */
995 if (++sc->sc_ilen > PKT_MAXLEN(sc)) {
996 if (sc->sc_flags & SC_DEBUG)
997 printf("%s: packet too big\n", sc->sc_if.if_xname);
998 goto flush;
999 }
1000
1001 /* is this packet full? */
1002 pkt = sc->sc_pktc;
1003 if (PKT_LEN(pkt) >= sizeof(pkt->p_buf)) {
1004 if (PKT_NEXT(pkt) == NULL) {
1005 ppppkt(sc);
1006 if (PKT_NEXT(pkt) == NULL) {
1007 if (sc->sc_flags & SC_DEBUG)
1008 printf("%s: too few input packets!\n", sc->sc_if.if_xname);
1009 goto flush;
1010 }
1011 }
1012 sc->sc_pktc = pkt = PKT_NEXT(pkt);
1013 PKT_LEN(pkt) = 0;
1014 sc->sc_pktp = pkt->p_buf;
1015 }
1016
1017 ++PKT_LEN(pkt);
1018 *sc->sc_pktp++ = c;
1019 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1020 return 0;
1021
1022 flush:
1023 if (!(sc->sc_flags & SC_FLUSH)) {
1024 s = spltty();
1025 sc->sc_if.if_ierrors++;
1026 sc->sc_stats.ppp_ierrors++;
1027 sc->sc_flags |= SC_FLUSH;
1028 splx(s);
1029 if (sc->sc_flags & SC_LOG_FLUSH)
1030 ppplogchar(sc, c);
1031 }
1032 return 0;
1033 }
1034
1035 #define MAX_DUMP_BYTES 128
1036
1037 void
ppplogchar(struct ppp_softc * sc,int c)1038 ppplogchar(struct ppp_softc *sc, int c)
1039 {
1040 if (c >= 0)
1041 sc->sc_rawin[sc->sc_rawin_count++] = c;
1042 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1043 || (c < 0 && sc->sc_rawin_count > 0)) {
1044 printf("%s input: ", sc->sc_if.if_xname);
1045 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1046 sc->sc_rawin_count = 0;
1047 }
1048 }
1049
1050 void
pppdumpb(u_char * b,int l)1051 pppdumpb(u_char *b, int l)
1052 {
1053 char buf[3*MAX_DUMP_BYTES+4];
1054 char *bp = buf;
1055 static char digits[] = "0123456789abcdef";
1056
1057 while (l--) {
1058 if (bp >= buf + sizeof(buf) - 3) {
1059 *bp++ = '>';
1060 break;
1061 }
1062 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1063 *bp++ = digits[*b++ & 0xf];
1064 *bp++ = ' ';
1065 }
1066
1067 *bp = 0;
1068 printf("%s\n", buf);
1069 }
1070
1071 #endif /* NPPP > 0 */
1072