📄 if_ppp.c
字号:
/* * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. * * 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). *//* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */#include "ppp.h"#if NPPP > 0#define VJC#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/mbuf.h>#include <sys/buf.h>#include <sys/dkstat.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/file.h>#include <sys/tty.h>#include <sys/kernel.h>#include <sys/conf.h>#include <sys/vnode.h>#include <sys/kernel.h>#include <net/if.h>#include <net/if_types.h>#include <net/netisr.h>#include <net/route.h>#if INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#endif#include "bpfilter.h"#if NBPFILTER > 0#include <sys/time.h>#include <net/bpf.h>#endif#ifdef VJC#include <net/pppcompress.h>#define HDROFF MAX_HDR/* HDROFF should really be 128, but other parts of the system will panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */#else#define HDROFF (0)#endif#include <net/if_ppp.h>#include <machine/cpu.h>/* This is a FreeBSD-2.x kernel. */#define CCOUNT(q) ((q)->c_cc)#define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */#define PPP_MAXMTU 16384 /* Largest MTU we allow */struct ppp_softc ppp_softc[NPPP];void pppattach __P((void));int pppopen __P((dev_t dev, struct tty *tp));int pppclose __P((struct tty *tp, int flag));int pppread __P((struct tty *tp, struct uio *uio, int flag));int pppwrite __P((struct tty *tp, struct uio *uio, int flag));int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag, struct proc *));int pppoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *));int pppinput __P((int c, struct tty *tp));int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data));int pppstart __P((struct tty *tp));static struct linesw pppdisc = { pppopen, pppclose, pppread, pppwrite, ppptioctl, pppinput, pppstart, ttymodem};extern struct ppp_softc *pppalloc __P((pid_t pid));extern void pppdealloc __P((struct ppp_softc *sc));extern struct mbuf *ppp_dequeue __P((struct ppp_softc *sc));extern int ppppktin __P((struct ppp_softc *sc, struct mbuf *m, int ilen));static int pppasyncstart __P((struct ppp_softc *));static u_short pppfcs __P((u_short fcs, u_char *cp, int len));static int pppgetm __P((struct ppp_softc *sc));static struct mbuf *ppp_btom __P((struct ppp_softc *sc));static void pppdumpm __P((struct mbuf *m0, int pktlen));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_DATASTART(m) \ ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \ (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)#define M_DATASIZE(m) \ ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \ (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)/* * The following disgusting hack gets around the problem that IP TOS * can't be set yet. We want to put "interactive" traffic on a high * priority queue. To decide if traffic is interactive, we check that * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. */static u_short interactive_ports[8] = { 0, 513, 0, 0, 0, 21, 0, 23,};#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))/* * Does c need to be escaped? */#define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))/* * Called from boot code to establish ppp interfaces. */voidpppattach(){ register struct ppp_softc *sc; register int i = 0; linesw[PPPDISC] = pppdisc; for (sc = ppp_softc; i < NPPP; sc++) { sc->sc_if.if_name = "ppp"; sc->sc_if.if_unit = i++; sc->sc_if.if_mtu = PPP_MTU; sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; sc->sc_if.if_type = IFT_PPP; sc->sc_if.if_hdrlen = PPP_HDRLEN; sc->sc_if.if_ioctl = pppioctl; sc->sc_if.if_output = pppoutput; sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; if_attach(&sc->sc_if);#if NBPFILTER > 0 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);#endif }}/* * Allocate a ppp interface unit and initialize it. */struct ppp_softc *pppalloc(pid) pid_t pid;{ int nppp; struct ppp_softc *sc; for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) if (sc->sc_xfer == pid) { sc->sc_xfer = 0; break; } if (nppp >= NPPP) for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) if (sc->sc_devp == NULL) break; if (nppp >= NPPP) return NULL; sc->sc_flags = 0; sc->sc_mru = PPP_MRU;#ifdef VJC sl_compress_init(&sc->sc_comp);#endif sc->sc_if.if_flags |= IFF_RUNNING; microtime(&sc->sc_if.if_lastchange); return sc;}/* * Deallocate a ppp unit. */voidpppdealloc(sc) struct ppp_softc *sc;{ struct mbuf *m; if_down(&sc->sc_if); sc->sc_devp = NULL; sc->sc_xfer = 0; for (;;) { IF_DEQUEUE(&sc->sc_inq, m); if (m == NULL) break; m_freem(m); } for (;;) { IF_DEQUEUE(&sc->sc_fastq, m); if (m == NULL) break; m_freem(m); } sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); microtime(&sc->sc_if.if_lastchange);}/* * Line specific open routine for async tty devices. * Attach the given tty to the first available ppp unit. *//* ARGSUSED */intpppopen(dev, tp) dev_t dev; register struct tty *tp;{ struct proc *p = curproc; /* XXX */ register struct ppp_softc *sc; int error, s, i; if (error = suser(p->p_ucred, &p->p_acflag)) return (error); if (tp->t_line == PPPDISC) { sc = (struct ppp_softc *) tp->t_sc; if (sc != NULL && sc->sc_devp == (void *) tp) return (0); } if ((sc = pppalloc(p->p_pid)) == NULL) return ENXIO; if (sc->sc_outm != NULL) { m_freem(sc->sc_outm); sc->sc_outm = NULL; } if (pppgetm(sc) == 0) { sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); microtime(&sc->sc_if.if_lastchange); return (ENOBUFS); } sc->sc_ilen = 0; 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 = (void *) tp; sc->sc_start = pppasyncstart; tp->t_sc = (caddr_t) sc; ttyflush(tp, FREAD | FWRITE); /* * XXX we fudge t_canq to avoid providing pppselect() and FIONREAD. * I hope one char is enough. The following actually gives CBSIZE * chars. */ clist_alloc_cblocks(&tp->t_canq, 1, 1); clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT, sc->sc_if.if_mtu + PPP_HIWAT); clist_alloc_cblocks(&tp->t_rawq, 0, 0); return (0);}/* * Line specific close routine. * Detach the tty from the ppp unit. * Mimics part of ttyclose(). */intpppclose(tp, flag) struct tty *tp; int flag;{ register struct ppp_softc *sc; struct mbuf *m; int s; ttyflush(tp, FREAD | FWRITE); s = splimp(); /* paranoid; splnet probably ok */ clist_free_cblocks(&tp->t_canq); clist_free_cblocks(&tp->t_outq); tp->t_line = 0; sc = (struct ppp_softc *)tp->t_sc; if (sc != NULL) { tp->t_sc = NULL; if (tp == (struct tty *) sc->sc_devp) { m_freem(sc->sc_outm); sc->sc_outm = NULL; m_freem(sc->sc_m); sc->sc_m = NULL; pppdealloc(sc); } } splx(s); return (0); /* success */}/* * Line specific (tty) read routine. */intpppread(tp, uio, flag) register struct tty *tp; struct uio *uio; int flag;{ register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; struct mbuf *m, *m0; register int s; int error = 0; if ((tp->t_state & TS_CONNECTED) == 0) return 0; /* end of file */ if (sc == NULL || tp != (struct tty *) sc->sc_devp) return 0; s = splimp(); while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) { if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { splx(s); return (EWOULDBLOCK); } error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0); if (error) return error; } if (tp->t_line != PPPDISC) { splx(s); return (-1); } /* Pull place-holder byte out of canonical queue */ getc(&tp->t_canq); /* Get the packet from the input queue */ IF_DEQUEUE(&sc->sc_inq, m0); splx(s); for (m = m0; m && uio->uio_resid; m = m->m_next) if (error = uiomove(mtod(m, u_char *), m->m_len, uio)) break; m_freem(m0); return (error);}/* * Line specific (tty) write routine. */intpppwrite(tp, uio, flag) register struct tty *tp; struct uio *uio; int flag;{ register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; struct mbuf *m, *m0, **mp; struct sockaddr dst; struct ppp_header *ph1, *ph2; int len, error; if ((tp->t_state & TS_CONNECTED) == 0) return 0; /* wrote 0 bytes */ if (tp->t_line != PPPDISC) return (EINVAL); if (sc == NULL || tp != (struct tty *) sc->sc_devp) return EIO; if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || uio->uio_resid < PPP_HDRLEN) return (EMSGSIZE); for (mp = &m0; uio->uio_resid; mp = &m->m_next) { MGET(m, M_WAIT, MT_DATA); if ((*mp = m) == NULL) { m_freem(m0); return (ENOBUFS); } m->m_len=0; if (uio->uio_resid >= MCLBYTES / 2) MCLGET(m, M_DONTWAIT); len = M_TRAILINGSPACE(m); if (len > uio->uio_resid) len = uio->uio_resid; if (error = uiomove(mtod(m, u_char *), len, uio)) { m_freem(m0); return (error); } m->m_len = len; } dst.sa_family = AF_UNSPEC; ph1 = (struct ppp_header *) &dst.sa_data; ph2 = mtod(m0, struct ppp_header *); *ph1 = *ph2; m0->m_data += PPP_HDRLEN; m0->m_len -= PPP_HDRLEN; return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));}/* * Line specific (tty) ioctl routine. * Provide a way to get the ppp unit number. * This discipline requires that tty device drivers call * the line specific l_ioctl routine from their ioctl routines. *//* ARGSUSED */intppptioctl(tp, cmd, data, flag, p) struct tty *tp; caddr_t data; int cmd, flag; struct proc *p;{ register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; int s, error, flags, mru; if (sc == NULL || tp != (struct tty *) sc->sc_devp) return -1; switch (cmd) { case FIONREAD: *(int *)data = sc->sc_inq.ifq_len; break; case PPPIOCGUNIT: *(int *)data = sc->sc_if.if_unit; break; case PPPIOCGFLAGS: *(u_int *)data = sc->sc_flags; break; case PPPIOCSFLAGS: if (error = suser(p->p_ucred, &p->p_acflag)) return (error); flags = *(int *)data & SC_MASK; s = splimp(); sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; splx(s); break; case PPPIOCSASYNCMAP: if (error = suser(p->p_ucred, &p->p_acflag)) return (error); sc->sc_asyncmap[0] = *(u_int *)data; break; case PPPIOCGASYNCMAP: *(u_int *)data = sc->sc_asyncmap[0]; break; case PPPIOCSRASYNCMAP: if (error = suser(p->p_ucred, &p->p_acflag)) return (error); sc->sc_rasyncmap = *(u_int *)data; break; case PPPIOCGRASYNCMAP: *(u_int *)data = sc->sc_rasyncmap; break; case PPPIOCSXASYNCMAP: if (error = suser(p->p_ucred, &p->p_acflag)) return (error); 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; case PPPIOCSMRU: if (error = suser(p->p_ucred, &p->p_acflag)) return (error);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -