OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [pppd/] [ppp_tty.c] - Blame information for rev 674

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
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: ppp_tty.c,v 1.2 2001-09-27 12:01:57 chris Exp $ */
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
 
113
void    pppasyncattach __P((void));
114
int     pppopen __P((dev_t dev, struct tty *tp));
115
int     pppclose __P((struct tty *tp, int flag));
116
int     pppread __P((struct tty *tp, struct uio *uio, int flag));
117
int     pppwrite __P((struct tty *tp, struct uio *uio, int flag));
118
int     ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag,
119
                       struct proc *));
120
int     pppinput __P((int c, struct tty *tp));
121
int     pppstart __P((struct tty *tp));
122
 
123
static u_short  pppfcs __P((u_short fcs, u_char *cp, int len));
124
static void     pppasyncstart __P((struct ppp_softc *));
125
static void     pppasyncctlp __P((struct ppp_softc *));
126
static void     pppasyncrelinq __P((struct ppp_softc *));
127
static void     ppp_timeout __P((void *));
128
static void     pppgetm __P((struct ppp_softc *sc));
129
static void     pppdumpb __P((u_char *b, int l));
130
static 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
 
163
static struct linesw pppdisc = {
164
        pppopen, pppclose, pppread, pppwrite, ppptioctl,
165
        pppinput, pppstart, ttymodem
166
};
167
 
168
void
169
pppasyncattach()
170
{
171
    linesw[PPPDISC] = pppdisc;
172
}
173
 
174
TEXT_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 */
182
int
183
pppopen(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
 */
240
int
241
pppclose(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
 */
266
static void
267
pppasyncrelinq(sc)
268
    struct ppp_softc *sc;
269
{
270
    int s;
271
 
272
    s = spltty();
273
    if (sc->sc_outm) {
274
        m_freem(sc->sc_outm);
275
        sc->sc_outm = NULL;
276
    }
277
    if (sc->sc_m) {
278
        m_freem(sc->sc_m);
279
        sc->sc_m = NULL;
280
    }
281
    if (sc->sc_flags & SC_TIMEOUT) {
282
        untimeout(ppp_timeout, (void *) sc);
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
    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
 */
349
int
350
pppwrite(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 */
400
int
401
ppptioctl(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
 */
463
static 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
 */
501
static u_short
502
pppfcs(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
 */
516
static void
517
pppasyncstart(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
 */
699
static void
700
pppasyncctlp(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
 */
720
int
721
pppstart(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
 */
750
static void
751
ppp_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
 */
767
static void
768
pppgetm(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
 */
791
static unsigned paritytab[8] = {
792
    0x96696996, 0x69969669, 0x69969669, 0x96696996,
793
    0x69969669, 0x96696996, 0x96696996, 0x69969669
794
};
795
 
796
int
797
pppinput(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
 
1042
static void
1043
ppplogchar(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
 
1057
static void
1058
pppdumpb(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 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.