source: rtems/c/src/libnetworking/modem/ppp_tty.c @ 85a0f07

4.104.114.84.95
Last change on this file since 85a0f07 was 85a0f07, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 25, 2000 at 10:10:01 PM

2000-11-25 Antti P Miettinen <antti.p.miettinen@…>

  • wrapup/Makefile.am: Added modem subdir.
  • configure.in, Makefile.am: Added modem subdir.
  • net/Makefile.am: Added if_pppvar.h, pppcompress.h.
  • pppd/Makefile.am: Added pppmain.c (which needs work).
  • pppd/chat.c, pppd/fsm.c, pppd/fsm.h, pppd/ipxcp.c, pppd/main.c, pppd/ppp_tty.c, pppd/upap.c: Changes from Thomas Doerfler <Thomas.Doerfler@…> and cosmetic changes by me. Actually main.c and ppp_tty.c should be scratched. The modem subdir has the real ppp_tty.c and the real pppd main is in pppmain.c.
  • Property mode set to 100644
File size: 26.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 * Adapted to RTEMS by Thomas Doerfler
73 * based on the package of Tomasz Domin delivered
74 * in RTEMS snapshot rtems-19991203:
75 *    Splitted hardware-independent driver parts from the hardware-dependent
76 *    parts, integrated into termios with newly defined line-discipline support
77 */
78
79/* Thomas: ppp_tty.c,v 1.3 2000/09/12 19:26:17 thomas Exp */
80/* $Id$ */
81/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
82/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
83
84#include "ppp.h"
85#if NPPP > 0
86
87#define VJC
88#define PPP_COMPRESS
89
90#include <rtems/rtems_bsdnet.h> /* to get right defines */
91
92#include <sys/param.h>
93#include <sys/systm.h>
94#include <sys/proc.h>
95#include <sys/mbuf.h>
96#if 0
97#include <sys/dkstat.h>
98#endif
99#include <sys/socket.h>
100#include <sys/ioctl.h>
101#include <sys/file.h>
102#if 0
103#include <sys/tty.h>
104#endif
105#include <sys/kernel.h>
106#if 0
107#include <sys/conf.h>
108#include <sys/vnode.h>
109#endif
110
111#include <net/if.h>
112#include <net/if_types.h>
113
114#ifdef VJC
115#include <netinet/in.h>
116#include <netinet/in_systm.h>
117#include <netinet/ip.h>
118#include <net/pppcompress.h>
119#endif
120
121#include <rtems.h>
122#include <rtems/libio.h>
123#include <sys/ttycom.h>
124#include <termios.h>
125#include <termiostypes.h>
126
127#ifdef PPP_FILTER
128#include <net/bpf.h>
129#endif
130#include <net/ppp_defs.h>
131#include <net/if_ppp.h>
132#include <net/if_pppvar.h>
133
134void    pppasyncattach __P((void));
135int     pppopen   __P((struct rtems_termios_tty *tty));
136int     pppclose  __P((struct rtems_termios_tty *tty));
137int     pppread   __P((struct rtems_termios_tty *tty,
138                       rtems_libio_rw_args_t *rw_args));
139int     pppwrite  __P((struct rtems_termios_tty *tty,
140                       rtems_libio_rw_args_t *rw_args));
141int     ppptioctl __P((struct rtems_termios_tty *tty,
142                       rtems_libio_ioctl_args_t *args));
143int     pppinput  __P((int c,struct rtems_termios_tty *tty));
144int     pppstart  __P((struct rtems_termios_tty *tp));
145
146static u_short  pppfcs __P((u_short fcs, u_char *cp, int len));
147static void     pppasyncstart __P((struct ppp_softc *));
148static void     pppasyncctlp __P((struct ppp_softc *));
149static void     pppasyncrelinq __P((struct ppp_softc *));
150static void     ppp_timeout __P((void *));
151static void     pppgetm __P((struct ppp_softc *sc));
152static void     pppdumpb __P((u_char *b, int l));
153static void     ppplogchar __P((struct ppp_softc *, int));
154
155/*
156 * Some useful mbuf macros not in mbuf.h.
157 */
158#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
159
160#define M_DATASTART(m)  \
161        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
162            (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
163
164#define M_DATASIZE(m)   \
165        (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
166            (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
167
168/*
169 * Does c need to be escaped?
170 */
171#define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
172
173/*
174 * Procedures for using an async tty interface for PPP.
175 */
176
177/*
178 * compute used space in raw buffer
179 */
180#define CCOUNT(rb) (((rb).Size+(rb).Head-(rb).Tail) \
181                       % (rb).Size)
182/*
183 * compute free space in raw buffer
184 */
185#define FCOUNT(rb) ((rb).Size-CCOUNT(rb)-1)
186#define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
187#define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
188/* FIXME: make dependent on raw buffer size */
189
190/*
191 * Define the PPP line discipline.
192 */
193
194static struct linesw pppdisc = {
195        pppopen, pppclose, pppread, pppwrite, 
196        pppinput, pppstart, ppptioctl, NULL
197};
198
199void
200pppasyncattach()
201{
202    linesw[PPPDISC] = pppdisc;
203}
204
205TEXT_SET(pseudo_set, pppasyncattach);
206
207/*
208 * Line specific open routine for async tty devices.
209 * Attach the given tty to the first available ppp unit.
210 * Called from device open routine or ttioctl.
211 */
212/* ARGSUSED */
213/*
214 * Open the PPP device
215 */
216int 
217pppopen(struct rtems_termios_tty *tty)
218{
219  register struct ppp_softc *sc;
220  rtems_status_code status;
221
222  if ((tty->t_line == PPPDISC)) {
223    sc = tty->t_sc;
224    if (sc != NULL && sc->sc_devp == (void *) tty) {
225      return (0);
226    }
227  }
228   
229  if ((sc = pppalloc(1)) == NULL) {
230    return 2;
231  }
232
233  if (sc->sc_relinq) {
234    (*sc->sc_relinq)(sc);       /* get previous owner to relinquish the unit */
235  }
236  /*
237   * create communication semaphore
238   */
239  status = rtems_semaphore_create (rtems_build_name ('P', 'P', 'P', 
240                                                     '0'+sc->sc_if.if_unit),
241                                   0,
242                                   RTEMS_COUNTING_SEMAPHORE,
243                                   RTEMS_NO_PRIORITY_CEILING,
244                                   &sc->sem_id); 
245  if (status != RTEMS_SUCCESSFUL)
246    rtems_fatal_error_occurred (status);
247
248  sc->sc_ilen = 0;
249  sc->sc_m = NULL;
250  bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
251  sc->sc_asyncmap[0] = 0xffffffff;
252  sc->sc_asyncmap[3] = 0x60000000;
253  sc->sc_rasyncmap = 0;
254  sc->sc_devp = tty;
255  sc->sc_start = pppasyncstart;
256  sc->sc_ctlp = pppasyncctlp;
257  sc->sc_relinq = pppasyncrelinq;
258  sc->sc_outm = NULL;
259  pppgetm(sc);
260  sc->sc_if.if_flags |= IFF_RUNNING;
261  sc->sc_if.if_baudrate = 9600; /* FIXME: get line speed from termios */
262
263  tty->t_sc= (void *)sc;
264
265  return RTEMS_SUCCESSFUL;
266}
267 
268/*
269 * Line specific close routine, called from device close routine
270 * and from ttioctl.
271 * Detach the tty from the ppp unit.
272 * Mimics part of ttyclose().
273 */
274int 
275pppclose(struct rtems_termios_tty *tty)
276{
277  register struct ppp_softc *sc;
278  rtems_status_code status;
279
280
281  tty->t_line = 0;
282  sc = tty->t_sc;
283  if (sc != NULL) {
284    tty->t_sc = NULL;
285    if (tty == (struct rtems_termios_tty *) sc->sc_devp) {
286      rtems_bsdnet_semaphore_obtain();
287      pppasyncrelinq(sc);
288      /*
289       * delete communication semaphore
290       */
291      status = rtems_semaphore_delete (sc->sem_id); 
292      pppdealloc(sc);
293      rtems_bsdnet_semaphore_release();
294    }
295  }
296  return RTEMS_SUCCESSFUL;
297}
298
299/*
300 * Relinquish the interface unit to another device.
301 */
302static void
303pppasyncrelinq(sc)
304    struct ppp_softc *sc;
305{
306    int s;
307
308    if (sc->sc_outm) {
309        m_freem(sc->sc_outm);
310        sc->sc_outm = NULL;
311    }
312    if (sc->sc_m) {
313        m_freem(sc->sc_m);
314        sc->sc_m = NULL;
315    }
316    if (sc->sc_flags & SC_TIMEOUT) {
317        untimeout(ppp_timeout, (void *) sc);
318        sc->sc_flags &= ~SC_TIMEOUT;
319    }
320}
321
322/*
323 * Line specific (tty) read routine.
324 */
325pppread(struct rtems_termios_tty *tty,
326            rtems_libio_rw_args_t *rw_args)
327{
328  char *buffer;
329  int count=0,maximum;
330  rtems_status_code status;
331
332  struct mbuf *m, *m0;
333  register int s;
334  int error = 0;
335  rtems_interval    ticks;
336  register struct ppp_softc *sc = (struct ppp_softc *)tty->t_sc;
337  buffer = rw_args->buffer;
338  maximum = rw_args->count;
339
340  ticks=1000000/rtems_bsdnet_microseconds_per_tick;
341
342  if (sc == NULL) {
343    return 0;
344  }
345  /*
346   * Loop waiting for input, checking that nothing disasterous
347   * happens in the meantime.
348   */
349  for (;;) {
350    if (sc->sc_inq.ifq_head != NULL) {
351      break;
352    }
353    status=rtems_semaphore_obtain(sc->sem_id,RTEMS_WAIT,ticks);
354    if (status==RTEMS_TIMEOUT) {
355      return status;
356    }
357  }
358  rtems_bsdnet_semaphore_obtain();
359  IF_DEQUEUE(&sc->sc_inq, m0);
360  rtems_bsdnet_semaphore_release();
361
362  for (m = m0; 
363       ((m != NULL) && 
364        (count+m->m_len<maximum)); 
365       m = m->m_next) {/* check if packet will fit in buffer */
366    memcpy(buffer,mtod(m, u_char *),m->m_len);
367    count+=m->m_len;
368    buffer+=m->m_len;
369  }
370  m_freem(m0);
371  rw_args->bytes_moved = count;
372
373  return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
374}
375
376/*
377 * Line specific (tty) write routine.
378 */
379int 
380pppwrite(struct rtems_termios_tty *tty,
381          rtems_libio_rw_args_t *rw_args)
382{
383  int count,len;
384  char *out_buffer;
385  int n,maximum;
386 
387  register struct ppp_softc *sc = (struct ppp_softc *)tty->t_sc;
388  struct sockaddr dst;
389  struct mbuf *m, *m0, **mp;   
390
391  out_buffer = rw_args->buffer;
392  maximum = rw_args->count; 
393
394  rtems_bsdnet_semaphore_obtain();
395  for (mp = &m0; maximum; mp = &m->m_next) {
396    MGET(m, M_WAIT, MT_DATA);
397    if ((*mp = m) == NULL) {
398      rtems_bsdnet_semaphore_release();
399      m_freem(m0);
400      return (ENOBUFS);
401    }
402    m->m_len = 0;
403    if (maximum>= MCLBYTES / 2) {
404      MCLGET(m, M_DONTWAIT);
405    }
406    len = M_TRAILINGSPACE(m);
407    if (len > maximum) {
408      memcpy(mtod(m, u_char *),out_buffer,maximum);
409      m->m_len=maximum;
410      maximum=0;
411    }
412    else {
413      memcpy(mtod(m, u_char *),out_buffer,len);
414      maximum-=len;
415      m->m_len=len;
416      out_buffer+=len;
417    }
418  }
419 
420  dst.sa_family = AF_UNSPEC;
421  bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
422  m0->m_data += PPP_HDRLEN;
423  m0->m_len -= PPP_HDRLEN;
424 
425  n=pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
426  rtems_bsdnet_semaphore_release();
427  return n;
428}
429
430/*
431 * Line specific (tty) ioctl routine.
432 * This discipline requires that tty device drivers call
433 * the line specific l_ioctl routine from their ioctl routines.
434 */
435/* ARGSUSED */
436int 
437ppptioctl(struct rtems_termios_tty *tty,
438          rtems_libio_ioctl_args_t *args)
439{
440  struct ppp_softc *sc=tty->t_sc;
441  int cmd;
442  caddr_t data;
443  int error=RTEMS_SUCCESSFUL;
444
445  data=args->buffer;
446  cmd=args->command;
447
448  switch (cmd) {
449  case RTEMS_IO_GET_ATTRIBUTES:
450  case RTEMS_IO_SET_ATTRIBUTES:
451  case RTEMS_IO_TCDRAIN:
452  case TIOCGETD:       
453  case TIOCSETD:       
454    return RTEMS_UNSATISFIED;
455    break;     
456  case PPPIOCSASYNCMAP:
457    sc->sc_asyncmap[0] = *(u_int *)data;
458    break;
459
460  case PPPIOCGASYNCMAP:
461    *(u_int *)data = sc->sc_asyncmap[0];
462    break;
463   
464  case PPPIOCSRASYNCMAP:
465    sc->sc_rasyncmap = *(u_int *)data;
466    break;
467   
468  case TIOCMBIS:
469    break;
470  case TIOCMBIC:
471    break;     
472  case PPPIOCGRASYNCMAP:
473    *(u_int *)data = sc->sc_rasyncmap;
474    break;
475   
476  case PPPIOCSXASYNCMAP:
477    bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
478    sc->sc_asyncmap[1] = 0;                 /* mustn't escape 0x20 - 0x3f */
479    sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
480    sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
481    break;
482
483  case PPPIOCGXASYNCMAP:
484    bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
485    break;
486   
487  default:
488    rtems_bsdnet_semaphore_obtain();
489    error = pppioctl(sc, cmd, data, 0, NULL);
490    if (error == 0 && cmd == PPPIOCSMRU)
491      pppgetm(sc);
492    rtems_bsdnet_semaphore_release();
493       
494  }
495  return error;
496}
497
498/*
499 * FCS lookup table as calculated by genfcstab.
500 */
501static u_short fcstab[256] = {
502        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
503        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
504        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
505        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
506        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
507        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
508        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
509        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
510        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
511        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
512        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
513        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
514        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
515        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
516        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
517        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
518        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
519        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
520        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
521        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
522        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
523        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
524        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
525        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
526        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
527        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
528        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
529        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
530        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
531        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
532        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
533        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
534};
535
536/*
537 * Calculate a new FCS given the current FCS and the new data.
538 */
539static u_short
540pppfcs(fcs, cp, len)
541    register u_short fcs;
542    register u_char *cp;
543    register int len;
544{
545    while (len--)
546        fcs = PPP_FCS(fcs, *cp++);
547    return (fcs);
548}
549
550/*
551 * This gets called at splsoftnet from if_ppp.c at various times
552 * when there is data ready to be sent.
553 */
554static void
555pppasyncstart(sc)
556    register struct ppp_softc *sc;
557{
558    /* Call pppstart to start output again if necessary. */
559    pppstart(sc->sc_devp);
560
561    /*
562     * This timeout is needed for operation on a pseudo-tty,
563     * because the pty code doesn't call pppstart after it has
564     * drained the t_outq.
565     */
566/*    if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
567        timeout(ppp_timeout, (void *) sc, 1);
568        sc->sc_flags |= SC_TIMEOUT;
569    }
570*/
571
572}
573
574
575void modem_sendpacket(struct rtems_termios_tty *tty)
576{
577  struct mbuf *l = NULL;
578  rtems_unsigned16 status;
579  int curr;
580  register struct mbuf *m;
581  register int len;
582  register u_char *start, *stop, *cp;
583  int n, ndone, done, idle;
584  struct mbuf *m2;
585  int s;
586  char c;
587   register struct ppp_softc *sc=tty->t_sc;
588 
589
590   while (CCOUNT(tty->rawOutBuf) < PPP_HIWAT) {
591        /*
592         * See if we have an existing packet partly sent.
593         * If not, get a new packet and start sending it.
594         */
595        m = sc->sc_outm;
596        if (m == NULL) {
597            /*
598             * Get another packet to be sent.
599             
600             */
601            m = ppp_dequeue(sc);
602            if (m == NULL) 
603            {
604              break;
605            }
606
607            /*
608             * The extra PPP_FLAG will start up a new packet, and thus
609             * will flush any accumulated garbage.  We do this whenever
610             * the line may have been idle for some time.
611             */
612            if (CCOUNT(tty->rawOutBuf) == 0) {
613                ++sc->sc_stats.ppp_obytes;
614                c = PPP_FLAG;
615                rtems_termios_puts(&c,1,tty);
616            }
617
618            /* Calculate the FCS for the first mbuf's worth. */
619            sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
620            microtime(&sc->sc_if.if_lastchange);
621        }
622
623        for (;;) {
624            start = mtod(m, u_char *);
625            len = m->m_len;
626            stop = start + len;
627            while (len > 0) {
628                /*
629                 * Find out how many bytes in the string we can
630                 * handle without doing something special.
631                 */
632                for (cp = start; cp < stop; cp++)
633                    if (ESCAPE_P(*cp))
634                                break;
635                n = cp - start;
636                if (n) {
637                  register int i;
638                  i = FCOUNT(tty->rawOutBuf);
639                  if (n < i) {
640                    i = n;
641                  }
642                  if (i > 0) {
643                    rtems_termios_puts(start,i,tty);
644                  }
645                  ndone = i;
646                  len -= ndone;
647                  start += ndone;
648                  sc->sc_stats.ppp_obytes += ndone;
649                 
650                  if (ndone < n)
651                    break;      /* packet doesn't fit */
652                }
653                /*
654                 * If there are characters left in the mbuf,
655                 * the first one must be special.
656                 * Put it out in a different form.
657                 */
658                if (len) {
659                    if (FCOUNT(tty->rawOutBuf) < 2) {
660                        break;
661                    }
662                    else {
663                      char str[2];
664                      str[0] = PPP_ESCAPE;
665                      str[1] = *start ^ PPP_TRANS;
666                      rtems_termios_puts(str,2,tty);
667                    }
668                    sc->sc_stats.ppp_obytes += 2;
669                    start++;
670                    len--;
671                }
672            }
673
674            /*
675             * If we didn't empty this mbuf, remember where we're up to.
676             * If we emptied the last mbuf, try to add the FCS and closing
677             * flag, and if we can't, leave sc_outm pointing to m, but with
678             * m->m_len == 0, to remind us to output the FCS and flag later.
679             */
680            done = len == 0;
681            if (done && m->m_next == NULL) {
682                u_char *p, *q;
683                int c;
684                u_char endseq[8];
685
686                /*
687                 * We may have to escape the bytes in the FCS.
688                 */
689                p = endseq;
690                c = ~sc->sc_outfcs & 0xFF;
691                if (ESCAPE_P(c)) {
692                    *p++ = PPP_ESCAPE;
693                    *p++ = c ^ PPP_TRANS;
694                } else
695                    *p++ = c;
696                c = (~sc->sc_outfcs >> 8) & 0xFF;
697                if (ESCAPE_P(c)) {
698                    *p++ = PPP_ESCAPE;
699                    *p++ = c ^ PPP_TRANS;
700                } else
701                    *p++ = c;
702                *p++ = PPP_FLAG;
703
704                /*
705                 * Try to output the FCS and flag.  If the bytes
706                 * don't all fit, back out.
707                 */
708                if (FCOUNT(tty->rawOutBuf) > (p-endseq)) {
709                  rtems_termios_puts(endseq,p-endseq,tty);
710                }
711                else {
712                  done = 0;
713                }
714                if (done)
715                    sc->sc_stats.ppp_obytes += p - endseq;
716            }
717
718            if (!done) {
719                /* remember where we got to */
720                m->m_data = start;
721                m->m_len = len;
722                break;
723            }
724
725            /* Finished with this mbuf; free it and move on. */
726            MFREE(m, m2);
727            m = m2;
728            if (m == NULL) {
729                /* Finished a packet */
730                break;
731            }
732            sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
733        }
734
735        /*
736         * If m == NULL, we have finished a packet.
737         * If m != NULL, we've either done as much work this time
738         * as we need to, or else we've filled up the output queue.
739         */
740        sc->sc_outm = m;
741        if (m)
742            break;
743    }
744}
745
746/*
747 * This gets called when a received packet is placed on
748 * the inq, at splsoftnet.
749 */
750
751static void
752pppasyncctlp(sc)
753    struct ppp_softc *sc;
754{
755        rtems_semaphore_release(sc->sem_id);
756}
757
758/* Put data in input queue */
759int
760pppstart(struct rtems_termios_tty *tp)
761{
762  register struct ppp_softc *sc = tp->t_sc;
763
764  /*
765   * If there is stuff in the output queue, send it now.
766   * We are being called in lieu of ttstart and must do what it would.
767   */
768  sc->sc_if.if_flags  |= IFF_OACTIVE;
769 
770  /*
771   * If the transmit queue has drained and the tty has not hung up
772   * or been disconnected from the ppp unit, then tell if_ppp.c that
773   * we need more output.
774   */
775  if (CCOUNT(tp->rawOutBuf) < PPP_LOWAT
776      /*        && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)*/
777      && sc != NULL && tp == (struct rtems_termios_tty *) sc->sc_devp) {
778    modem_sendpacket(tp);
779  }
780 
781  return 0;
782}
783
784/*
785 * Timeout routine - try to start some more output.
786 */
787static void
788ppp_timeout(x)
789    void *x;
790{
791    struct rtems_termios_tty *tty = ((struct rtems_termios_tty *)x);
792    struct ppp_softc *sc = tty->t_sc;
793    struct rtems_termios_tty *tp = (struct rtems_termios_tty *) sc->sc_devp;
794    int s;
795
796    sc->sc_flags &= ~SC_TIMEOUT;
797    pppstart(tp);
798}
799
800
801/*
802 * Allocate enough mbuf to handle current MRU.
803 */
804static void
805pppgetm(sc)
806    register struct ppp_softc *sc;
807{
808    struct mbuf *m, **mp;
809    int len;
810
811    mp = &sc->sc_m;
812    for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
813        if ((m = *mp) == NULL) {
814            MGETHDR(m, M_DONTWAIT, MT_DATA);
815            if (m == NULL)
816                break;
817            *mp = m;
818            MCLGET(m, M_DONTWAIT);
819        }
820        len -= M_DATASIZE(m);
821        mp = &m->m_next;
822    }
823}
824
825/*
826 * tty interface receiver interrupt.
827 */
828static unsigned paritytab[8] = {
829    0x96696996, 0x69969669, 0x69969669, 0x96696996,
830    0x69969669, 0x96696996, 0x96696996, 0x69969669
831};
832
833
834int
835pppinput(int c,struct rtems_termios_tty *tty)
836 
837{
838    register struct ppp_softc *sc=tty->t_sc;
839    struct mbuf *m;
840    int ilen, s;
841
842    if (sc == NULL )
843        return 0;
844
845    ++sc->sc_stats.ppp_ibytes;
846
847#if 0
848    if (c & TTY_FE) {
849        /* framing error or overrun on this char - abort packet */
850        if (sc->sc_flags & SC_DEBUG)
851            printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c);
852        goto flush;
853    }
854#endif
855
856    c &= 0xff;
857
858    /*
859     * Handle software flow control of output.
860     */
861/*    if (tp->t_iflag & IXON) {
862        if (c == tp->t_cc[VSTOP] ) {
863            if ((tp->t_state & TS_TTSTOP) == 0) {
864                tp->t_state |= TS_TTSTOP;
865                sccppp_stop_transmission(tp);
866            }
867            return 0;
868        }
869        if (c == tp->t_cc[VSTART]  ) {
870            tp->t_state &= ~TS_TTSTOP;
871                sccppp_start_transmission(tp);
872            return 0;
873        }
874    }
875*/
876
877    if (c & 0x80)
878        sc->sc_flags |= SC_RCV_B7_1;
879    else
880        sc->sc_flags |= SC_RCV_B7_0;
881    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
882        sc->sc_flags |= SC_RCV_ODDP;
883    else
884        sc->sc_flags |= SC_RCV_EVNP;
885
886
887    if (sc->sc_flags & SC_LOG_RAWIN)
888        ppplogchar(sc, c);
889
890    if (c == PPP_FLAG) {
891        ilen = sc->sc_ilen;
892        sc->sc_ilen = 0;
893
894        if (sc->sc_rawin_count > 0) 
895            ppplogchar(sc, -1);
896
897        /*
898         * If SC_ESCAPED is set, then we've seen the packet
899         * abort sequence
900         */
901        if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
902            || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
903            sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
904            if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
905                if (sc->sc_flags & SC_DEBUG)
906                    printf("ppp%d: bad fcs %x, pkt len %d\n",
907                           sc->sc_if.if_unit, sc->sc_fcs, ilen);
908                sc->sc_if.if_ierrors++;
909                sc->sc_stats.ppp_ierrors++;
910            } else
911                sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
912            return 0;
913        }
914
915        if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
916            if (ilen) {
917                if (sc->sc_flags & SC_DEBUG)
918                    printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
919                sc->sc_if.if_ierrors++;
920                sc->sc_stats.ppp_ierrors++;
921                sc->sc_flags |= SC_PKTLOST;
922                splx(s);
923            }
924            return 0;
925        }
926
927        /*
928         * Remove FCS trailer.  Somewhat painful...
929         */
930        ilen -= 2;
931        if (--sc->sc_mc->m_len == 0) {
932            for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
933                ;
934            sc->sc_mc = m;
935        }
936        sc->sc_mc->m_len--;
937
938        /* excise this mbuf chain */
939        m = sc->sc_m;
940        sc->sc_m = sc->sc_mc->m_next;
941        sc->sc_mc->m_next = NULL;
942        ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
943        if (sc->sc_flags & SC_PKTLOST) {
944            sc->sc_flags &= ~SC_PKTLOST;
945        }
946
947        pppgetm(sc);
948        return 0;
949    }
950
951    if (sc->sc_flags & SC_FLUSH) {
952        if (sc->sc_flags & SC_LOG_FLUSH)
953            ppplogchar(sc, c);
954        return 0;
955    }
956
957    if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
958        return 0;
959
960    if (sc->sc_flags & SC_ESCAPED) {
961        sc->sc_flags &= ~SC_ESCAPED;
962        c ^= PPP_TRANS;
963    } else if (c == PPP_ESCAPE) {
964        sc->sc_flags |= SC_ESCAPED;
965        return 0;
966    }
967
968    /*
969     * Initialize buffer on first octet received.
970     * First octet could be address or protocol (when compressing
971     * address/control).
972     * Second octet is control.
973     * Third octet is first or second (when compressing protocol)
974     * octet of protocol.
975     * Fourth octet is second octet of protocol.
976     */
977    if (sc->sc_ilen == 0) {
978        /* reset the first input mbuf */
979        if (sc->sc_m == NULL) {
980            pppgetm(sc);
981            if (sc->sc_m == NULL) {
982                if (sc->sc_flags & SC_DEBUG)
983                    printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
984                goto flush;
985            }
986        }
987        m = sc->sc_m;
988        m->m_len = 0;
989        m->m_data = M_DATASTART(sc->sc_m);
990        sc->sc_mc = m;
991        sc->sc_mp = mtod(m, char *);
992        sc->sc_fcs = PPP_INITFCS;
993        if (c != PPP_ALLSTATIONS) {
994            if (sc->sc_flags & SC_REJ_COMP_AC) {
995                if (sc->sc_flags & SC_DEBUG)
996                    printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
997                           sc->sc_if.if_unit, c);
998                goto flush;
999            }
1000            *sc->sc_mp++ = PPP_ALLSTATIONS;
1001            *sc->sc_mp++ = PPP_UI;
1002            sc->sc_ilen += 2;
1003            m->m_len += 2;
1004        }
1005    }
1006    if (sc->sc_ilen == 1 && c != PPP_UI) {
1007        if (sc->sc_flags & SC_DEBUG)
1008            printf("ppp%d: missing UI (0x3), got 0x%x\n",
1009                   sc->sc_if.if_unit, c);
1010        goto flush;
1011    }
1012    if (sc->sc_ilen == 2 && (c & 1) == 1) {
1013        /* a compressed protocol */
1014        *sc->sc_mp++ = 0;
1015        sc->sc_ilen++;
1016        sc->sc_mc->m_len++;
1017    }
1018    if (sc->sc_ilen == 3 && (c & 1) == 0) {
1019        if (sc->sc_flags & SC_DEBUG)
1020            printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
1021                   (sc->sc_mp[-1] << 8) + c);
1022        goto flush;
1023    }
1024
1025    /* packet beyond configured mru? */
1026    if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1027        if (sc->sc_flags & SC_DEBUG)
1028            printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
1029        goto flush;
1030    }
1031
1032    /* is this mbuf full? */
1033    m = sc->sc_mc;
1034    if (M_TRAILINGSPACE(m) <= 0) {
1035        if (m->m_next == NULL) {
1036            pppgetm(sc);
1037            if (m->m_next == NULL) {
1038                if (sc->sc_flags & SC_DEBUG)
1039                    printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
1040                goto flush;
1041            }
1042        }
1043        sc->sc_mc = m = m->m_next;
1044        m->m_len = 0;
1045        m->m_data = M_DATASTART(m);
1046        sc->sc_mp = mtod(m, char *);
1047    }
1048
1049    ++m->m_len;
1050    *sc->sc_mp++ = c;
1051    sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1052    return 0;
1053
1054 flush:
1055    if (!(sc->sc_flags & SC_FLUSH)) {
1056        sc->sc_if.if_ierrors++;
1057        sc->sc_stats.ppp_ierrors++;
1058        sc->sc_flags |= SC_FLUSH;
1059        if (sc->sc_flags & SC_LOG_FLUSH)
1060            ppplogchar(sc, c);
1061    }
1062    return 0;
1063}
1064
1065
1066#define MAX_DUMP_BYTES  128
1067
1068static void
1069ppplogchar(sc, c)
1070    struct ppp_softc *sc;
1071    int c;
1072{
1073    if (c >= 0)
1074        sc->sc_rawin[sc->sc_rawin_count++] = c;
1075    if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1076        || (c < 0 && sc->sc_rawin_count > 0)) {
1077        printf("ppp%d input: ", sc->sc_if.if_unit);
1078        pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1079        sc->sc_rawin_count = 0;
1080    }
1081}
1082
1083static void
1084pppdumpb(b, l)
1085    u_char *b;
1086    int l;
1087{
1088    char buf[3*MAX_DUMP_BYTES+4];
1089    char *bp = buf;
1090    static char digits[] = "0123456789abcdef";
1091
1092    while (l--) {
1093        if (bp >= buf + sizeof(buf) - 3) {
1094            *bp++ = '>';
1095            break;
1096        }
1097        *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1098        *bp++ = digits[*b++ & 0xf];
1099        *bp++ = ' ';
1100    }
1101
1102    *bp = 0;
1103    printf("%s\n", buf);
1104}
1105
1106#endif  /* NPPP > 0 */
Note: See TracBrowser for help on using the repository browser.