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