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