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