]> git.ozlabs.org Git - ppp.git/blobdiff - modules/ppp.c
Install Microsoft dictionaries (patch from Frank Cusack)
[ppp.git] / modules / ppp.c
index d033f6e173196303a70f4821809df1986e27b7cb..0ed435b9904404a888415698076fd640b14ea70f 100644 (file)
@@ -24,7 +24,7 @@
  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
  * OR MODIFICATIONS.
  *
- * $Id: ppp.c,v 1.21 1999/09/15 23:49:05 masputra Exp $
+ * $Id: ppp.c,v 1.25 1999/10/08 01:10:12 masputra Exp $
  */
 
 /*
@@ -54,6 +54,7 @@
 #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
@@ -193,6 +207,12 @@ typedef struct upperstr {
 #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;
@@ -252,6 +272,12 @@ 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));
@@ -572,6 +598,9 @@ pppuwput(q, mp)
 #ifdef PRIOQ
     queue_t *tlq;
 #endif /* PRIOQ */
+#ifdef NO_DLPI
+    upperstr_t *os;
+#endif
 
     us = (upperstr_t *) q->q_ptr;
     if (us == 0) {
@@ -622,6 +651,12 @@ pppuwput(q, mp)
            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;
@@ -834,9 +869,12 @@ pppuwput(q, mp)
                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);
@@ -1046,6 +1084,10 @@ dlpi_request(q, mp, us)
     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,
@@ -1064,15 +1106,7 @@ dlpi_request(q, mp, us)
        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;
@@ -1131,23 +1165,29 @@ dlpi_request(q, mp, us)
        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)
@@ -1207,6 +1247,16 @@ dlpi_request(q, mp, us)
            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
@@ -1294,14 +1344,55 @@ dlpi_request(q, mp, us)
        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:
@@ -1792,6 +1883,15 @@ pppurput(q, mp)
            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.
@@ -1965,6 +2065,148 @@ find_dest(ppa, proto)
     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