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