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