* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
*
- * $Id: ppp.c,v 1.4 1995/06/01 02:22:12 paulus Exp $
+ * $Id: ppp.c,v 1.7 1995/10/27 03:55:56 paulus Exp $
*/
/*
#include <sys/modctl.h>
#include <sys/kstat.h>
#include <sys/sunddi.h>
+#else
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
#endif
#include <net/ppp_defs.h>
#include <net/pppio.h>
struct pppstat stats; /* statistics */
#ifdef sun
kstat_t *kstats; /* stats for netstat */
+#else
+ int ifflags;
+ char ifname[IFNAMSIZ];
+ struct ifstats ifstats;
#endif
} upperstr_t;
#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 */
static upperstr_t *minor_devs = NULL;
static upperstr_t *ppas = NULL;
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 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));
ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
};
-static struct streamtab pppinfo = {
+#ifndef sun
+extern struct ifstats *ifstats;
+int pppdevflag = 0;
+#else
+static
+#endif
+struct streamtab pppinfo = {
&pppurint, &pppuwint,
&ppplrint, &ppplwint
};
#endif /* sun */
#ifndef sun
+#define put(q, mp) ((*(q)->q_qinfo->qi_putp)((q), (mp)))
# define qprocson(q)
# define qprocsoff(q)
# define canputnext(q) canput((q)->q_next)
if (drv_priv(credp) == 0)
up->flags |= US_PRIV;
up->state = DL_UNATTACHED;
+#ifndef sun
+ up->ifflags = IFF_UP | IFF_POINTOPOINT;
+#endif
up->sap = -1;
q->q_ptr = up;
WR(q)->q_ptr = up;
qprocsoff(q);
up = (upperstr_t *) q->q_ptr;
+ if (up->flags & US_DBGLOG)
+ cmn_err(CE_CONT, "ppp/%d: close, flags=%x\n", up->mn, up->flags);
if (up == 0)
return 0;
if (up->flags & US_CONTROL) {
+#ifndef sun
+ struct ifstats *ifp, *pifp;
+#endif
/*
* This stream represents a PPA:
* For all streams attached to the PPA, clear their
*upp = up->nextppa;
break;
}
-
+#ifndef sun
+ /* Remove the statistics from the active list. */
+ for (ifp = ifstats, pifp = 0; ifp; ifp = ifp->ifs_next) {
+ if (ifp == &up->ifstats) {
+ if (pifp)
+ pifp->ifs_next = ifp->ifs_next;
+ else
+ ifstats = ifp->ifs_next;
+ break;
+ }
+ pifp = ifp;
+ }
+#endif
} else {
/*
* If this stream is attached to a PPA,
}
}
+#ifdef sun
if (up->kstats)
kstat_delete(up->kstats);
+#endif
q->q_ptr = NULL;
WR(q)->q_ptr = NULL;
upperstr_t *us, *usnext, *ppa;
struct iocblk *iop;
struct linkblk *lb;
+#ifndef sun
+ struct ifreq *ifr;
+ int i;
+#endif
queue_t *lq;
int error, n;
mblk_t *mq;
break;
case M_DATA:
+ if (us->flags & US_DBGLOG)
+ cmn_err(CE_CONT, "ppp/%d: uwput M_DATA len=%d flags=%x\n",
+ us->mn, msgdsize(mp), us->flags);
if ((us->flags & US_CONTROL) == 0
|| msgdsize(mp) > us->mtu + PPP_HDRLEN) {
#if DEBUG
case M_IOCTL:
iop = (struct iocblk *) mp->b_rptr;
error = EINVAL;
+ if (us->flags & US_DBGLOG)
+ cmn_err(CE_CONT, "ppp/%d: ioctl %x count=%d\n",
+ us->mn, iop->ioc_cmd, iop->ioc_count);
switch (iop->ioc_cmd) {
case I_LINK:
if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
us->lowerq = lq = lb->l_qbot;
lq->q_ptr = us;
RD(lq)->q_ptr = us;
+ noenable(RD(lq));
iop->ioc_count = 0;
error = 0;
us->flags &= ~US_LASTMOD;
if (n < PPP_MRU)
n = PPP_MRU;
us->mtu = n;
+#ifndef sun
+ us->ifstats.ifs_mtu = n;
+#endif
if (us->lowerq)
putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
error = 0;
error = 0;
break;
+ case PPPIO_DEBUG:
+ if (iop->ioc_count != sizeof(int))
+ break;
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
+ qwriter(q, NULL, debug_dump, PERIM_OUTER);
+ iop->ioc_count = 0;
+ error = 0;
+ } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
+ cmn_err(CE_CONT, "ppp/%d: debug log enabled\n", us->mn);
+ us->flags |= US_DBGLOG;
+ iop->ioc_count = 0;
+ error = 0;
+ } else {
+ if (us->ppa == 0 || us->ppa->lowerq == 0)
+ break;
+ putnext(us->ppa->lowerq, mp);
+ error = -1;
+ }
+ break;
+
+#ifndef sun
+ case SIOCSIFNAME:
+ printf("SIOCSIFNAME\n");
+ /* Sent from IP down to us. Attach the ifstats structure. */
+ if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
+ break;
+ ifr = (struct ifreq *)mp->b_cont->b_rptr;
+ /* Find the unit number in the interface name. */
+ for (i = 0; i < IFNAMSIZ; i++) {
+ if (ifr->ifr_name[i] == 0 ||
+ (ifr->ifr_name[i] >= '0' &&
+ ifr->ifr_name[i] <= '9'))
+ break;
+ else
+ us->ifname[i] = ifr->ifr_name[i];
+ }
+ us->ifname[i] = 0;
+
+ /* Convert the unit number to binary. */
+ for (n = 0; i < IFNAMSIZ; i++) {
+ if (ifr->ifr_name[i] == 0) {
+ break;
+ }
+ else {
+ n = n * 10 + ifr->ifr_name[i] - '0';
+ }
+ }
+
+ /* Verify the ppa. */
+ if (us->ppa->ppa_id != n)
+ break;
+ ppa = us->ppa;
+
+ /* Set up the netstat block. */
+ strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
+
+ ppa->ifstats.ifs_name = ppa->ifname;
+ ppa->ifstats.ifs_unit = n;
+ ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
+ ppa->ifstats.ifs_mtu = ppa->mtu;
+
+ /* Link in statistics used by netstat. */
+ ppa->ifstats.ifs_next = ifstats;
+ ifstats = &ppa->ifstats;
+
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case SIOCGIFFLAGS:
+ printf("SIOCGIFFLAGS\n");
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
+ error = 0;
+ break;
+
+ case SIOCSIFFLAGS:
+ printf("SIOCSIFFLAGS\n");
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
+ error = 0;
+ break;
+
+ case SIOCSIFADDR:
+ printf("SIOCSIFADDR\n");
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ us->ifflags |= IFF_RUNNING;
+ ((struct iocblk_in *)iop)->ioc_ifflags |= IFF_RUNNING;
+ error = 0;
+ break;
+
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFMETRIC:
+ error = 0;
+ break;
+#endif
+
default:
if (us->ppa == 0 || us->ppa->lowerq == 0)
break;
break;
case M_FLUSH:
+ if (us->flags & US_DBGLOG)
+ cmn_err(CE_CONT, "ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
if (*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
if (*mp->b_rptr & FLUSHR) {
dl_info_ack_t *info;
dl_bind_ack_t *ackp;
+ if (us->flags & US_DBGLOG)
+ cmn_err(CE_CONT, "ppp/%d: dlpi prim %x len=%d\n", us->mn,
+ d->dl_primitive, size);
switch (d->dl_primitive) {
case DL_INFO_REQ:
if (size < sizeof(dl_info_req_t))
}
us->sap = -1;
us->state = DL_UNBOUND;
+#ifndef sun
+ us->ppa->ifstats.ifs_active = 0;
+#endif
dlpi_ok(q, DL_UNBIND_REQ);
break;
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:
mblk_t *mp;
us = (upperstr_t *) q->q_ptr;
+ us->flags &= ~US_BLOCKED;
while ((mp = getq(q)) != 0) {
if (!send_data(mp, us)) {
putbq(q, mp);
break;
}
}
- if (mp == 0)
- us->flags &= ~US_BLOCKED;
return 0;
}
if (ppa != 0) { /* why wouldn't it? */
ppa->stats.ppp_opackets++;
ppa->stats.ppp_obytes += msgdsize(mp);
+#ifdef sun
if (ppa->kstats != 0)
KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++;
+#else
+ ppa->ifstats.ifs_opackets++;
+#endif
}
putnext(q, mp);
return 0;
dl_unitdata_ind_t *ud;
int proto;
- /*
- * If this is a control stream and we don't have a lower queue attached,
- * run the write service routines of other streams attached to this PPA.
- */
us = (upperstr_t *) q->q_ptr;
if (us->flags & US_CONTROL) {
/*
/*
* A network protocol stream. Put a DLPI header on each
* packet and send it on.
+ * (Actually, it seems that the IP module will happily
+ * accept M_DATA messages without the DL_UNITDATA_IND header.)
*/
while ((mp = getq(q)) != 0) {
if (!canputnext(q)) {
freemsg(mp);
continue;
}
+ hdr->b_datap->db_type = M_PROTO;
ud = (dl_unitdata_ind_t *) hdr->b_wptr;
hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong);
hdr->b_cont = mp;
(e.g. PPP_IP) */
((ulong *)(ud + 1))[0] = us->req_sap; /* dest SAP */
((ulong *)(ud + 1))[1] = us->req_sap; /* src SAP */
- putnext(q, mp);
+ putnext(q, hdr);
}
}
+
+ /*
+ * If this stream is attached to a PPA with a lower queue pair,
+ * enable the read queue's service routine if it has data queued.
+ * XXX there is a possibility that packets could get out of order
+ * if ppplrput now runs before ppplrsrv.
+ */
+ if (us->ppa != 0 && us->ppa->lowerq != 0)
+ qenable(RD(us->ppa->lowerq));
+
return 0;
}
case M_CTL:
switch (*mp->b_rptr) {
case PPPCTL_IERROR:
+#ifdef sun
if (ppa->kstats != 0) {
KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++;
}
+#else
+ ppa->ifstats.ifs_ierrors++;
+#endif
ppa->stats.ppp_ierrors++;
break;
case PPPCTL_OERROR:
+#ifdef sun
if (ppa->kstats != 0) {
KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++;
}
+#else
+ ppa->ifstats.ifs_oerrors++;
+#endif
ppa->stats.ppp_oerrors++;
break;
}
if (mp->b_datap->db_type == M_DATA) {
len = msgdsize(mp);
if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
+#ifdef USE_MSGPULLUP
np = msgpullup(mp, PPP_HDRLEN);
freemsg(mp);
if (np == 0) {
break;
}
mp = np;
+#else
+ if (!pullupmsg (mp, PPP_HDRLEN)) {
+#if DEBUG
+ cmn_err(CE_CONT, "ppp_lrput: pullupmsg failed (len=%d)\n",
+ len);
+#endif
+ break;
+ }
+#endif
}
ppa->stats.ppp_ipackets++;
ppa->stats.ppp_ibytes += len;
+#ifdef sun
if (ppa->kstats != 0) {
KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++;
}
+#else
+ ppa->ifstats.ifs_ipackets++;
+#endif
proto = PPP_PROTOCOL(mp->b_rptr);
if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
/*
putnext(q, mp);
return 1;
}
+
+static void
+debug_dump(q, mp)
+ queue_t *q; /* not used */
+ mblk_t *mp; /* not used either */
+{
+ upperstr_t *us;
+ queue_t *uq, *lq;
+
+ cmn_err(CE_CONT, "ppp upper streams:\n");
+ for (us = minor_devs; us != 0; us = us->nextmn) {
+ uq = us->q;
+ cmn_err(CE_CONT, " %d: q=%x rlev=%d wlev=%d flags=0x%b",
+ us->mn, uq, (uq? qsize(uq): 0), (uq? qsize(WR(uq)): 0),
+ us->flags, "\020\1priv\2control\3blocked\4last");
+ cmn_err(CE_CONT, " state=%x sap=%x req_sap=%x", us->state, us->sap,
+ us->req_sap);
+ if (us->ppa == 0)
+ cmn_err(CE_CONT, " ppa=?\n");
+ else
+ cmn_err(CE_CONT, " ppa=%d\n", us->ppa->ppa_id);
+ if (us->flags & US_CONTROL) {
+ lq = us->lowerq;
+ cmn_err(CE_CONT, " control for %d lq=%x rlev=%d wlev=%d",
+ us->ppa_id, lq, (lq? qsize(RD(lq)): 0),
+ (lq? qsize(lq): 0));
+ cmn_err(CE_CONT, " mru=%d mtu=%d\n", us->mru, us->mtu);
+ }
+ }
+}