📄 ppp_tty.c
字号:
/* * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous * tty devices. * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Carnegie Mellon University. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Drew D. Perkins * Carnegie Mellon University * 4910 Forbes Ave. * Pittsburgh, PA 15213 * (412) 268-8576 * ddp@andrew.cmu.edu * * Based on: * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 * * Copyright (c) 1987 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Serial Line interface * * Rick Adams * Center for Seismic Studies * 1300 N 17th Street, Suite 1450 * Arlington, Virginia 22209 * (703)276-7900 * rick@seismo.ARPA * seismo!rick * * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). * Converted to 4.3BSD Beta by Chris Torek. * Other changes made at Berkeley, based in part on code by Kirk Smith. * * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) * Added VJ tcp header compression; more unified ioctls * * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). * Cleaned up a lot of the mbuf-related code to fix bugs that * caused system crashes and packet corruption. Changed pppstart * so that it doesn't just give up with a "collision" if the whole * packet doesn't fit in the output ring buffer. * * Added priority queueing for interactive IP packets, following * the model of if_sl.c, plus hooks for bpf. * Paul Mackerras (paulus@cs.anu.edu.au). *//* $Id: ppp_tty.c,v 1.3.2.1 2004/01/30 14:43:05 joel Exp $ *//* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp *//* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */#include "ppp.h"#if NPPP > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/file.h>#include <sys/kernel.h>#include <net/if.h>#include <net/if_types.h>#ifdef VJC#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <net/pppcompress.h>#endif#include <rtems.h>#include <rtems/libio.h>#include <sys/ttycom.h>#include <termios.h>#include <rtems/termiostypes.h>#ifdef PPP_FILTER#include <net/bpf.h>#endif#include <net/ppp_defs.h>#include <net/if_ppp.h>#include <net/if_pppvar.h>void pppasyncattach __P((void));int pppopen __P((struct rtems_termios_tty *tty));int pppclose __P((struct rtems_termios_tty *tty));int pppread __P((struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args));int pppwrite __P((struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args));int ppptioctl __P((struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args));int pppinput __P((int c, struct rtems_termios_tty *tty));int pppstart __P((struct rtems_termios_tty *tp));u_short pppfcs __P((u_short fcs, u_char *cp, int len));void pppallocmbuf __P((struct ppp_softc *sc, struct mbuf **mp));static void pppasyncstart __P((struct ppp_softc *));static void pppasyncctlp __P((struct ppp_softc *));static void pppasyncrelinq __P((struct ppp_softc *));/*static void ppp_timeout __P((void *)); *//*static void pppdumpb __P((u_char *b, int l)); *//*static void ppplogchar __P((struct ppp_softc *, int)); *//* * Some useful mbuf macros not in mbuf.h. */#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)#define M_DATASTART(m) \ (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)#define M_DATASIZE(m) \ (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)/* * We steal two bits in the mbuf m_flags, to mark high-priority packets * for output, and received packets following lost/corrupted packets. */#define M_HIGHPRI 0x2000 /* output packet for sc_fastq */#define M_ERRMARK 0x4000 /* steal a bit in mbuf m_flags *//* * Does c need to be escaped? */#define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))/* * Procedures for using an async tty interface for PPP. *//* This is a FreeBSD-2.0 kernel. */#define CCOUNT(rb) (((rb).Size+(rb).Head-(rb).Tail) % (rb).Size)#define FCOUNT(rb) ((rb).Size-CCOUNT(rb)-1)#define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */#define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que *//* * Define the PPP line discipline. */static struct linesw pppdisc = { pppopen, pppclose, pppread, pppwrite, pppinput, pppstart, ppptioctl, NULL};voidpppasyncattach(){ linesw[PPPDISC] = pppdisc;}TEXT_SET(pseudo_set, pppasyncattach);/* * Line specific open routine for async tty devices. * Attach the given tty to the first available ppp unit. * Called from device open routine or ttioctl. *//* ARGSUSED */intpppopen(struct rtems_termios_tty *tty){ int i; register struct ppp_softc *sc; struct mbuf *m = (struct mbuf *)0; extern int termios_baud_to_number(int); if (tty->t_line == PPPDISC) { sc = (struct ppp_softc *)tty->t_sc; if (sc != NULL && sc->sc_devp == (void *)tty) { return (0); } } if ((sc = pppalloc(1)) == NULL) { return ENXIO; } if (sc->sc_relinq) (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ sc->sc_ilen = 0; sc->sc_m = NULL; bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); sc->sc_asyncmap[0] = 0xffffffff; sc->sc_asyncmap[3] = 0x60000000; sc->sc_rasyncmap = 0; sc->sc_devp = tty; sc->sc_start = pppasyncstart; sc->sc_ctlp = pppasyncctlp; sc->sc_relinq = pppasyncrelinq; sc->sc_outm = NULL; sc->sc_outmc = NULL; /* preallocate mbufs for free queue */ rtems_bsdnet_semaphore_obtain(); for (i=0; i<NUM_MBUFQ; i++) { pppallocmbuf(sc, &m); if ( i == 0 ) { /* use first mbuf for rx iterrupt handling */ sc->sc_m = m; } else { /* enqueue mbuf for later use */ IF_ENQUEUE(&sc->sc_freeq, m); } m = (struct mbuf *)0; } rtems_bsdnet_semaphore_release(); /* initialize values */ sc->sc_if.if_flags |= IFF_RUNNING; sc->sc_if.if_baudrate = termios_baud_to_number(tty->termios.c_cflag & CBAUD); tty->t_sc = (void *)sc; return ( RTEMS_SUCCESSFUL );}/* * Line specific close routine, called from device close routine * and from ttioctl. * Detach the tty from the ppp unit. * Mimics part of ttyclose(). */intpppclose(struct rtems_termios_tty *tty){ register struct ppp_softc *sc; tty->t_line = 0; sc = (struct ppp_softc *)tty->t_sc; if (sc != NULL) { tty->t_sc = NULL; if (tty == (struct rtems_termios_tty *)sc->sc_devp) { rtems_bsdnet_semaphore_obtain(); pppasyncrelinq(sc); pppdealloc(sc); rtems_bsdnet_semaphore_release(); } } return ( RTEMS_SUCCESSFUL );}/* * Relinquish the interface unit to another device. */static voidpppasyncrelinq(sc) struct ppp_softc *sc;{#ifdef XXX_XXX if (sc->sc_outm) { m_freem(sc->sc_outm); sc->sc_outm = NULL; } if (sc->sc_m) { m_freem(sc->sc_m); sc->sc_m = NULL; } if (sc->sc_flags & SC_TIMEOUT) { untimeout(ppp_timeout, (void *) sc); sc->sc_flags &= ~SC_TIMEOUT; }#endif}/* * Line specific (tty) read routine. */intpppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args){ rtems_status_code status = RTEMS_UNSATISFIED; int count = 0; int maximum = rw_args->count; char *buffer = rw_args->buffer; register struct ppp_softc *sc = (struct ppp_softc *)tty->t_sc; struct mbuf *m; struct mbuf *m0; u_char *p; if (sc == NULL) { return 0; } /* * Loop waiting for input, checking that nothing disasterous * happens in the meantime. */ if (tty != (struct rtems_termios_tty *)sc->sc_devp || tty->t_line != PPPDISC) { return ( status ); } if (sc->sc_inq.ifq_head == NULL) { return ( status ); } /* Get the packet from the input queue */ rtems_bsdnet_semaphore_obtain(); IF_DEQUEUE(&sc->sc_inq, m0); /* loop over mbuf chain */ m = m0; while (( m != NULL ) && ( m->m_len > 0 ) && ( count+m->m_len < maximum )) { /* copy data into buffer */ p = mtod(m, u_char *); memcpy(buffer, p, m->m_len); memset(p, 0, m->m_len); count += m->m_len; buffer += m->m_len; /* increment loop index */ m = m->m_next; } /* free mbuf chain */ m_freem(m0); rtems_bsdnet_semaphore_release(); /* update return values */ rw_args->bytes_moved = count; if ( count >= 0 ) { status = RTEMS_SUCCESSFUL; } /* check to see if queue is empty */ if (sc->sc_inq.ifq_head != NULL) { /* queue is not empty - post another event to ourself */ rtems_event_send(sc->sc_pppdtask, PPPD_EVENT); } return ( status );}/* * Line specific (tty) write routine. */intpppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args){ struct sockaddr dst; int n; int len; int maximum = rw_args->count; char *out_buffer = rw_args->buffer; register struct ppp_softc *sc = (struct ppp_softc *)tty->t_sc; struct mbuf *m; struct mbuf *m0; struct mbuf **mp; rtems_bsdnet_semaphore_obtain(); for (mp = &m0; maximum; mp = &m->m_next) { MGET(m, M_WAIT, MT_DATA); if ((*mp = m) == NULL) { m_freem(m0); return (ENOBUFS); } m->m_len = 0; if (maximum >= MCLBYTES / 2) { MCLGET(m, M_DONTWAIT); } len = M_TRAILINGSPACE(m); if (len > maximum) { memcpy(mtod(m, u_char *),out_buffer,maximum); m->m_len = maximum; maximum = 0; } else { memcpy(mtod(m, u_char *),out_buffer,len); m->m_len = len; maximum -= len; out_buffer += len; } } dst.sa_family = AF_UNSPEC; bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); m0->m_data += PPP_HDRLEN; m0->m_len -= PPP_HDRLEN; n = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0); rtems_bsdnet_semaphore_release(); return ( n );}/* * Line specific (tty) ioctl routine. * This discipline requires that tty device drivers call * the line specific l_ioctl routine from their ioctl routines. *//* ARGSUSED */intppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args){/* int i; */ int error = RTEMS_SUCCESSFUL; int cmd = args->command; caddr_t data = args->buffer; struct ppp_softc *sc = tty->t_sc; switch (cmd) { case RTEMS_IO_GET_ATTRIBUTES: case RTEMS_IO_SET_ATTRIBUTES: case RTEMS_IO_TCDRAIN: case RTEMS_IO_SNDWAKEUP: case RTEMS_IO_RCVWAKEUP: case TIOCGETD: case TIOCSETD: error = rtems_termios_ioctl(args); break; case PPPIOCSASYNCMAP: sc->sc_asyncmap[0] = *(u_int *)data; break; case PPPIOCGASYNCMAP: *(u_int *)data = sc->sc_asyncmap[0]; break; case PPPIOCSRASYNCMAP: sc->sc_rasyncmap = *(u_int *)data; break; case PPPIOCGRASYNCMAP: *(u_int *)data = sc->sc_rasyncmap; break; case PPPIOCSXASYNCMAP: bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ break; case PPPIOCGXASYNCMAP: bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); break; default: rtems_bsdnet_semaphore_obtain(); error = pppioctl(sc, cmd, data, 0, NULL); rtems_bsdnet_semaphore_release(); } return error;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -