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

4.104.11
Last change on this file since dcbfe08 was dcbfe08, checked in by Ralf Corsepius <ralf.corsepius@…>, on Sep 30, 2009 at 2:58:25 AM

2009-09-30 Ralf Corsépius <ralf.corsepius@…>

  • libnetworking/net/ppp_tty.c: Reflect termios_baud_to_number having been renamed to rtems_termios_baud_to_number.
  • Property mode set to 100644
File size: 25.7 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/* $Id$ */
78
79#include "opt_ppp.h"            /* XXX for ppp_defs.h */
80
81#if NPPP > 0
82
83#include <sys/param.h>
84#include <sys/systm.h>
85#include <sys/proc.h>
86#include <sys/mbuf.h>
87#include <sys/socket.h>
88#include <sys/ioctl.h>
89#include <sys/file.h>
90#include <sys/kernel.h>
91
92#include <net/if.h>
93#include <net/if_types.h>
94
95#ifdef VJC
96#include <netinet/in.h>
97#include <netinet/in_systm.h>
98#include <netinet/ip.h>
99#include <net/slcompress.h>
100#endif
101
102#include <rtems.h>
103#include <rtems/libio.h>
104#include <sys/ttycom.h>
105#include <termios.h>
106#include <rtems/termiostypes.h>
107
108#ifdef PPP_FILTER
109#include <net/bpf.h>
110#endif
111#include <net/ppp_defs.h>
112#include <net/if_ppp.h>
113#include <net/if_pppvar.h>
114
115
116void    pppasyncattach(void);
117int     pppopen(struct rtems_termios_tty *tty);
118int     pppclose(struct rtems_termios_tty *tty);
119int     pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args);
120int     pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args);
121int     ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args);
122int     pppinput(int c, struct rtems_termios_tty *tty);
123int     pppstart(struct rtems_termios_tty *tp);
124u_short pppfcs(u_short fcs, u_char *cp, int len);
125void    pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp);
126
127static void pppasyncstart(struct ppp_softc *);
128static void pppasyncctlp(struct ppp_softc *);
129static void pppasyncrelinq(struct ppp_softc *);
130/*static void ppp_timeout __P((void *)); */
131/*static void pppdumpb __P((u_char *b, int l)); */
132/*static void ppplogchar __P((struct ppp_softc *, int)); */
133
134/*
135 * Some useful mbuf macros not in mbuf.h.
136 */
137#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
138
139#define M_DATASTART(m)  \
140        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
141            (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
142
143#define M_DATASIZE(m)   \
144        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
145            (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
146
147/*
148 * We steal two bits in the mbuf m_flags, to mark high-priority packets
149 * for output, and received packets following lost/corrupted packets.
150 */
151#define M_HIGHPRI       0x2000  /* output packet for sc_fastq */
152#define M_ERRMARK       0x4000  /* steal a bit in mbuf m_flags */
153
154/*
155 * Does c need to be escaped?
156 */
157#define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
158
159/*
160 * Procedures for using an async tty interface for PPP.
161 */
162
163/* This is a FreeBSD-2.0 kernel. */
164#define CCOUNT(rb)      (((rb).Size+(rb).Head-(rb).Tail) % (rb).Size)
165#define FCOUNT(rb)      ((rb).Size-CCOUNT(rb)-1)
166#define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
167#define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
168
169/*
170 * Define the PPP line discipline.
171 */
172
173static struct rtems_termios_linesw pppdisc = {
174        pppopen, pppclose, pppread, pppwrite,
175        pppinput, pppstart, ppptioctl, NULL
176};
177
178void
179pppasyncattach(void)
180{
181    rtems_termios_linesw[PPPDISC] = pppdisc;
182}
183
184TEXT_SET(pseudo_set, pppasyncattach);
185
186/*
187 * Line specific open routine for async tty devices.
188 * Attach the given tty to the first available ppp unit.
189 * Called from device open routine or ttioctl.
190 */
191/* ARGSUSED */
192int
193pppopen(struct rtems_termios_tty *tty)
194{
195    int                        i;
196    register struct ppp_softc *sc;
197    struct mbuf *m = (struct mbuf *)0;
198
199    if (tty->t_line == PPPDISC) {
200        sc = (struct ppp_softc *)tty->t_sc;
201        if (sc != NULL && sc->sc_devp == (void *)tty) {
202            return (0);
203        }
204    }
205
206    if ((sc = pppalloc(1)) == NULL) {
207        return ENXIO;
208    }
209
210    if (sc->sc_relinq)
211        (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
212
213    sc->sc_ilen = 0;
214    sc->sc_m = NULL;
215    bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
216    sc->sc_asyncmap[0] = 0xffffffff;
217    sc->sc_asyncmap[3] = 0x60000000;
218    sc->sc_rasyncmap = 0;
219    sc->sc_devp = tty;
220    sc->sc_start = pppasyncstart;
221    sc->sc_ctlp = pppasyncctlp;
222    sc->sc_relinq = pppasyncrelinq;
223    sc->sc_outm = NULL;
224    sc->sc_outmc = NULL;
225   
226    /* preallocate mbufs for free queue */
227    rtems_bsdnet_semaphore_obtain();
228    for (i=0; i<NUM_MBUFQ; i++) {
229      pppallocmbuf(sc, &m);
230      if ( i == 0 ) {
231        /* use first mbuf for rx iterrupt handling */
232        sc->sc_m = m;
233      }
234      else {
235        /* enqueue mbuf for later use */
236        IF_ENQUEUE(&sc->sc_freeq, m);
237      }
238      m = (struct mbuf *)0;
239    }
240    rtems_bsdnet_semaphore_release();
241
242    /* initialize values */
243    sc->sc_if.if_flags |= IFF_RUNNING;
244    sc->sc_if.if_baudrate =
245        rtems_termios_baud_to_number(tty->termios.c_cflag & CBAUD);
246
247    tty->t_sc = (void *)sc;
248
249    return ( RTEMS_SUCCESSFUL );
250}
251
252/*
253 * Line specific close routine, called from device close routine
254 * and from ttioctl.
255 * Detach the tty from the ppp unit.
256 * Mimics part of ttyclose().
257 */
258int
259pppclose(struct rtems_termios_tty *tty)
260{
261    register struct ppp_softc *sc;
262
263    tty->t_line = 0;
264    sc = (struct ppp_softc *)tty->t_sc;
265    if (sc != NULL) {
266        tty->t_sc = NULL;
267        if (tty == (struct rtems_termios_tty *)sc->sc_devp) {
268            rtems_bsdnet_semaphore_obtain();
269            pppasyncrelinq(sc);
270            pppdealloc(sc);
271            rtems_bsdnet_semaphore_release();
272        }
273    }
274    return ( RTEMS_SUCCESSFUL );
275}
276
277/*
278 * Relinquish the interface unit to another device.
279 */
280static void
281pppasyncrelinq(struct ppp_softc *sc)
282{
283#ifdef XXX_XXX
284    if (sc->sc_outm) {
285        m_freem(sc->sc_outm);
286        sc->sc_outm = NULL;
287    }
288    if (sc->sc_m) {
289        m_freem(sc->sc_m);
290        sc->sc_m = NULL;
291    }
292    if (sc->sc_flags & SC_TIMEOUT) {
293        untimeout(ppp_timeout, (void *) sc);
294        sc->sc_flags &= ~SC_TIMEOUT;
295    }
296#endif
297}
298
299/*
300 * Line specific (tty) read routine.
301 */
302int
303pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args)
304{
305    rtems_status_code            status  = RTEMS_UNSATISFIED;
306    int                          count   = 0;
307    int                          maximum = rw_args->count;
308    char                        *buffer  = rw_args->buffer;
309    register struct ppp_softc   *sc      = (struct ppp_softc *)tty->t_sc;
310    struct mbuf                 *m;
311    struct mbuf                 *m0;
312    u_char                      *p;
313
314    if (sc == NULL)
315        return 0;
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    ioctl_command_t     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(
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  u_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
574    /* Ready with PPP_FLAG Character ? */
575    if(sc->sc_outflag & SC_TX_LASTCHAR){
576        sc->sc_outflag &= ~(SC_TX_BUSY | SC_TX_FCS | SC_TX_LASTCHAR);
577        rtems_event_send(sc->sc_txtask, TX_TRANSMIT);   /* Ready for the next Packet */
578        return(0);
579    }
580
581    if ( sc->sc_outoff >= sc->sc_outlen ) {
582      /* loop to get next non-zero length buffer */
583      if ( sc->sc_outmc != NULL ) {
584        m = sc->sc_outmc->m_next;
585      }
586
587      /* check for next mbuf in chain */
588      if ( m != NULL ) {
589        /* update values to use this mbuf */
590        sc->sc_outmc  = m;
591        sc->sc_outbuf = mtod(m, u_char *);
592        sc->sc_outlen = m->m_len;
593        sc->sc_outoff = (short)0;
594      }
595      else if ( (sc->sc_outflag & SC_TX_FCS) == 0 ) {
596        /* setup to use FCS buffer */
597        sc->sc_outflag |= SC_TX_FCS;
598        sc->sc_outbuf   = sc->sc_outfcsbuf;
599        sc->sc_outlen   = sc->sc_outfcslen;
600        sc->sc_outoff   = (short)0;
601      }
602      else {
603        /* done with this packet */
604        sc->sc_outflag |= SC_TX_LASTCHAR;
605        sc->sc_outflag &=~(SC_TX_FCS);
606                sc->sc_outchar = (u_char)PPP_FLAG;
607        (*tp->device.write)(tp->minor, (char *)&sc->sc_outchar, 1);
608        return(0);
609      }
610    }
611
612    /* check to see if there is some data to write out */
613    if ( sc->sc_outoff < sc->sc_outlen ) {
614      /* check to see if character needs to be escaped */
615      sc->sc_outchar = sc->sc_outbuf[sc->sc_outoff];
616      if ( ESCAPE_P(sc->sc_outchar) ) {
617        if ( sc->sc_outflag & SC_TX_ESCAPE ) {
618          /* last sent character was the escape character */
619          sc->sc_outchar = sc->sc_outchar ^ PPP_TRANS;
620
621          /* clear the escape flag and increment the offset */
622          sc->sc_outflag &= ~SC_TX_ESCAPE;
623          ioffset++;
624        }
625        else {
626          /* need to send the escape character */
627          sc->sc_outchar = PPP_ESCAPE;
628
629          /* set the escape flag */
630          sc->sc_outflag |= SC_TX_ESCAPE;
631        }
632        sendBegin = &sc->sc_outchar;
633      }
634      else {
635        /* escape not needed - increment the offset as much as possible */
636        while ((!ESCAPE_P(sc->sc_outchar)) && ((sc->sc_outoff + ioffset) < sc->sc_outlen)) {
637            ioffset++;
638            sc->sc_outchar = sc->sc_outbuf[sc->sc_outoff + ioffset];
639        }
640        sendBegin = &sc->sc_outbuf[sc->sc_outoff];
641      }
642
643      /* write out the character(s) and update the stats */
644      (*tp->device.write)(tp->minor, (char *)sendBegin, (ioffset > 0) ? ioffset : 1);
645      sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1;
646      sc->sc_outoff += ioffset;
647    }
648  }
649
650  return ( 0 );
651}
652
653#ifdef XXX_XXX
654/*
655 * Timeout routine - try to start some more output.
656 */
657static void
658ppp_timeout(void *x)
659{
660    struct rtems_termios_tty *tty = (struct rtems_termios_tty *)x;
661    struct ppp_softc         *sc  = tty->t_sc;
662/*    struct rtems_termios_tty *tp  = (struct rtems_termios_tty *)sc->sc_devp; */
663
664    sc->sc_flags &= ~SC_TIMEOUT;
665/*    pppstart(tp); */
666}
667#endif
668
669/*
670 * Allocate enough mbuf to handle current MRU.
671 */
672#ifdef XXX_XXX
673static void
674pppgetm(struct ppp_softc *sc)
675{
676    struct mbuf *m, **mp;
677    int len;
678
679    mp = &sc->sc_m;
680    for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
681        if ((m = *mp) == NULL) {
682            MGETHDR(m, M_DONTWAIT, MT_DATA);
683            if (m == NULL)
684                break;
685            *mp = m;
686            MCLGET(m, M_DONTWAIT);
687        }
688        len -= M_DATASIZE(m);
689        mp = &m->m_next;
690    }
691}
692#endif
693
694void
695pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp)
696{
697  int            ilen;
698  struct mbuf   *m;
699
700  /* loop over length value */
701  ilen = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN;
702  while ( ilen > 0 ) {
703    /* see if this is end of the chain */
704    m = *mp;
705    if ( m == NULL ) {
706      /* get mbuf header */
707      MGETHDR(m, M_DONTWAIT, MT_DATA);
708      if ( m == NULL ) {
709        /* error - set condition to break out */
710        printf("pppallocmbuf: MGETHDR failed\n");
711        break;
712      }
713      MCLGET(m, M_DONTWAIT);
714      m->m_next = NULL;
715      *mp = m;
716    }
717
718    /* update loop variables */
719    mp    = &m->m_next;
720    ilen -= M_DATASIZE(m);
721  }
722}
723
724/*
725 * tty interface receiver interrupt.
726 */
727static uint32_t paritytab[8] = {
728    0x96696996L, 0x69969669L, 0x69969669L, 0x96696996L,
729    0x69969669L, 0x96696996L, 0x96696996L, 0x69969669L
730};
731
732int
733pppinput(int c, struct rtems_termios_tty *tp)
734{
735    register struct ppp_softc *sc = tp->t_sc;
736    struct mbuf *m;
737    int ilen;
738
739    if (sc == NULL || tp != (struct rtems_termios_tty *)sc->sc_devp)
740        return 0;
741    if (sc->sc_m == NULL) {
742        rtems_event_send(sc->sc_rxtask, RX_EMPTY);
743        IF_DEQUEUE(&sc->sc_freeq, sc->sc_m);
744        if ( sc->sc_m == NULL ) {
745          return 0;
746        }
747    }
748
749    ++sc->sc_stats.ppp_ibytes;
750
751    c &= 0xff;
752    if (c & 0x80)
753        sc->sc_flags |= SC_RCV_B7_1;
754    else
755        sc->sc_flags |= SC_RCV_B7_0;
756    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
757        sc->sc_flags |= SC_RCV_ODDP;
758    else
759        sc->sc_flags |= SC_RCV_EVNP;
760
761    if (c == PPP_FLAG) {
762        ilen = sc->sc_ilen;
763        sc->sc_ilen = 0;
764
765        /*
766         * If SC_ESCAPED is set, then we've seen the packet
767         * abort sequence "}~".
768         */
769        if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
770            || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
771            sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
772            if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
773                /* bad fcs error */
774                sc->sc_if.if_ierrors++;
775                sc->sc_stats.ppp_ierrors++;
776            } else
777                sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
778            return 0;
779        }
780
781        if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
782            if (ilen) {
783                /* too short error */
784                sc->sc_if.if_ierrors++;
785                sc->sc_stats.ppp_ierrors++;
786                sc->sc_flags |= SC_PKTLOST;
787            }
788            return 0;
789        }
790
791        /* Remove FCS trailer.  Somewhat painful... */
792        ilen -= 2;
793        if (--sc->sc_mc->m_len == 0) {
794            for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next);
795            sc->sc_mc = m;
796        }
797        sc->sc_mc->m_len--;
798
799        /* excise this mbuf chain - place on raw queue */
800        m = sc->sc_m;
801        if ( sc->sc_flags & SC_PKTLOST ) {
802          m->m_flags   |= M_ERRMARK;
803          sc->sc_flags &= ~SC_PKTLOST;
804        }
805        IF_ENQUEUE(&sc->sc_rawq, m);
806
807        /* setup next mbuf chain */
808        IF_DEQUEUE(&sc->sc_freeq, sc->sc_m);
809
810        /* send rx packet event */
811        rtems_event_send(sc->sc_rxtask, RX_PACKET);
812        return 0;
813    }
814
815    if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
816        return 0;
817
818    if (sc->sc_flags & SC_ESCAPED) {
819        sc->sc_flags &= ~SC_ESCAPED;
820        c ^= PPP_TRANS;
821    } else if (c == PPP_ESCAPE) {
822        sc->sc_flags |= SC_ESCAPED;
823        return 0;
824    }
825
826    /*
827     * Initialize buffer on first octet received.
828     * First octet could be address or protocol (when compressing
829     * address/control).
830     * Second octet is control.
831     * Third octet is first or second (when compressing protocol)
832     * octet of protocol.
833     * Fourth octet is second octet of protocol.
834     */
835    if (sc->sc_ilen == 0) {
836        m = sc->sc_m;
837        m->m_len = 0;
838        m->m_data = M_DATASTART(sc->sc_m);
839        sc->sc_mc = m;
840        sc->sc_mp = mtod(m, char *);
841        sc->sc_fcs = PPP_INITFCS;
842        if (c != PPP_ALLSTATIONS) {
843            if (sc->sc_flags & SC_REJ_COMP_AC) {
844                /* garbage received error */
845                goto flush;
846            }
847            *sc->sc_mp++ = PPP_ALLSTATIONS;
848            *sc->sc_mp++ = PPP_UI;
849            sc->sc_ilen += 2;
850            m->m_len += 2;
851        }
852    }
853    if (sc->sc_ilen == 1 && c != PPP_UI) {
854        /* missing UI error */
855        goto flush;
856    }
857    if (sc->sc_ilen == 2 && (c & 1) == 1) {
858        /* a compressed protocol */
859        *sc->sc_mp++ = 0;
860        sc->sc_ilen++;
861        sc->sc_mc->m_len++;
862    }
863    if (sc->sc_ilen == 3 && (c & 1) == 0) {
864        /* bad protocol error */
865        goto flush;
866    }
867
868    /* packet beyond configured mru? */
869    if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
870        /* packet too big error */
871        goto flush;
872    }
873
874    /* is this mbuf full? */
875    m = sc->sc_mc;
876    if (M_TRAILINGSPACE(m) <= 0) {
877        if (m->m_next == NULL) {
878          /* get next available mbuf for the chain */
879          IF_DEQUEUE(&sc->sc_freeq, m->m_next);
880          if (m->m_next == NULL) {
881            /* too few mbufs */
882            goto flush;
883          }
884          else {
885            /* send rx mbuf event */
886            rtems_event_send(sc->sc_rxtask, RX_MBUF);
887          }
888        }
889        sc->sc_mc = m = m->m_next;
890        m->m_len  = 0;
891        m->m_next = 0;
892        m->m_data = M_DATASTART(m);
893        sc->sc_mp = mtod(m, char *);
894    }
895
896    ++m->m_len;
897    *sc->sc_mp++ = c;
898    sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
899    return 0;
900
901 flush:
902    if (!(sc->sc_flags & SC_FLUSH)) {
903        sc->sc_if.if_ierrors++;
904        sc->sc_stats.ppp_ierrors++;
905        sc->sc_flags |= SC_FLUSH;
906    }
907    return 0;
908}
909
910#ifdef XXX_XXX
911#define MAX_DUMP_BYTES  128
912
913static void
914ppplogchar(struct ppp_softc *sc, int c)
915{
916    if (c >= 0)
917        sc->sc_rawin[sc->sc_rawin_count++] = c;
918    if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
919        || (c < 0 && sc->sc_rawin_count > 0)) {
920        printf("ppp%d input: ", sc->sc_if.if_unit);
921        pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
922        sc->sc_rawin_count = 0;
923    }
924}
925
926static void
927pppdumpb(u_char *b, int l)
928{
929    char buf[3*MAX_DUMP_BYTES+4];
930    char *bp = buf;
931    static char digits[] = "0123456789abcdef";
932
933    while (l--) {
934        if (bp >= buf + sizeof(buf) - 3) {
935            *bp++ = '>';
936            break;
937        }
938        *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
939        *bp++ = digits[*b++ & 0xf];
940        *bp++ = ' ';
941    }
942
943    *bp = 0;
944    printf("%s\n", buf);
945}
946#endif
947
948#endif  /* NPPP > 0 */
Note: See TracBrowser for help on using the repository browser.