source: rtems/cpukit/libnetworking/net/ppp_tty.c @ 3e1bf78

4.11
Last change on this file since 3e1bf78 was 3e1bf78, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 8, 2014 at 9:43:10 AM

ppp: PR1943: Avoid NULL pointer access

Waiting for mbufs at this level is a bad solution. It would be better
to try to allocate a new mbuf chain before we hand over the current mbuf
chain to the upper layer. In case the allocation fails we should drop
the current packet and use its mbuf chain for a new packet.

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