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