source: rtems/cpukit/libnetworking/net/ppp_tty.c @ 1c6926c1

5
Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on 03/21/17 at 19:39:48

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

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