source: rtems/c/src/libnetworking/pppd/ppp_tty.c @ d0950ad

4.104.114.84.95
Last change on this file since d0950ad was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on 11/30/99 at 22:12:50

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

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