source: rtems/cpukit/libnetworking/net/ppp_tty.c @ df6348bb

4.104.114.84.95
Last change on this file since df6348bb was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:11

2001-01-31 Mike Siers <mikes@…>

  • Nice Update of PPPD support which eliminates the requiremetn that drivers be in the termios TASK_DRIVEN mode. Mike did significant testing and reports that it seems to be more stable and handle larger packets better. This patch replaces the termios tasks with more general pppd network driver tasks. The functions pppinput() and pppstart() get called from the interrupt service routine.
  • Makefile.am, configure.ac, net/Makefile.am, net/bpf.h, net/ethernet.h, net/if.c, net/if.h, net/if_arp.h, net/if_dl.h, net/if_ethersubr.c, net/if_llc.h, net/if_loop.c, net/if_ppp.h, net/if_pppvar.h, net/if_types.h, net/netisr.h, net/ppp-comp.h, net/ppp_defs.h, net/pppcompress.h, net/radix.c, net/radix.h, net/raw_cb.c, net/raw_cb.h, net/raw_usrreq.c, net/route.c, net/route.h, net/rtsock.c, pppd/Makefile.am, pppd/README, pppd/STATUS, pppd/auth.c, pppd/cbcp.c, pppd/ccp.c, pppd/ccp.h, pppd/chap.c, pppd/chap.h, pppd/chap_ms.c, pppd/chap_ms.h, pppd/chat.c, pppd/demand.c, pppd/fsm.c, pppd/fsm.h, pppd/ipcp.c, pppd/ipcp.h, pppd/ipxcp.c, pppd/ipxcp.h, pppd/lcp.c, pppd/lcp.h, pppd/magic.c, pppd/magic.h, pppd/options.c, pppd/patchlevel.h, pppd/pathnames.h, pppd/pppd.8, pppd/pppd.h, pppd/rtemsmain.c, pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/upap.c, pppd/upap.h, pppd/utils.c, pppd/example/README, pppd/example/netconfig.h, wrapup/Makefile.am: Modified.
  • net/bsd-comp.c, net/if_ppp.c, net/ppp-deflate.c, net/ppp.h, net/ppp_tty.c, net/pppcompress.c, net/zlib.c, net/zlib.h: New file.
  • modem/, modem/.cvsignore, modem/Makefile.am, modem/ppp.c, modem/ppp.h, modem/ppp_tty.c, modem/pppcompress.c: Subdirectory removed.
  • Property mode set to 100644
File size: 25.1 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#include <sys/param.h>
81#include <sys/systm.h>
82#include <sys/proc.h>
83#include <sys/mbuf.h>
84#include <sys/socket.h>
85#include <sys/ioctl.h>
86#include <sys/file.h>
87#include <sys/kernel.h>
88
89#include <net/if.h>
90#include <net/if_types.h>
91
92#ifdef VJC
93#include <netinet/in.h>
94#include <netinet/in_systm.h>
95#include <netinet/ip.h>
96#include <net/pppcompress.h>
97#endif
98
99#include <rtems.h>
100#include <rtems/libio.h>
101#include <sys/ttycom.h>
102#include <termios.h>
103#include <rtems/termiostypes.h>
104
105#ifdef PPP_FILTER
106#include <net/bpf.h>
107#endif
108#include <net/ppp_defs.h>
109#include <net/if_ppp.h>
110#include <net/if_pppvar.h>
111
112
113void    pppasyncattach __P((void));
114int     pppopen __P((struct rtems_termios_tty *tty));
115int     pppclose __P((struct rtems_termios_tty *tty));
116int     pppread __P((struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args));
117int     pppwrite __P((struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args));
118int     ppptioctl __P((struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args));
119int     pppinput __P((int c, struct rtems_termios_tty *tty));
120int     pppstart __P((struct rtems_termios_tty *tp));
121u_short pppfcs __P((u_short fcs, u_char *cp, int len));
122void    pppallocmbuf __P((struct ppp_softc *sc, struct mbuf **mp));
123
124static void pppasyncstart __P((struct ppp_softc *));
125static void pppasyncctlp __P((struct ppp_softc *));
126static void pppasyncrelinq __P((struct ppp_softc *));
127/*static void ppp_timeout __P((void *)); */
128/*static void pppdumpb __P((u_char *b, int l)); */
129/*static void ppplogchar __P((struct ppp_softc *, int)); */
130
131/*
132 * Some useful mbuf macros not in mbuf.h.
133 */
134#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
135
136#define M_DATASTART(m)  \
137        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
138            (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
139
140#define M_DATASIZE(m)   \
141        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
142            (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
143
144/*
145 * We steal two bits in the mbuf m_flags, to mark high-priority packets
146 * for output, and received packets following lost/corrupted packets.
147 */
148#define M_HIGHPRI       0x2000  /* output packet for sc_fastq */
149#define M_ERRMARK       0x4000  /* steal a bit in mbuf m_flags */
150
151/*
152 * Does c need to be escaped?
153 */
154#define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
155
156/*
157 * Procedures for using an async tty interface for PPP.
158 */
159
160/* This is a FreeBSD-2.0 kernel. */
161#define CCOUNT(rb)      (((rb).Size+(rb).Head-(rb).Tail) % (rb).Size)
162#define FCOUNT(rb)      ((rb).Size-CCOUNT(rb)-1)
163#define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
164#define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
165
166/*
167 * Define the PPP line discipline.
168 */
169
170static struct linesw pppdisc = {
171        pppopen, pppclose, pppread, pppwrite,
172        pppinput, pppstart, ppptioctl, NULL
173};
174
175void
176pppasyncattach()
177{
178    linesw[PPPDISC] = pppdisc;
179}
180
181TEXT_SET(pseudo_set, pppasyncattach);
182
183/*
184 * Line specific open routine for async tty devices.
185 * Attach the given tty to the first available ppp unit.
186 * Called from device open routine or ttioctl.
187 */
188/* ARGSUSED */
189int
190pppopen(struct rtems_termios_tty *tty)
191{
192    int                        i;
193    register struct ppp_softc *sc;
194    struct mbuf *m = (struct mbuf *)0;
195
196    if (tty->t_line == PPPDISC) {
197        sc = (struct ppp_softc *)tty->t_sc;
198        if (sc != NULL && sc->sc_devp == (void *)tty) {
199            return (0);
200        }
201    }
202
203    if ((sc = pppalloc(1)) == NULL) {
204        return ENXIO;
205    }
206
207    if (sc->sc_relinq)
208        (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
209
210    sc->sc_ilen = 0;
211    sc->sc_m = NULL;
212    bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
213    sc->sc_asyncmap[0] = 0xffffffff;
214    sc->sc_asyncmap[3] = 0x60000000;
215    sc->sc_rasyncmap = 0;
216    sc->sc_devp = tty;
217    sc->sc_start = pppasyncstart;
218    sc->sc_ctlp = pppasyncctlp;
219    sc->sc_relinq = pppasyncrelinq;
220    sc->sc_outm = NULL;
221    sc->sc_outmc = NULL;
222   
223    /* preallocate mbufs for free queue */
224    rtems_bsdnet_semaphore_obtain();
225    for (i=0; i<NUM_MBUFQ; i++) {
226      pppallocmbuf(sc, &m);
227      if ( i == 0 ) {
228        /* use first mbuf for rx iterrupt handling */
229        sc->sc_m = m;
230      }
231      else {
232        /* enqueue mbuf for later use */
233        IF_ENQUEUE(&sc->sc_freeq, m);
234      }
235      m = (struct mbuf *)0;
236    }
237    rtems_bsdnet_semaphore_release();
238
239    /* initialize values */
240    sc->sc_if.if_flags |= IFF_RUNNING;
241    sc->sc_if.if_baudrate = 57600; /* FIX: get line speed from termios */
242
243    tty->t_sc = (void *)sc;
244
245    return ( RTEMS_SUCCESSFUL );
246}
247
248/*
249 * Line specific close routine, called from device close routine
250 * and from ttioctl.
251 * Detach the tty from the ppp unit.
252 * Mimics part of ttyclose().
253 */
254int
255pppclose(struct rtems_termios_tty *tty)
256{
257    register struct ppp_softc *sc;
258
259    tty->t_line = 0;
260    sc = (struct ppp_softc *)tty->t_sc;
261    if (sc != NULL) {
262        tty->t_sc = NULL;
263        if (tty == (struct rtems_termios_tty *)sc->sc_devp) {
264            rtems_bsdnet_semaphore_obtain();
265            pppasyncrelinq(sc);
266            pppdealloc(sc);
267            rtems_bsdnet_semaphore_release();
268        }
269    }
270    return ( RTEMS_SUCCESSFUL );
271}
272
273/*
274 * Relinquish the interface unit to another device.
275 */
276static void
277pppasyncrelinq(sc)
278    struct ppp_softc *sc;
279{
280#ifdef XXX_XXX
281    if (sc->sc_outm) {
282        m_freem(sc->sc_outm);
283        sc->sc_outm = NULL;
284    }
285    if (sc->sc_m) {
286        m_freem(sc->sc_m);
287        sc->sc_m = NULL;
288    }
289    if (sc->sc_flags & SC_TIMEOUT) {
290        untimeout(ppp_timeout, (void *) sc);
291        sc->sc_flags &= ~SC_TIMEOUT;
292    }
293#endif
294}
295
296/*
297 * Line specific (tty) read routine.
298 */
299int
300pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args)
301{
302    rtems_status_code            status  = RTEMS_UNSATISFIED;
303    int                          count   = 0;
304    int                          maximum = rw_args->count;
305    char                        *buffer  = rw_args->buffer;
306    register struct ppp_softc   *sc      = (struct ppp_softc *)tty->t_sc;
307    struct mbuf                 *m;
308    struct mbuf                 *m0;
309    u_char                      *p;
310
311    if (sc == NULL) {
312        return 0;
313    }
314
315    /*
316     * Loop waiting for input, checking that nothing disasterous
317     * happens in the meantime.
318     */
319    if (tty != (struct rtems_termios_tty *)sc->sc_devp || tty->t_line != PPPDISC) {
320        return ( status );
321    }
322    if (sc->sc_inq.ifq_head == NULL) {
323      return ( status );
324    }
325
326    /* Get the packet from the input queue */
327    rtems_bsdnet_semaphore_obtain();
328    IF_DEQUEUE(&sc->sc_inq, m0);
329
330    /* loop over mbuf chain */
331    m = m0;
332    while (( m != NULL ) && ( m->m_len > 0 ) && ( count+m->m_len < maximum )) {
333      /* copy data into buffer */
334      p = mtod(m, u_char *);
335      memcpy(buffer, p, m->m_len);
336      memset(p, 0, m->m_len);
337      count  += m->m_len;
338      buffer += m->m_len;
339
340      /* increment loop index */
341      m = m->m_next;
342    }
343
344    /* free mbuf chain */
345    m_freem(m0);
346    rtems_bsdnet_semaphore_release();
347
348    /* update return values */
349    rw_args->bytes_moved = count;
350    if ( count >= 0 ) {
351      status = RTEMS_SUCCESSFUL;
352    }
353
354    /* check to see if queue is empty */
355    if (sc->sc_inq.ifq_head != NULL) {
356      /* queue is not empty - post another event to ourself */
357      rtems_event_send(sc->sc_pppdtask, PPPD_EVENT);
358    }
359
360    return ( status );
361}
362
363/*
364 * Line specific (tty) write routine.
365 */
366int
367pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args)
368{
369    struct sockaddr               dst;
370    int                           n;
371    int                           len;
372    int                           maximum    = rw_args->count;
373    char                         *out_buffer = rw_args->buffer;
374    register struct ppp_softc    *sc         = (struct ppp_softc *)tty->t_sc;
375    struct mbuf                  *m;
376    struct mbuf                  *m0;
377    struct mbuf                 **mp;
378
379    rtems_bsdnet_semaphore_obtain();
380    for (mp = &m0; maximum; mp = &m->m_next) {
381        MGET(m, M_WAIT, MT_DATA);
382        if ((*mp = m) == NULL) {
383            m_freem(m0);
384            return (ENOBUFS);
385        }
386        m->m_len = 0;
387        if (maximum >= MCLBYTES / 2) {
388            MCLGET(m, M_DONTWAIT);
389        }
390        len = M_TRAILINGSPACE(m);
391        if (len > maximum) {
392          memcpy(mtod(m, u_char *),out_buffer,maximum);
393          m->m_len = maximum;
394          maximum  = 0;
395        }
396        else {
397          memcpy(mtod(m, u_char *),out_buffer,len);
398          m->m_len    = len;
399          maximum    -= len;
400          out_buffer += len;
401        }
402    }
403
404    dst.sa_family = AF_UNSPEC;
405    bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
406    m0->m_data += PPP_HDRLEN;
407    m0->m_len  -= PPP_HDRLEN;
408
409    n = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
410    rtems_bsdnet_semaphore_release();
411
412    return ( n );
413}
414
415/*
416 * Line specific (tty) ioctl routine.
417 * This discipline requires that tty device drivers call
418 * the line specific l_ioctl routine from their ioctl routines.
419 */
420/* ARGSUSED */
421int
422ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args)
423{
424    int                 i;
425    int                 error = RTEMS_SUCCESSFUL;
426    int                 cmd   = args->command;
427    caddr_t             data  = args->buffer;
428    struct ppp_softc   *sc    = tty->t_sc;
429
430    switch (cmd) {
431    case RTEMS_IO_GET_ATTRIBUTES:
432    case RTEMS_IO_SET_ATTRIBUTES:
433    case RTEMS_IO_TCDRAIN:
434    case RTEMS_IO_SNDWAKEUP:
435    case RTEMS_IO_RCVWAKEUP:
436    case TIOCGETD:
437    case TIOCSETD:
438        error = rtems_termios_ioctl(args);
439        break;
440
441    case PPPIOCSASYNCMAP:
442        sc->sc_asyncmap[0] = *(u_int *)data;
443        break;
444
445    case PPPIOCGASYNCMAP:
446        *(u_int *)data = sc->sc_asyncmap[0];
447        break;
448
449    case PPPIOCSRASYNCMAP:
450        sc->sc_rasyncmap = *(u_int *)data;
451        break;
452
453    case PPPIOCGRASYNCMAP:
454        *(u_int *)data = sc->sc_rasyncmap;
455        break;
456
457    case PPPIOCSXASYNCMAP:
458        bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
459        sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
460        sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
461        sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
462        break;
463
464    case PPPIOCGXASYNCMAP:
465        bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
466        break;
467
468    default:
469        rtems_bsdnet_semaphore_obtain();
470        error = pppioctl(sc, cmd, data, 0, NULL);
471        rtems_bsdnet_semaphore_release();
472    }
473    return error;
474}
475
476/*
477 * FCS lookup table as calculated by genfcstab.
478 */
479static u_short fcstab[256] = {
480        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
481        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
482        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
483        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
484        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
485        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
486        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
487        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
488        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
489        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
490        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
491        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
492        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
493        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
494        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
495        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
496        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
497        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
498        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
499        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
500        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
501        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
502        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
503        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
504        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
505        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
506        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
507        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
508        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
509        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
510        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
511        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
512};
513
514/*
515 * Calculate a new FCS given the current FCS and the new data.
516 */
517u_short
518pppfcs(u_short fcs, u_char *cp, int len)
519{
520    while (len--)
521        fcs = PPP_FCS(fcs, *cp++);
522    return (fcs);
523}
524
525/*
526 * This gets called at splsoftnet from if_ppp.c at various times
527 * when there is data ready to be sent.
528 */
529void pppasyncstart(struct ppp_softc *sc)
530{
531  /* check to see if output is not active */
532  if ( sc->sc_outflag == 0 ) {
533    /* mark active and post tx event to daemon */
534    sc->sc_outflag |= SC_TX_PENDING;
535    rtems_event_send(sc->sc_txtask, TX_PACKET);
536  }
537}
538
539/*
540 * This gets called when a received packet is placed on
541 * the inq, at splsoftnet.
542 */
543static void
544pppasyncctlp(sc)
545    struct ppp_softc *sc;
546{
547  /* check to see if task id was set */
548  if ( sc->sc_pppdtask != 0 ) {
549    /* post event to daemon */
550    rtems_event_send(sc->sc_pppdtask, PPPD_EVENT);
551  }
552}
553
554/*
555 * Start output on async tty interface.  If the transmit queue
556 * has drained sufficiently, arrange for pppasyncstart to be
557 * called later at splsoftnet.
558 * Called at spltty or higher.
559 */
560int
561pppstart(struct rtems_termios_tty *tp)
562{
563  char                c;
564  char                cFrame  = (char         )PPP_FLAG;
565  u_char              ioffset = (u_char       )0;
566  struct mbuf        *m       = (struct mbuf *)0;
567  struct ppp_softc   *sc      = tp->t_sc;
568
569  /* ensure input is valid and we are busy */
570  if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) {
571    /* check to see if we need to get the next buffer */
572    if ( sc->sc_outoff >= sc->sc_outlen ) {
573      /* loop to get next non-zero length buffer */
574      if ( sc->sc_outmc != NULL ) {
575        m = sc->sc_outmc->m_next;
576      }
577
578      /* check for next mbuf in chain */
579      if ( m != NULL ) {
580        /* update values to use this mbuf */
581        sc->sc_outmc  = m;
582        sc->sc_outbuf = mtod(m, u_char *);
583        sc->sc_outlen = m->m_len;
584        sc->sc_outoff = (short)0;
585      }
586      else if ( (sc->sc_outflag & SC_TX_FCS) == 0 ) {
587        /* setup to use FCS buffer */
588        sc->sc_outflag |= SC_TX_FCS;
589        sc->sc_outbuf   = sc->sc_outfcsbuf;
590        sc->sc_outlen   = sc->sc_outfcslen;
591        sc->sc_outoff   = (short)0;
592      }
593      else {
594        /* done with this packet */
595        sc->sc_outflag &= ~SC_TX_BUSY;
596        (*tp->device.write)(tp->minor, &cFrame, 1);
597        rtems_event_send(sc->sc_txtask, TX_TRANSMIT);
598      }
599    }
600
601    /* check to see if there is some data to write out */
602    if ( sc->sc_outoff < sc->sc_outlen ) {
603      /* check to see if character needs to be escaped */
604      c = sc->sc_outbuf[sc->sc_outoff];
605      if ( ESCAPE_P(c) ) {
606        if ( sc->sc_outflag & SC_TX_ESCAPE ) {
607          /* last sent character was the escape character */
608          c = c ^ PPP_TRANS;
609
610          /* clear the escape flag and increment the offset */
611          sc->sc_outflag &= ~SC_TX_ESCAPE;
612          ioffset++;
613        }
614        else {
615          /* need to send the escape character */
616          c = PPP_ESCAPE;
617
618          /* set the escape flag */
619          sc->sc_outflag |= SC_TX_ESCAPE;
620        }
621      }
622      else {
623        /* escape not needed - increment the offset */
624        ioffset++;
625      }
626
627      /* write out the character and update the stats */
628      (*tp->device.write)(tp->minor, &c, 1);
629      sc->sc_stats.ppp_obytes++;
630      sc->sc_outoff += ioffset;
631    }
632  }
633
634  return ( 0 );
635}
636
637#ifdef XXX_XXX
638/*
639 * Timeout routine - try to start some more output.
640 */
641static void
642ppp_timeout(x)
643    void *x;
644{
645    struct rtems_termios_tty *tty = (struct rtems_termios_tty *)x;
646    struct ppp_softc         *sc  = tty->t_sc;
647/*    struct rtems_termios_tty *tp  = (struct rtems_termios_tty *)sc->sc_devp; */
648
649    sc->sc_flags &= ~SC_TIMEOUT;
650/*    pppstart(tp); */
651}
652#endif
653
654/*
655 * Allocate enough mbuf to handle current MRU.
656 */
657#ifdef XXX_XXX
658static void
659pppgetm(sc)
660    register struct ppp_softc *sc;
661{
662    struct mbuf *m, **mp;
663    int len;
664
665    mp = &sc->sc_m;
666    for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
667        if ((m = *mp) == NULL) {
668            MGETHDR(m, M_DONTWAIT, MT_DATA);
669            if (m == NULL)
670                break;
671            *mp = m;
672            MCLGET(m, M_DONTWAIT);
673        }
674        len -= M_DATASIZE(m);
675        mp = &m->m_next;
676    }
677}
678#endif
679
680void
681pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp)
682{
683  int            ilen;
684  struct mbuf   *m;
685
686  /* loop over length value */
687  ilen = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN;
688  while ( ilen > 0 ) {
689    /* see if this is end of the chain */
690    m = *mp;
691    if ( m == NULL ) {
692      /* get mbuf header */
693      MGETHDR(m, M_DONTWAIT, MT_DATA);
694      if ( m == NULL ) {
695        /* error - set condition to break out */
696        printf("pppallocmbuf: MGETHDR failed\n");
697        break;
698      }
699      MCLGET(m, M_DONTWAIT);
700      m->m_next = NULL;
701      *mp = m;
702    }
703
704    /* update loop variables */
705    mp    = &m->m_next;
706    ilen -= M_DATASIZE(m);
707  }
708}
709
710/*
711 * tty interface receiver interrupt.
712 */
713static unsigned paritytab[8] = {
714    0x96696996, 0x69969669, 0x69969669, 0x96696996,
715    0x69969669, 0x96696996, 0x96696996, 0x69969669
716};
717
718int
719pppinput(int c, struct rtems_termios_tty *tp)
720{
721    register struct ppp_softc *sc = tp->t_sc;
722    struct mbuf *m;
723    int ilen;
724
725    if (sc == NULL || tp != (struct rtems_termios_tty *)sc->sc_devp)
726        return 0;
727    if (sc->sc_m == NULL) {
728        rtems_event_send(sc->sc_rxtask, RX_EMPTY);
729        IF_DEQUEUE(&sc->sc_freeq, sc->sc_m);
730        if ( sc->sc_m == NULL ) {
731          return 0;
732        }
733    }
734
735    ++sc->sc_stats.ppp_ibytes;
736
737    c &= 0xff;
738    if (c & 0x80)
739        sc->sc_flags |= SC_RCV_B7_1;
740    else
741        sc->sc_flags |= SC_RCV_B7_0;
742    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
743        sc->sc_flags |= SC_RCV_ODDP;
744    else
745        sc->sc_flags |= SC_RCV_EVNP;
746
747    if (c == PPP_FLAG) {
748        ilen = sc->sc_ilen;
749        sc->sc_ilen = 0;
750
751        /*
752         * If SC_ESCAPED is set, then we've seen the packet
753         * abort sequence "}~".
754         */
755        if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
756            || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
757            sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
758            if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
759                /* bad fcs error */
760                sc->sc_if.if_ierrors++;
761                sc->sc_stats.ppp_ierrors++;
762            } else
763                sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
764            return 0;
765        }
766
767        if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
768            if (ilen) {
769                /* too short error */
770                sc->sc_if.if_ierrors++;
771                sc->sc_stats.ppp_ierrors++;
772                sc->sc_flags |= SC_PKTLOST;
773            }
774            return 0;
775        }
776
777        /* Remove FCS trailer.  Somewhat painful... */
778        ilen -= 2;
779        if (--sc->sc_mc->m_len == 0) {
780            for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next);
781            sc->sc_mc = m;
782        }
783        sc->sc_mc->m_len--;
784
785        /* excise this mbuf chain - place on raw queue */
786        m = sc->sc_m;
787        if ( sc->sc_flags & SC_PKTLOST ) {
788          m->m_flags   |= M_ERRMARK;
789          sc->sc_flags &= ~SC_PKTLOST;
790        }
791        IF_ENQUEUE(&sc->sc_rawq, m);
792
793        /* setup next mbuf chain */
794        IF_DEQUEUE(&sc->sc_freeq, sc->sc_m);
795
796        /* send rx packet event */
797        rtems_event_send(sc->sc_rxtask, RX_PACKET);
798        return 0;
799    }
800
801    if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
802        return 0;
803
804    if (sc->sc_flags & SC_ESCAPED) {
805        sc->sc_flags &= ~SC_ESCAPED;
806        c ^= PPP_TRANS;
807    } else if (c == PPP_ESCAPE) {
808        sc->sc_flags |= SC_ESCAPED;
809        return 0;
810    }
811
812    /*
813     * Initialize buffer on first octet received.
814     * First octet could be address or protocol (when compressing
815     * address/control).
816     * Second octet is control.
817     * Third octet is first or second (when compressing protocol)
818     * octet of protocol.
819     * Fourth octet is second octet of protocol.
820     */
821    if (sc->sc_ilen == 0) {
822        m = sc->sc_m;
823        m->m_len = 0;
824        m->m_data = M_DATASTART(sc->sc_m);
825        sc->sc_mc = m;
826        sc->sc_mp = mtod(m, char *);
827        sc->sc_fcs = PPP_INITFCS;
828        if (c != PPP_ALLSTATIONS) {
829            if (sc->sc_flags & SC_REJ_COMP_AC) {
830                /* garbage received error */
831                goto flush;
832            }
833            *sc->sc_mp++ = PPP_ALLSTATIONS;
834            *sc->sc_mp++ = PPP_UI;
835            sc->sc_ilen += 2;
836            m->m_len += 2;
837        }
838    }
839    if (sc->sc_ilen == 1 && c != PPP_UI) {
840        /* missing UI error */
841        goto flush;
842    }
843    if (sc->sc_ilen == 2 && (c & 1) == 1) {
844        /* a compressed protocol */
845        *sc->sc_mp++ = 0;
846        sc->sc_ilen++;
847        sc->sc_mc->m_len++;
848    }
849    if (sc->sc_ilen == 3 && (c & 1) == 0) {
850        /* bad protocol error */
851        goto flush;
852    }
853
854    /* packet beyond configured mru? */
855    if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
856        /* packet too big error */
857        goto flush;
858    }
859
860    /* is this mbuf full? */
861    m = sc->sc_mc;
862    if (M_TRAILINGSPACE(m) <= 0) {
863        if (m->m_next == NULL) {
864          /* get next available mbuf for the chain */
865          IF_DEQUEUE(&sc->sc_freeq, m->m_next);
866          if (m->m_next == NULL) {
867            /* too few mbufs */
868            goto flush;
869          }
870          else {
871            /* send rx mbuf event */
872            rtems_event_send(sc->sc_rxtask, RX_MBUF);
873          }
874        }
875        sc->sc_mc = m = m->m_next;
876        m->m_len  = 0;
877        m->m_next = 0;
878        m->m_data = M_DATASTART(m);
879        sc->sc_mp = mtod(m, char *);
880    }
881
882    ++m->m_len;
883    *sc->sc_mp++ = c;
884    sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
885    return 0;
886
887 flush:
888    if (!(sc->sc_flags & SC_FLUSH)) {
889        sc->sc_if.if_ierrors++;
890        sc->sc_stats.ppp_ierrors++;
891        sc->sc_flags |= SC_FLUSH;
892    }
893    return 0;
894}
895
896#ifdef XXX_XXX
897#define MAX_DUMP_BYTES  128
898
899static void
900ppplogchar(sc, c)
901    struct ppp_softc *sc;
902    int c;
903{
904    if (c >= 0)
905        sc->sc_rawin[sc->sc_rawin_count++] = c;
906    if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
907        || (c < 0 && sc->sc_rawin_count > 0)) {
908        printf("ppp%d input: ", sc->sc_if.if_unit);
909        pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
910        sc->sc_rawin_count = 0;
911    }
912}
913
914static void
915pppdumpb(b, l)
916    u_char *b;
917    int l;
918{
919    char buf[3*MAX_DUMP_BYTES+4];
920    char *bp = buf;
921    static char digits[] = "0123456789abcdef";
922
923    while (l--) {
924        if (bp >= buf + sizeof(buf) - 3) {
925            *bp++ = '>';
926            break;
927        }
928        *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
929        *bp++ = digits[*b++ & 0xf];
930        *bp++ = ' ';
931    }
932
933    *bp = 0;
934    printf("%s\n", buf);
935}
936#endif
937
938#endif  /* NPPP > 0 */
Note: See TracBrowser for help on using the repository browser.