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