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