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