📄 ppp.c
字号:
/* * ppp.c - STREAMS multiplexing pseudo-device driver for PPP. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies. This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * * $Id: ppp.c,v 1.1 2000/04/18 23:51:28 masputra Exp $ *//* * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX. */#include <sys/types.h>#include <sys/param.h>#include <sys/stat.h>#include <sys/stream.h>#include <sys/stropts.h>#include <sys/errno.h>#ifdef __osf__#include <sys/ioctl.h>#include <sys/cmn_err.h>#define queclass(mp) ((mp)->b_band & QPCTL)#else#include <sys/ioccom.h>#endif#include <sys/time.h>#ifdef SVR4#include <sys/cmn_err.h>#include <sys/conf.h>#include <sys/dlpi.h>#include <sys/ddi.h>#ifdef SOL2#include <sys/ksynch.h>#include <sys/kstat.h>#include <sys/sunddi.h>#include <sys/ethernet.h>#else#include <sys/socket.h>#include <sys/sockio.h>#include <net/if.h>#include <netinet/in.h>#endif /* SOL2 */#else /* not SVR4 */#include <sys/user.h>#endif /* SVR4 */#include <net/ppp_defs.h>#include <net/pppio.h>#include "ppp_mod.h"/* * Modifications marked with #ifdef PRIOQ are for priority queueing of * interactive traffic, and are due to Marko Zec <zec@japa.tel.fer.hr>. */#ifdef PRIOQ#endif /* PRIOQ */#include <netinet/in.h> /* leave this outside of PRIOQ for htons */#ifdef __STDC__#define __P(x) x#else#define __P(x) ()#endif/* * The IP module may use this SAP value for IP packets. */#ifndef ETHERTYPE_IP#define ETHERTYPE_IP 0x800#endif#if !defined(ETHERTYPE_IPV6) #define ETHERTYPE_IPV6 0x86dd#endif /* !defined(ETHERTYPE_IPV6) */#if !defined(ETHERTYPE_ALLSAP) && defined(SOL2)#define ETHERTYPE_ALLSAP 0#endif /* !defined(ETHERTYPE_ALLSAP) && defined(SOL2) */#if !defined(PPP_ALLSAP) && defined(SOL2)#define PPP_ALLSAP PPP_ALLSTATIONS#endif /* !defined(PPP_ALLSAP) && defined(SOL2) */extern time_t time;#ifdef SOL2/* * We use this reader-writer lock to ensure that the lower streams * stay connected to the upper streams while the lower-side put and * service procedures are running. Essentially it is an existence * lock for the upper stream associated with each lower stream. */krwlock_t ppp_lower_lock;#define LOCK_LOWER_W rw_enter(&ppp_lower_lock, RW_WRITER)#define LOCK_LOWER_R rw_enter(&ppp_lower_lock, RW_READER)#define TRYLOCK_LOWER_R rw_tryenter(&ppp_lower_lock, RW_READER)#define UNLOCK_LOWER rw_exit(&ppp_lower_lock)#define MT_ENTER(x) mutex_enter(x)#define MT_EXIT(x) mutex_exit(x)/* * Notes on multithreaded implementation for Solaris 2: * * We use an inner perimeter around each queue pair and an outer * perimeter around the whole driver. The inner perimeter is * entered exclusively for all entry points (open, close, put, * service). The outer perimeter is entered exclusively for open * and close and shared for put and service. This is all done for * us by the streams framework. * * I used to think that the perimeters were entered for the lower * streams' put and service routines as well as for the upper streams'. * Because of problems experienced by people, and after reading the * documentation more closely, I now don't think that is true. So we * now use ppp_lower_lock to give us an existence guarantee on the * upper stream controlling each lower stream. * * Shared entry to the outer perimeter protects the existence of all * the upper streams and their upperstr_t structures, and guarantees * that the following fields of any upperstr_t won't change: * nextmn, next, nextppa. It guarantees that the lowerq field of an * upperstr_t won't go from non-zero to zero, that the global `ppas' * won't change and that the no lower stream will get unlinked. * * Shared (reader) access to ppa_lower_lock guarantees that no lower * stream will be unlinked and that the lowerq field of all upperstr_t * structures won't change. */#else /* SOL2 */#define LOCK_LOWER_W 0#define LOCK_LOWER_R 0#define TRYLOCK_LOWER_R 1#define UNLOCK_LOWER 0#define MT_ENTER(x) 0#define MT_EXIT(x) 0#endif /* SOL2 *//* * Private information; one per upper stream. */typedef struct upperstr { minor_t mn; /* minor device number */ struct upperstr *nextmn; /* next minor device */ queue_t *q; /* read q associated with this upper stream */ int flags; /* flag bits, see below */ int state; /* current DLPI state */ int sap; /* service access point */ int req_sap; /* which SAP the DLPI client requested */ struct upperstr *ppa; /* control stream for our ppa */ struct upperstr *next; /* next stream for this ppa */ uint ioc_id; /* last ioctl ID for this stream */ enum NPmode npmode; /* what to do with packets on this SAP */ unsigned char rblocked; /* flow control has blocked upper read strm */ /* N.B. rblocked is only changed by control stream's put/srv procs */ /* * There is exactly one control stream for each PPA. * The following fields are only used for control streams. */ int ppa_id; queue_t *lowerq; /* write queue attached below this PPA */ struct upperstr *nextppa; /* next control stream */ int mru; int mtu; struct pppstat stats; /* statistics */ time_t last_sent; /* time last NP packet sent */ time_t last_recv; /* time last NP packet rcvd */#ifdef SOL2 kmutex_t stats_lock; /* lock for stats updates */ kstat_t *kstats; /* stats for netstat */#endif /* SOL2 */#ifdef LACHTCP int ifflags; char ifname[IFNAMSIZ]; struct ifstats ifstats;#endif /* LACHTCP */} upperstr_t;/* Values for flags */#define US_PRIV 1 /* stream was opened by superuser */#define US_CONTROL 2 /* stream is a control stream */#define US_BLOCKED 4 /* flow ctrl has blocked lower write stream */#define US_LASTMOD 8 /* no PPP modules below us */#define US_DBGLOG 0x10 /* log various occurrences */#define US_RBLOCKED 0x20 /* flow ctrl has blocked upper read stream */#if defined(SOL2)#if DL_CURRENT_VERSION >= 2#define US_PROMISC 0x40 /* stream is promiscuous */#endif /* DL_CURRENT_VERSION >= 2 */#define US_RAWDATA 0x80 /* raw M_DATA, no DLPI header */#endif /* defined(SOL2) */#ifdef PRIOQstatic u_char max_band=0;static u_char def_band=0;#define IPPORT_DEFAULT 65535/* * Port priority table * Highest priority ports are listed first, lowest are listed last. * ICMP & packets using unlisted ports will be treated as "default". * If IPPORT_DEFAULT is not listed here, "default" packets will be * assigned lowest priority. * Each line should be terminated with "0". * Line containing only "0" marks the end of the list. */static u_short prioq_table[]= { 113, 53, 0, 22, 23, 513, 517, 518, 0, 514, 21, 79, 111, 0, 25, 109, 110, 0, IPPORT_DEFAULT, 0, 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */0 };#endif /* PRIOQ */static upperstr_t *minor_devs = NULL;static upperstr_t *ppas = NULL;#ifdef SVR4static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));static int pppclose __P((queue_t *, int, cred_t *));#elsestatic int pppopen __P((queue_t *, int, int, int));static int pppclose __P((queue_t *, int));#endif /* SVR4 */static int pppurput __P((queue_t *, mblk_t *));static int pppuwput __P((queue_t *, mblk_t *));static int pppursrv __P((queue_t *));static int pppuwsrv __P((queue_t *));static int ppplrput __P((queue_t *, mblk_t *));static int ppplwput __P((queue_t *, mblk_t *));static int ppplrsrv __P((queue_t *));static int ppplwsrv __P((queue_t *));#ifndef NO_DLPIstatic void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int));static void dlpi_ok __P((queue_t *, int));#endifstatic int send_data __P((mblk_t *, upperstr_t *));static void new_ppa __P((queue_t *, mblk_t *));static void attach_ppa __P((queue_t *, mblk_t *));static void detach_ppa __P((queue_t *, mblk_t *));static void detach_lower __P((queue_t *, mblk_t *));static void debug_dump __P((queue_t *, mblk_t *));static upperstr_t *find_dest __P((upperstr_t *, int));#if defined(SOL2)static upperstr_t *find_promisc __P((upperstr_t *, int));static mblk_t *prepend_ether __P((upperstr_t *, mblk_t *, int));static mblk_t *prepend_udind __P((upperstr_t *, mblk_t *, int));static void promisc_sendup __P((upperstr_t *, mblk_t *, int, int));#endif /* defined(SOL2) */static int putctl2 __P((queue_t *, int, int, int));static int putctl4 __P((queue_t *, int, int, int));static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));#ifdef FILTER_PACKETSstatic int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));#endif /* FILTER_PACKETS */#define PPP_ID 0xb1a6static struct module_info ppp_info = {#ifdef PRIOQ PPP_ID, "ppp", 0, 512, 512, 384#else PPP_ID, "ppp", 0, 512, 512, 128#endif /* PRIOQ */};static struct qinit pppurint = { pppurput, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL};static struct qinit pppuwint = { pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL};static struct qinit ppplrint = { ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL};static struct qinit ppplwint = { ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL};#ifdef LACHTCPextern struct ifstats *ifstats;int pppdevflag = 0;#endifstruct streamtab pppinfo = { &pppurint, &pppuwint, &ppplrint, &ppplwint};int ppp_count;/* * How we maintain statistics. */#ifdef SOL2#define INCR_IPACKETS(ppa) \ if (ppa->kstats != 0) { \ KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++; \ }#define INCR_IERRORS(ppa) \ if (ppa->kstats != 0) { \ KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++; \ }#define INCR_OPACKETS(ppa) \ if (ppa->kstats != 0) { \ KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++; \ }#define INCR_OERRORS(ppa) \ if (ppa->kstats != 0) { \ KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++; \ }#endif#ifdef LACHTCP#define INCR_IPACKETS(ppa) ppa->ifstats.ifs_ipackets++;#define INCR_IERRORS(ppa) ppa->ifstats.ifs_ierrors++;#define INCR_OPACKETS(ppa) ppa->ifstats.ifs_opackets++;#define INCR_OERRORS(ppa) ppa->ifstats.ifs_oerrors++;#endif/* * STREAMS driver entry points. */static int#ifdef SVR4pppopen(q, devp, oflag, sflag, credp) queue_t *q; dev_t *devp; int oflag, sflag; cred_t *credp;#elsepppopen(q, dev, oflag, sflag) queue_t *q; int dev; /* really dev_t */ int oflag, sflag;#endif{ upperstr_t *up; upperstr_t **prevp; minor_t mn;#ifdef PRIOQ u_short *ptr; u_char new_band;#endif /* PRIOQ */ if (q->q_ptr) DRV_OPEN_OK(dev); /* device is already open */#ifdef PRIOQ /* Calculate max_bband & def_band from definitions in prioq.h This colud be done at some more approtiate time (less often) but this way it works well so I'll just leave it here */ max_band = 1; def_band = 0; ptr = prioq_table; while (*ptr) { new_band = 1; while (*ptr) if (*ptr++ == IPPORT_DEFAULT) { new_band = 0; def_band = max_band; } max_band += new_band; ptr++; } if (def_band) def_band = max_band - def_band; --max_band;#endif /* PRIOQ */ if (sflag == CLONEOPEN) { mn = 0; for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) { if (up->mn != mn) break; ++mn; } } else {#ifdef SVR4 mn = getminor(*devp);#else mn = minor(dev);#endif for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) { if (up->mn >= mn) break; } if (up->mn == mn) { /* this can't happen */ q->q_ptr = WR(q)->q_ptr = (caddr_t) up; DRV_OPEN_OK(dev); } } /* * Construct a new minor node. */ up = (upperstr_t *) ALLOC_SLEEP(sizeof(upperstr_t)); bzero((caddr_t) up, sizeof(upperstr_t)); if (up == 0) { DPRINT("pppopen: out of kernel memory\n"); OPEN_ERROR(ENXIO); } up->nextmn = *prevp; *prevp = up; up->mn = mn;#ifdef SVR4 *devp = makedevice(getmajor(*devp), mn);#endif up->q = q; if (NOTSUSER() == 0) up->flags |= US_PRIV;#ifndef NO_DLPI up->state = DL_UNATTACHED;#endif#ifdef LACHTCP up->ifflags = IFF_UP | IFF_POINTOPOINT;#endif up->sap = -1; up->last_sent = up->last_recv = time; up->npmode = NPMODE_DROP; q->q_ptr = (caddr_t) up; WR(q)->q_ptr = (caddr_t) up; noenable(WR(q));#ifdef SOL2 mutex_init(&up->stats_lock, NULL, MUTEX_DRIVER, NULL);#endif ++ppp_count; qprocson(q); DRV_OPEN_OK(makedev(major(dev), mn));}static int#ifdef SVR4pppclose(q, flag, credp) queue_t *q; int flag; cred_t *credp;#elsepppclose(q, flag) queue_t *q; int flag;#endif{ upperstr_t *up, **upp; upperstr_t *as, *asnext; upperstr_t **prevp; qprocsoff(q); up = (upperstr_t *) q->q_ptr; if (up == 0) { DPRINT("pppclose: q_ptr = 0\n"); return 0; } if (up->flags & US_DBGLOG) DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags); if (up->flags & US_CONTROL) {#ifdef LACHTCP struct ifstats *ifp, *pifp;#endif if (up->lowerq != 0) { /* Gack! the lower stream should have be unlinked earlier! */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -