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