/*
* 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.21 1999/09/15 23:49:05 masputra 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.
*/
/*
#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 */
-#ifdef __STDC__
-#define __P(x) x
-#else
-#define __P(x) ()
-#endif
+#include <netinet/in.h> /* leave this outside of PRIOQ for htons */
/*
* The IP module may use this SAP value for IP packets.
#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 upperstr_t *ppas = NULL;
#ifdef SVR4
-static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
-static int pppclose __P((queue_t *, int, cred_t *));
+static int pppopen(queue_t *, dev_t *, int, int, cred_t *);
+static int pppclose(queue_t *, int, cred_t *);
#else
-static int pppopen __P((queue_t *, int, int, int));
-static int pppclose __P((queue_t *, int));
+static int pppopen(queue_t *, int, int, int);
+static int pppclose(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 *));
+static int pppurput(queue_t *, mblk_t *);
+static int pppuwput(queue_t *, mblk_t *);
+static int pppursrv(queue_t *);
+static int pppuwsrv(queue_t *);
+static int ppplrput(queue_t *, mblk_t *);
+static int ppplwput(queue_t *, mblk_t *);
+static int ppplrsrv(queue_t *);
+static int ppplwsrv(queue_t *);
#ifndef NO_DLPI
-static 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));
+static void dlpi_request(queue_t *, mblk_t *, upperstr_t *);
+static void dlpi_error(queue_t *, upperstr_t *, int, int, int);
+static void dlpi_ok(queue_t *, int);
#endif
-static 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));
-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));
+static int send_data(mblk_t *, upperstr_t *);
+static void new_ppa(queue_t *, mblk_t *);
+static void attach_ppa(queue_t *, mblk_t *);
+static void detach_ppa(queue_t *, mblk_t *);
+static void detach_lower(queue_t *, mblk_t *);
+static void debug_dump(queue_t *, mblk_t *);
+static upperstr_t *find_dest(upperstr_t *, int);
+#if defined(SOL2)
+static upperstr_t *find_promisc(upperstr_t *, int);
+static mblk_t *prepend_ether(upperstr_t *, mblk_t *, int);
+static mblk_t *prepend_udind(upperstr_t *, mblk_t *, int);
+static void promisc_sendup(upperstr_t *, mblk_t *, int, int);
+#endif /* defined(SOL2) */
+static int putctl2(queue_t *, int, int, int);
+static int putctl4(queue_t *, int, int, int);
+static int pass_packet(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));
+static int ip_hard_filter(upperstr_t *ppa, mblk_t *mp, int outbound);
#endif /* FILTER_PACKETS */
#define PPP_ID 0xb1a6
#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;
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 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;
sap = d->bind_req.dl_sap;
us->req_sap = sap;
-#ifdef SOL2
- /*
- * ip will send a sap value of 0 (post-Solaris 7), or
- * ETHERTYPE_IP (0x800) (pre-Solaris 8) due to how the
- * ppp DLPI provider declares its characteristics.
- * <adi.masputra@sun.com>
- */
- if (sap == 0)
- sap = ETHERTYPE_IP;
-#endif /* SOL2 */
+#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:
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