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

4.104.114.84.95
Last change on this file since f4c118d was f4c118d, checked in by Joel Sherrill <joel.sherrill@…>, on 03/27/02 at 14:36:07

2002-03-27 Ilya Alexeev <ilya@…>

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