/*
* ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
*
- * Copyright (c) 1994 The Australian National University.
- * All rights reserved.
+ * Copyright (c) 1994 Paul Mackerras. 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.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
*
- * 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.
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
*
- * 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
- * $Id: ppp.c,v 1.17 1999/03/08 05:34:16 paulus Exp $
+ * 3. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ppp.c,v 1.26 2002/12/06 09:49:15 paulus Exp $
*/
/*
#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>
* interactive traffic, and are due to Marko Zec <zec@japa.tel.fer.hr>.
*/
#ifdef PRIOQ
-#include <netinet/in.h>
#endif /* PRIOQ */
+#include <netinet/in.h> /* leave this outside of PRIOQ for htons */
+
#ifdef __STDC__
#define __P(x) x
#else
#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
#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 PRIOQ
static u_char max_band=0;
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_PACKETS
static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+#endif /* FILTER_PACKETS */
#define PPP_ID 0xb1a6
static struct module_info ppp_info = {
queue_t *q;
mblk_t *mp;
{
- upperstr_t *us, *usnext, *ppa, *os, *nps;
+ upperstr_t *us, *ppa, *nps;
struct iocblk *iop;
struct linkblk *lb;
#ifdef LACHTCP
int error, n, sap;
mblk_t *mq;
struct ppp_idle *pip;
- int len;
#ifdef PRIOQ
queue_t *tlq;
#endif /* PRIOQ */
+#ifdef NO_DLPI
+ upperstr_t *os;
+#endif
us = (upperstr_t *) q->q_ptr;
if (us == 0) {
DPRINT3("ppp/%d: ioctl %x count=%d\n",
us->mn, iop->ioc_cmd, iop->ioc_count);
switch (iop->ioc_cmd) {
+#if defined(SOL2)
+ case DLIOCRAW: /* raw M_DATA mode */
+ us->flags |= US_RAWDATA;
+ error = 0;
+ break;
+#endif /* defined(SOL2) */
case I_LINK:
if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
break;
if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
qwriter(q, NULL, debug_dump, PERIM_OUTER);
iop->ioc_count = 0;
- error = 0;
+ error = -1;
} else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
DPRINT1("ppp/%d: debug log enabled\n", us->mn);
us->flags |= US_DBGLOG;
break;
}
sap = ((int *)mp->b_cont->b_rptr)[0];
- for (nps = us->next; nps != 0; nps = nps->next)
+ for (nps = us->next; nps != 0; nps = nps->next) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("us = 0x%x, us->next->sap = 0x%x\n", nps, nps->sap);
if (nps->sap == sap)
break;
+ }
if (nps == 0) {
if (us->flags & US_DBGLOG)
DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
int size = mp->b_wptr - mp->b_rptr;
mblk_t *reply, *np;
upperstr_t *ppa, *os;
- int sap, *ip, len;
+ int sap, len;
dl_info_ack_t *info;
dl_bind_ack_t *ackp;
+#if DL_CURRENT_VERSION >= 2
+ dl_phys_addr_ack_t *paddrack;
+ static struct ether_addr eaddr = {0};
+#endif
if (us->flags & US_DBGLOG)
DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU;
info->dl_min_sdu = 1;
info->dl_addr_length = sizeof(uint);
-#if 0
-#ifdef DL_OTHER
- info->dl_mac_type = DL_OTHER;
-#else
- info->dl_mac_type = DL_HDLC; /* a lie */
-#endif
-#else
info->dl_mac_type = DL_ETHER; /* a bigger lie */
-#endif
info->dl_current_state = us->state;
info->dl_service_mode = DL_CLDLS;
info->dl_provider_style = DL_STYLE2;
}
us->ppa = ppa;
qwriter(q, mp, attach_ppa, PERIM_OUTER);
- break;
+ return;
case DL_DETACH_REQ:
if (size < sizeof(dl_detach_req_t))
break;
}
qwriter(q, mp, detach_ppa, PERIM_OUTER);
- break;
+ return;
case DL_BIND_REQ:
if (size < sizeof(dl_bind_req_t))
except that we accept ETHERTYPE_IP in place of PPP_IP. */
sap = d->bind_req.dl_sap;
us->req_sap = sap;
+
+#if defined(SOL2)
+ if (us->flags & US_DBGLOG)
+ DPRINT2("DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x", sap, us);
+
+ if (sap == ETHERTYPE_IP) /* normal IFF_IPV4 */
+ sap = PPP_IP;
+ else if (sap == ETHERTYPE_IPV6) /* when IFF_IPV6 is set */
+ sap = PPP_IPV6;
+ else if (sap == ETHERTYPE_ALLSAP) /* snoop gives sap of 0 */
+ sap = PPP_ALLSAP;
+ else {
+ DPRINT2("DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x", sap, us);
+ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+ break;
+ }
+#else
if (sap == ETHERTYPE_IP)
sap = PPP_IP;
if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) {
dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
break;
}
+#endif /* defined(SOL2) */
/* check that no other stream is bound to this sap already. */
for (os = us->ppa; os != 0; os = os->next)
DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
break;
}
+
+#if defined(SOL2)
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ if (mp->b_cont)
+ promisc_sendup(ppa, mp->b_cont, us->sap, 0);
+#endif /* defined(SOL2) */
+
mp->b_band = 0;
#ifdef PRIOQ
/* Extract s_port & d_port from IP-packet, the code is a bit
return;
#if DL_CURRENT_VERSION >= 2
+ case DL_PHYS_ADDR_REQ:
+ if (size < sizeof(dl_phys_addr_req_t))
+ goto badprim;
+
+ /*
+ * Don't check state because ifconfig sends this one down too
+ */
+
+ if ((reply = allocb(sizeof(dl_phys_addr_ack_t)+ETHERADDRL,
+ BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ paddrack = (dl_phys_addr_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_phys_addr_ack_t);
+ bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
+ paddrack->dl_primitive = DL_PHYS_ADDR_ACK;
+ paddrack->dl_addr_length = ETHERADDRL;
+ paddrack->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
+ bcopy(&eaddr, reply->b_wptr, ETHERADDRL);
+ reply->b_wptr += ETHERADDRL;
+ qreply(q, reply);
+ break;
+
+#if defined(SOL2)
+ case DL_PROMISCON_REQ:
+ if (size < sizeof(dl_promiscon_req_t))
+ goto badprim;
+ us->flags |= US_PROMISC;
+ dlpi_ok(q, DL_PROMISCON_REQ);
+ break;
+
+ case DL_PROMISCOFF_REQ:
+ if (size < sizeof(dl_promiscoff_req_t))
+ goto badprim;
+ us->flags &= ~US_PROMISC;
+ dlpi_ok(q, DL_PROMISCOFF_REQ);
+ break;
+#else
+ case DL_PROMISCON_REQ: /* fall thru */
+ case DL_PROMISCOFF_REQ: /* fall thru */
+#endif /* defined(SOL2) */
+#endif /* DL_CURRENT_VERSION >= 2 */
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_SET_PHYS_ADDR_REQ:
case DL_SUBS_BIND_REQ:
case DL_SUBS_UNBIND_REQ:
case DL_ENABMULTI_REQ:
case DL_DISABMULTI_REQ:
- case DL_PROMISCON_REQ:
- case DL_PROMISCOFF_REQ:
- case DL_PHYS_ADDR_REQ:
- case DL_SET_PHYS_ADDR_REQ:
case DL_XID_REQ:
case DL_TEST_REQ:
case DL_REPLY_UPDATE_REQ:
mblk_t *mp;
upperstr_t *us;
{
- queue_t *q;
upperstr_t *ppa;
if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
freemsg(mp);
return 1;
}
- if ((q = ppa->lowerq) == 0) {
+ if (ppa->lowerq == 0) {
/* try to send it up the control stream */
if (bcanputnext(ppa->q, mp->b_band)) {
/*
mblk_t *mp;
{
upperstr_t *ppa, *us;
- queue_t *uq;
int proto, len;
- mblk_t *np;
struct iocblk *iop;
ppa = (upperstr_t *) q->q_ptr;
MT_EXIT(&ppa->stats_lock);
proto = PPP_PROTOCOL(mp->b_rptr);
+
+#if defined(SOL2)
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ promisc_sendup(ppa, mp, proto, 1);
+#endif /* defined(SOL2) */
+
if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
/*
* A data packet for some network protocol.
return us;
}
+#if defined (SOL2)
+/*
+ * Test upstream promiscuous conditions. As of now, only pass IPv4 and
+ * Ipv6 packets upstream (let PPP packets be decoded elsewhere).
+ */
+static upperstr_t *
+find_promisc(us, proto)
+ upperstr_t *us;
+ int proto;
+{
+
+ if ((proto != PPP_IP) && (proto != PPP_IPV6))
+ return (upperstr_t *)0;
+
+ for ( ; us; us = us->next) {
+ if ((us->flags & US_PROMISC) && (us->state == DL_IDLE))
+ return us;
+ }
+
+ return (upperstr_t *)0;
+}
+
+/*
+ * Prepend an empty Ethernet header to msg for snoop, et al.
+ */
+static mblk_t *
+prepend_ether(us, mp, proto)
+ upperstr_t *us;
+ mblk_t *mp;
+ int proto;
+{
+ mblk_t *eh;
+ int type;
+
+ if ((eh = allocb(sizeof(struct ether_header), BPRI_HI)) == 0) {
+ freemsg(mp);
+ return (mblk_t *)0;
+ }
+
+ if (proto == PPP_IP)
+ type = ETHERTYPE_IP;
+ else if (proto == PPP_IPV6)
+ type = ETHERTYPE_IPV6;
+ else
+ type = proto; /* What else? Let decoder decide */
+
+ eh->b_wptr += sizeof(struct ether_header);
+ bzero((caddr_t)eh->b_rptr, sizeof(struct ether_header));
+ ((struct ether_header *)eh->b_rptr)->ether_type = htons((short)type);
+ eh->b_cont = mp;
+ return (eh);
+}
+
+/*
+ * Prepend DL_UNITDATA_IND mblk to msg
+ */
+static mblk_t *
+prepend_udind(us, mp, proto)
+ upperstr_t *us;
+ mblk_t *mp;
+ int proto;
+{
+ dl_unitdata_ind_t *dlu;
+ mblk_t *dh;
+ size_t size;
+
+ size = sizeof(dl_unitdata_ind_t);
+ if ((dh = allocb(size, BPRI_MED)) == 0) {
+ freemsg(mp);
+ return (mblk_t *)0;
+ }
+
+ dh->b_datap->db_type = M_PROTO;
+ dh->b_wptr = dh->b_datap->db_lim;
+ dh->b_rptr = dh->b_wptr - size;
+
+ dlu = (dl_unitdata_ind_t *)dh->b_rptr;
+ dlu->dl_primitive = DL_UNITDATA_IND;
+ dlu->dl_dest_addr_length = 0;
+ dlu->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+ dlu->dl_src_addr_length = 0;
+ dlu->dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
+ dlu->dl_group_address = 0;
+
+ dh->b_cont = mp;
+ return (dh);
+}
+
+/*
+ * For any recognized promiscuous streams, send data upstream
+ */
+static void
+promisc_sendup(ppa, mp, proto, skip)
+ upperstr_t *ppa;
+ mblk_t *mp;
+ int proto, skip;
+{
+ mblk_t *dup_mp, *dup_dup_mp;
+ upperstr_t *prus, *nprus;
+
+ if ((prus = find_promisc(ppa, proto)) != 0) {
+ if (dup_mp = dupmsg(mp)) {
+
+ if (skip)
+ dup_mp->b_rptr += PPP_HDRLEN;
+
+ for ( ; nprus = find_promisc(prus->next, proto);
+ prus = nprus) {
+
+ if (dup_dup_mp = dupmsg(dup_mp)) {
+ if (canputnext(prus->q)) {
+ if (prus->flags & US_RAWDATA) {
+ dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
+ putnext(prus->q, dup_dup_mp);
+ } else {
+ dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
+ putnext(prus->q, dup_dup_mp);
+ }
+ } else {
+ DPRINT("ppp_urput: data to promisc q dropped\n");
+ freemsg(dup_dup_mp);
+ }
+ }
+ }
+
+ if (canputnext(prus->q)) {
+ if (prus->flags & US_RAWDATA) {
+ dup_mp = prepend_ether(prus, dup_mp, proto);
+ putnext(prus->q, dup_mp);
+ } else {
+ dup_mp = prepend_udind(prus, dup_mp, proto);
+ putnext(prus->q, dup_mp);
+ }
+ } else {
+ DPRINT("ppp_urput: data to promisc q dropped\n");
+ freemsg(dup_mp);
+ }
+ }
+ }
+}
+#endif /* defined(SOL2) */
+
/*
* We simply put the message on to the associated upper control stream
* (either here or in ppplrsrv). That way we enter the perimeters
mblk_t *mp;
{
queue_t *uq;
+ struct iocblk *iop;
+
+ switch (mp->b_datap->db_type) {
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ iop->ioc_error = EINVAL;
+ mp->b_datap->db_type = M_IOCNAK;
+ qreply(q, mp);
+ return 0;
+ case M_FLUSH:
+ if (*mp->b_rptr & FLUSHR)
+ flushq(q, FLUSHDATA);
+ if (*mp->b_rptr & FLUSHW) {
+ *mp->b_rptr &= ~FLUSHR;
+ qreply(q, mp);
+ } else
+ freemsg(mp);
+ return 0;
+ }
/*
* If we can't get the lower lock straight away, queue this one
static void
debug_dump(q, mp)
- queue_t *q; /* not used */
- mblk_t *mp; /* not used either */
+ queue_t *q;
+ mblk_t *mp;
{
upperstr_t *us;
queue_t *uq, *lq;
(lq? qsize(lq): 0), us->mru, us->mtu);
}
}
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
}
#ifdef FILTER_PACKETS