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