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