X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=svr4%2Fppp.c;h=43afb95925ef11b8ccdfaa063c75c597490a230b;hp=c99f426ebfd534234e07deea557009a2126e3386;hb=a44a616baa968a263dc273bc06ed79c475b7deec;hpb=3e9ccc01ba91b2b31000b3c51c7434e832dcf4ac diff --git a/svr4/ppp.c b/svr4/ppp.c index c99f426..43afb95 100644 --- a/svr4/ppp.c +++ b/svr4/ppp.c @@ -24,7 +24,7 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp.c,v 1.3 1995/05/29 06:59:36 paulus Exp $ + * $Id: ppp.c,v 1.7 1995/10/27 03:55:56 paulus Exp $ */ /* @@ -47,6 +47,11 @@ #include #include #include +#else +#include +#include +#include +#include #endif #include #include @@ -81,6 +86,7 @@ typedef struct upperstr { 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 */ /* * There is exactly one control stream for each PPA. * The following fields are only used for control streams. @@ -93,6 +99,10 @@ typedef struct upperstr { struct pppstat stats; /* statistics */ #ifdef sun kstat_t *kstats; /* stats for netstat */ +#else + int ifflags; + char ifname[IFNAMSIZ]; + struct ifstats ifstats; #endif } upperstr_t; @@ -101,6 +111,7 @@ typedef struct upperstr { #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; @@ -127,6 +138,7 @@ 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 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)); @@ -151,7 +163,13 @@ static struct qinit ppplwint = { 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 }; @@ -277,6 +295,7 @@ ppp_devinfo(dip, cmd, arg, result) #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) @@ -333,6 +352,9 @@ pppopen(q, devp, oflag, sflag, credp) 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; @@ -355,7 +377,14 @@ pppclose(q, flag, credp) 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 @@ -376,7 +405,19 @@ pppclose(q, flag, credp) *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, @@ -391,13 +432,15 @@ pppclose(q, flag, credp) } } +#ifdef sun if (up->kstats) kstat_delete(up->kstats); +#endif q->q_ptr = NULL; WR(q)->q_ptr = NULL; - for (prevp = &minor_devs; *prevp != 0; prevp = &up->nextmn) { + for (prevp = &minor_devs; *prevp != 0; prevp = &(*prevp)->nextmn) { if (*prevp == up) { *prevp = up->nextmn; break; @@ -422,6 +465,10 @@ pppuwput(q, mp) 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; @@ -434,6 +481,9 @@ pppuwput(q, mp) 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 @@ -449,6 +499,9 @@ pppuwput(q, mp) 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) @@ -457,6 +510,7 @@ pppuwput(q, mp) 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; @@ -521,7 +575,9 @@ pppuwput(q, mp) if (ppa == 0) break; us->ppa = ppa; - qwriter(q, NULL, attach_ppa, PERIM_OUTER); + iop->ioc_count = 0; + qwriter(q, mp, attach_ppa, PERIM_OUTER); + error = -1; break; case PPPIO_MRU: @@ -548,6 +604,9 @@ pppuwput(q, mp) 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; @@ -559,9 +618,127 @@ pppuwput(q, mp) 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; + us->ioc_id = iop->ioc_id; error = -1; switch (iop->ioc_cmd) { case PPPIO_GETSTAT: @@ -597,6 +774,8 @@ pppuwput(q, mp) 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) { @@ -627,6 +806,9 @@ dlpi_request(q, mp, us) 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)) @@ -746,6 +928,9 @@ dlpi_request(q, mp, us) } us->sap = -1; us->state = DL_UNBOUND; +#ifndef sun + us->ppa->ifstats.ifs_active = 0; +#endif dlpi_ok(q, DL_UNBIND_REQ); break; @@ -796,6 +981,7 @@ dlpi_request(q, mp, us) 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: @@ -982,8 +1168,12 @@ attach_ppa(q, mp) ; t->next = us; us->next = 0; - if (mp) + if (mp->b_datap->db_type == M_IOCTL) { + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + } else { dlpi_ok(q, DL_ATTACH_REQ); + } } static void @@ -1015,14 +1205,13 @@ pppuwsrv(q) 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; } @@ -1037,8 +1226,12 @@ ppplwput(q, mp) 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; @@ -1070,10 +1263,6 @@ pppursrv(q) 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) { /* @@ -1093,6 +1282,8 @@ pppursrv(q) /* * 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)) { @@ -1108,6 +1299,7 @@ pppursrv(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; @@ -1124,9 +1316,19 @@ pppursrv(q) (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; } @@ -1152,6 +1354,7 @@ ppplrput(q, mp) queue_t *uq; int proto, len; mblk_t *np; + struct iocblk *iop; ppa = (upperstr_t *) q->q_ptr; if (ppa == 0) { @@ -1173,25 +1376,50 @@ ppplrput(q, mp) 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; } freemsg(mp); break; + case M_IOCACK: + case M_IOCNAK: + /* + * Attempt to match up the response with the stream + * that the request came from. + */ + iop = (struct iocblk *) mp->b_rptr; + for (us = ppa; us != 0; us = us->next) + if (us->ioc_id == iop->ioc_id) + break; + if (us == 0) + freemsg(mp); + else + putnext(us->q, mp); + break; + default: 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) { @@ -1202,12 +1430,25 @@ ppplrput(q, mp) 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) { /* @@ -1305,3 +1546,33 @@ putctl4(q, type, code, val) 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); + } + } +}