From 334591e2dbdaebfb98e4bd65ae024f94623b2c2e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 19 May 1995 02:18:34 +0000 Subject: [PATCH] debugged and working (no stats yet) --- svr4/ppp.c | 294 +++++++++++++++++++++++++------ svr4/ppp_ahdlc.c | 180 +++++++++++++------ svr4/ppp_comp.c | 440 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 683 insertions(+), 231 deletions(-) diff --git a/svr4/ppp.c b/svr4/ppp.c index 4b66658..ef748e4 100644 --- a/svr4/ppp.c +++ b/svr4/ppp.c @@ -1,3 +1,36 @@ +/* + * ppp.c - STREAMS multiplexing pseudo-device driver for PPP. + * + * Copyright (c) 1994 The Australian National University. + * 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. + * + * 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 HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * 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. + * + * $Id: ppp.c,v 1.2 1995/05/19 02:17:42 paulus Exp $ + */ + +/* + * This file is used under Solaris 2. + */ + #include #include #include @@ -28,7 +61,7 @@ #endif #ifndef PPP_MAXMTU -#define PPP_MAXMTU 65536 +#define PPP_MAXMTU 65535 #endif /* @@ -40,6 +73,7 @@ struct upperstr { int flags; /* flag bits, see below */ int state; /* current DLPI state */ int sap; /* service access point */ + 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 */ /* @@ -49,6 +83,8 @@ struct upperstr { int ppa_id; queue_t *lowerq; /* write queue attached below this PPA */ struct upperstr *nextppa; /* next control stream */ + int mru; + int mtu; }; /* Values for flags */ @@ -77,6 +113,8 @@ static void dlpi_ok __P((queue_t *, int)); static int send_data __P((mblk_t *, struct upperstr *)); static void new_ppa __P((queue_t *, mblk_t *)); static struct upperstr *find_dest __P((struct upperstr *, int)); +static int putctl2 __P((queue_t *, int, int, int)); +static int putctl4 __P((queue_t *, int, int, int)); static struct module_info ppp_info = { 0xb1a6, "ppp", 0, 512, 512, 128 @@ -255,7 +293,6 @@ pppopen(q, devp, oflag, sflag, credp) } else { mn = getminor(*devp); } - cmn_err(CE_CONT, "pppopen: minor %d\n", mn); /* * Construct a new minor node. @@ -295,7 +332,6 @@ pppclose(q, flag, credp) qprocsoff(q); up = (struct upperstr *) q->q_ptr; - cmn_err(CE_CONT, "pppclose: minor %d\n", up->mn); if (up->flags & US_CONTROL) { /* * This stream represents a PPA: @@ -354,7 +390,7 @@ pppuwput(q, mp) struct iocblk *iop; struct linkblk *lb; queue_t *lq; - int error; + int error, n; mblk_t *mq; us = (struct upperstr *) q->q_ptr; @@ -365,56 +401,68 @@ pppuwput(q, mp) break; case M_DATA: + if ((us->flags & US_CONTROL) == 0 + || msgdsize(mp) > us->mtu + PPP_HDRLEN) { +#if DEBUG + cmn_err(CE_CONT, "pppuwput: junk data len=%d\n", msgdsize(mp)); +#endif + freemsg(mp); + break; + } if (!send_data(mp, us)) putq(q, mp); break; case M_IOCTL: iop = (struct iocblk *) mp->b_rptr; - cmn_err(CE_CONT, "ppp%d ioctl %x count=%d\n", us->mn, iop->ioc_cmd, - iop->ioc_count); + error = EINVAL; switch (iop->ioc_cmd) { case I_LINK: if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0) - goto iocnak; + break; lb = (struct linkblk *) mp->b_cont->b_rptr; us->lowerq = lq = lb->l_qbot; lq->q_ptr = us; - WR(lq)->q_ptr = us; + RD(lq)->q_ptr = us; iop->ioc_count = 0; - mp->b_datap->db_type = M_IOCACK; - qreply(q, mp); + error = 0; /* Unblock upper streams which now feed this lower stream. */ qenable(lq); + /* Send useful information down to the modules which + are now linked below us. */ + putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id); + putctl4(lq, M_CTL, PPPCTL_MRU, us->mru); + putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu); break; case I_UNLINK: lb = (struct linkblk *) mp->b_cont->b_rptr; +#if DEBUG if (us->lowerq != lb->l_qbot) cmn_err(CE_CONT, "ppp unlink: lowerq=%x qbot=%x\n", us->lowerq, lb->l_qbot); +#endif us->lowerq = 0; iop->ioc_count = 0; - mp->b_datap->db_type = M_IOCACK; - qreply(q, mp); + error = 0; /* Unblock streams which now feed back up the control stream. */ qenable(us->q); break; case PPPIO_NEWPPA: if (us->flags & US_CONTROL) - goto iocnak; + break; if ((us->flags & US_PRIV) == 0) { - iop->ioc_error = EPERM; - goto iocnak; + error = EPERM; + break; } /* Arrange to return an int */ if ((mq = mp->b_cont) == 0 || mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) { mq = allocb(sizeof(int), BPRI_HI); if (mq == 0) { - iop->ioc_error = ENOSR; - goto iocnak; + error = ENOSR; + break; } if (mp->b_cont != 0) freemsg(mp->b_cont); @@ -424,28 +472,67 @@ pppuwput(q, mp) iop->ioc_count = sizeof(int); mq->b_wptr = mq->b_rptr + sizeof(int); qwriter(q, mp, new_ppa, PERIM_OUTER); + error = -1; + break; + + case PPPIO_MRU: + if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0) + break; + n = *(int *)mp->b_cont->b_rptr; + if (n <= 0 || n > PPP_MAXMTU) + break; + if (n < PPP_MRU) + n = PPP_MRU; + us->mru = n; + if (us->lowerq) + putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n); + error = 0; + iop->ioc_count = 0; + break; + + case PPPIO_MTU: + if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0) + break; + n = *(int *)mp->b_cont->b_rptr; + if (n <= 0 || n > PPP_MAXMTU) + break; + if (n < PPP_MRU) + n = PPP_MRU; + us->mtu = n; + if (us->lowerq) + putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n); + error = 0; + iop->ioc_count = 0; break; default: if (us->ppa == 0 || us->ppa->lowerq == 0) - goto iocnak; + break; + error = -1; switch (iop->ioc_cmd) { case PPPIO_GETSTAT: case PPPIO_GETCSTAT: + putnext(us->ppa->lowerq, mp); break; default: - if ((us->flags & US_PRIV) == 0) { - iop->ioc_error = EPERM; - goto iocnak; + if (us->flags & US_PRIV) + putnext(us->ppa->lowerq, mp); + else { + cmn_err(CE_CONT, "ppp ioctl %x rejected\n", iop->ioc_cmd); + error = EPERM; } + break; } - putnext(us->ppa->lowerq, mp); break; + } - iocnak: + if (error > 0) { + iop->ioc_error = error; mp->b_datap->db_type = M_IOCNAK; qreply(q, mp); - break; + } else if (error == 0) { + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); } break; @@ -476,13 +563,12 @@ dlpi_request(q, mp, us) int size = mp->b_wptr - mp->b_rptr; mblk_t *reply, *np; struct upperstr *t, *ppa; - int sap; + int sap, *ip; dl_info_ack_t *info; dl_bind_ack_t *ackp; dl_phys_addr_ack_t *adrp; + dl_get_statistics_ack_t *statsp; - cmn_err(CE_CONT, "ppp%d dlpi prim %x, state=%x\n", us->mn, - d->dl_primitive, us->state); switch (d->dl_primitive) { case DL_INFO_REQ: if (size < sizeof(dl_info_req_t)) @@ -560,7 +646,10 @@ dlpi_request(q, mp, us) } /* saps must be valid PPP network protocol numbers */ sap = d->bind_req.dl_sap; + us->req_sap = sap; +#if DEBUG cmn_err(CE_CONT, "ppp bind %x\n", sap); +#endif if (sap == ETHERTYPE_IP) sap = PPP_IP; if (sap < 0x21 || sap > 0x3fff @@ -604,6 +693,14 @@ dlpi_request(q, mp, us) dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0); break; } + if (mp->b_cont != 0 && us->ppa != 0 + && msgdsize(mp->b_cont) > us->ppa->mtu) { +#if DEBUG + cmn_err(CE_CONT, "dlpi data too large (%d > %d)\n", + msgdsize(mp->b_cont), us->mtu); +#endif + break; + } /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */ if (mp->b_datap->db_ref > 1) { np = allocb(PPP_HDRLEN, BPRI_HI); @@ -613,8 +710,10 @@ dlpi_request(q, mp, us) mp->b_cont = 0; freeb(mp); mp = np; - } - /* XXX should use dl_dest_addr_offset/length here */ + } else + mp->b_datap->db_type = M_DATA; + /* XXX should use dl_dest_addr_offset/length here, + but we would have to translate ETHERTYPE_IP -> PPP_IP */ mp->b_wptr = mp->b_rptr + PPP_HDRLEN; mp->b_rptr[0] = PPP_ALLSTATIONS; mp->b_rptr[1] = PPP_UI; @@ -624,6 +723,29 @@ dlpi_request(q, mp, us) putq(q, mp); return; +#if 0 + case DL_GET_STATISTICS_REQ: + if (size < sizeof(dl_get_statistics_req_t)) + goto badprim; + if ((reply = allocb(sizeof(dl_get_statistics_ack_t) + 5 * sizeof(int), + BPRI_HI)) == 0) + break; /* XXX should do bufcall */ + statsp = (dl_get_statistics_ack_t *) reply->b_wptr; + reply->b_wptr += sizeof(dl_get_statistics_ack_t) + 5 * sizeof(int); + reply->b_datap->db_type = M_PCPROTO; + statsp->dl_primitive = DL_GET_STATISTICS_ACK; + statsp->dl_stat_length = 5 * sizeof(int); + statsp->dl_stat_offset = sizeof(dl_get_statistics_ack_t); + ip = (int *) (statsp + 1); + ip[0] = 1; + ip[1] = 2; + ip[2] = 3; + ip[3] = 4; + ip[4] = 5; + qreply(q, reply); + break; +#endif + case DL_SUBS_BIND_REQ: case DL_SUBS_UNBIND_REQ: case DL_ENABMULTI_REQ: @@ -637,7 +759,6 @@ dlpi_request(q, mp, us) case DL_CONNECT_REQ: case DL_TOKEN_REQ: case DL_REPLY_UPDATE_REQ: - case DL_GET_STATISTICS_REQ: case DL_REPLY_REQ: case DL_DATA_ACK_REQ: dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0); @@ -659,6 +780,8 @@ dlpi_request(q, mp, us) break; default: + cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive); + /* fall through */ badprim: dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0); break; @@ -759,6 +882,9 @@ new_ppa(q, mp) *usp = us; us->flags |= US_CONTROL; + us->mtu = PPP_MRU; + us->mru = PPP_MRU; + *(int *)mp->b_cont->b_rptr = ppa_id; mp->b_datap->db_type = M_IOCACK; qreply(q, mp); @@ -780,6 +906,8 @@ pppuwsrv(q) break; } } + if (mp == 0) + us->flags &= ~US_BLOCKED; return 0; } @@ -856,8 +984,11 @@ pppursrv(q) ud->dl_src_addr_length = sizeof(ulong); ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(ulong); ud->dl_group_address = 0; - ((ulong *)(ud + 1))[0] = proto; /* dest SAP */ - ((ulong *)(ud + 1))[1] = proto; /* src SAP */ + /* Send the DLPI client the data with the SAP they requested, + (e.g. ETHERTYPE_IP) rather than the PPP protocol number + (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); } } @@ -887,6 +1018,13 @@ ppplrput(q, mp) int proto; ppa = (struct upperstr *) q->q_ptr; + if (ppa == 0) { +#if DEBUG + cmn_err(CE_CONT, "ppplrput: q = %x, ppa = 0??\n", q); +#endif + freemsg(mp); + return 0; + } switch (mp->b_datap->db_type) { case M_FLUSH: if (*mp->b_rptr & FLUSHW) { @@ -896,30 +1034,42 @@ ppplrput(q, mp) freemsg(mp); break; + case M_CTL: + freemsg(mp); + break; + default: - if (mp->b_datap->db_type == M_DATA - && (proto = PPP_PROTOCOL(mp->b_rptr)) < 0x8000 - && (us = find_dest(ppa, proto)) != 0) { - /* - * A data packet for some network protocol. - * Queue it on the upper stream for that protocol. - */ - if (canput(us->q)) - putq(us->q, mp); - else - putq(q, mp); - break; - } else { - /* - * A control frame, a frame for an unknown protocol, - * or some other message type. - * Send it up to pppd via the control stream. - */ - if (mp->b_datap->db_type >= QPCTL || canputnext(ppa->q)) - putnext(ppa->q, mp); - else - putq(q, mp); + if (mp->b_datap->db_type == M_DATA) { + if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN + && !pullupmsg(mp, PPP_HDRLEN)) { +#if DEBUG + cmn_err(CE_CONT, "ppp_lrput: pullupmsg failed\n"); +#endif + freemsg(mp); + break; + } + proto = PPP_PROTOCOL(mp->b_rptr); + if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) { + /* + * A data packet for some network protocol. + * Queue it on the upper stream for that protocol. + */ + if (canput(us->q)) + putq(us->q, mp); + else + putq(q, mp); + break; + } } + /* + * A control frame, a frame for an unknown protocol, + * or some other message type. + * Send it up to pppd via the control stream. + */ + if (mp->b_datap->db_type >= QPCTL || canputnext(ppa->q)) + putnext(ppa->q, mp); + else + putq(q, mp); break; } @@ -959,3 +1109,39 @@ ppplrsrv(q) } return 0; } + +static int +putctl2(q, type, code, val) + queue_t *q; + int type, code, val; +{ + mblk_t *mp; + + mp = allocb(2, BPRI_HI); + if (mp == 0) + return 0; + mp->b_datap->db_type = type; + mp->b_wptr[0] = code; + mp->b_wptr[1] = val; + mp->b_wptr += 2; + putnext(q, mp); + return 1; +} + +static int +putctl4(q, type, code, val) + queue_t *q; + int type, code, val; +{ + mblk_t *mp; + + mp = allocb(4, BPRI_HI); + if (mp == 0) + return 0; + mp->b_datap->db_type = type; + mp->b_wptr[0] = code; + ((short *)mp->b_wptr)[1] = val; + mp->b_wptr += 4; + putnext(q, mp); + return 1; +} diff --git a/svr4/ppp_ahdlc.c b/svr4/ppp_ahdlc.c index 2e62d21..b483276 100644 --- a/svr4/ppp_ahdlc.c +++ b/svr4/ppp_ahdlc.c @@ -1,3 +1,36 @@ +/* + * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC. + * + * Copyright (c) 1994 The Australian National University. + * 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. + * + * 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 HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * 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. + * + * $Id: ppp_ahdlc.c,v 1.2 1995/05/19 02:18:34 paulus Exp $ + */ + +/* + * This file is used under Solaris 2. + */ + #include #include #include @@ -6,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -65,6 +100,7 @@ struct ahdlc_state { u_int32_t raccm; int mtu; int mru; + int unit; }; /* Values for flags */ @@ -185,6 +221,7 @@ ahdlc_wput(q, mp) { struct ahdlc_state *state; struct iocblk *iop; + int error; state = (struct ahdlc_state *) q->q_ptr; switch (mp->b_datap->db_type) { @@ -199,36 +236,63 @@ ahdlc_wput(q, mp) case M_IOCTL: iop = (struct iocblk *) mp->b_rptr; + error = EINVAL; switch (iop->ioc_cmd) { case PPPIO_XACCM: - if (iop->ioc_count != sizeof(ext_accm)) - goto iocnak; - bcopy(mp->b_cont->b_rptr, (caddr_t)state->xaccm, sizeof(ext_accm)); + if (iop->ioc_count < sizeof(u_int32_t) + || iop->ioc_count > sizeof(ext_accm)) + break; + bcopy(mp->b_cont->b_rptr, (caddr_t)state->xaccm, iop->ioc_count); state->xaccm[2] &= 0x40000000; /* don't escape 0x5e */ state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */ - goto iocack; + iop->ioc_count = 0; + error = 0; + break; case PPPIO_RACCM: if (iop->ioc_count != sizeof(u_int32_t)) - goto iocnak; - state->raccm = *(u_int32_t *)mp->b_cont->b_rptr; - goto iocack; + break; + bcopy(mp->b_cont->b_rptr, (caddr_t)&state->raccm, + sizeof(u_int32_t)); + iop->ioc_count = 0; + error = 0; + break; default: - putnext(q, mp); + error = -1; break; + } - iocack: - iop->ioc_count = 0; + if (error < 0) + putnext(q, mp); + else if (error == 0) { mp->b_datap->db_type = M_IOCACK; qreply(q, mp); - break; - - iocnak: + } else { mp->b_datap->db_type = M_IOCNAK; + iop->ioc_count = 0; + iop->ioc_error = error; qreply(q, mp); + } + break; + + case M_CTL: + switch (*mp->b_rptr) { + case PPPCTL_MTU: + state->mtu = ((unsigned short *)mp->b_rptr)[1]; + freemsg(mp); + break; + case PPPCTL_MRU: + state->mru = ((unsigned short *)mp->b_rptr)[1]; + freemsg(mp); + break; + case PPPCTL_UNIT: + state->unit = mp->b_rptr[1]; break; + default: + putnext(q, mp); } + break; default: putnext(q, mp); @@ -308,13 +372,22 @@ stuff_frame(q, mp) /* * For LCP packets, we must escape all control characters. + * LCP packets must not be A/C or protocol compressed. */ - if (proto == PPP_LCP) { - bcopy(state->xaccm, lcp_xaccm, sizeof(lcp_xaccm)); - lcp_xaccm[0] = ~0; - xaccm = lcp_xaccm; - } else - xaccm = state->xaccm; + xaccm = state->xaccm; + if (ilen >= PPP_HDRLEN) { + if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN + || pullupmsg(mp, PPP_HDRLEN)) { + if (PPP_ADDRESS(mp->b_rptr) == PPP_ALLSTATIONS + && PPP_CONTROL(mp->b_rptr) == PPP_UI + && PPP_PROTOCOL(mp->b_rptr) == PPP_LCP) { + bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, + sizeof(lcp_xaccm)); + lcp_xaccm[0] = ~0; + xaccm = lcp_xaccm; + } + } + } sp = mp->b_rptr; fcs = PPP_INITFCS; @@ -457,7 +530,7 @@ unstuff_chars(q, mp) */ dp = om->b_wptr; len = om->b_datap->db_lim - dp; /* max # output bytes */ - extra = (cpend - cp) - len; /* #input chars - #output bytes */ + extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */ if (extra < 0) { len += extra; /* we'll run out of input first */ extra = 0; @@ -471,11 +544,10 @@ unstuff_chars(q, mp) break; ++cp; if (c == PPP_ESCAPE) { - if (extra > 0) + if (extra > 0) { --extra; - else if (len > 1) - --len; - else { + ++cpend; + } else if (cp >= cpend) { state->flags |= ESCAPED; break; } @@ -491,7 +563,7 @@ unstuff_chars(q, mp) state->inlen += dp - dp0; state->infcs = fcs; om->b_wptr = dp; - if (len <= 0) + if (cp >= cpend) continue; /* go back and check cp again */ } @@ -508,20 +580,19 @@ unstuff_chars(q, mp) state->inlen = 0; if (om == 0) continue; - if (state->flags & (IFLUSH|ESCAPED) || len < PPP_FCSLEN) { - /* XXX should send up ctl message to notify VJ decomp */ - freemsg(om); - continue; - } - if (state->infcs != PPP_GOODFCS) { + if (!(state->flags & (IFLUSH|ESCAPED) || len < PPP_FCSLEN)) { + if (state->infcs == PPP_GOODFCS) { + adjmsg(om, -PPP_FCSLEN); /* chop off fcs */ + putnext(q, om); /* bombs away! */ + continue; + } /* incr bad fcs stats */ - /* would like to be able to pass this up for debugging */ - /* XXX should send up ctl message to notify VJ decomp */ - freemsg(om); - continue; +#if DEBUG + cmn_err(CE_CONT, "ppp_ahdl: bad fcs %x\n", state->infcs); +#endif } - adjmsg(om, -PPP_FCSLEN); /* chop off fcs */ - putnext(q, om); /* bombs away! */ + freemsg(om); + putctl1(q->q_next, M_CTL, PPPCTL_IERROR); continue; } @@ -529,6 +600,7 @@ unstuff_chars(q, mp) continue; if (state->flags & ESCAPED) { c ^= PPP_TRANS; + state->flags &= ~ESCAPED; } else if (c == PPP_ESCAPE) { state->flags |= ESCAPED; continue; @@ -549,11 +621,19 @@ unstuff_chars(q, mp) om = state->cur_blk; if (om->b_wptr >= om->b_datap->db_lim) { /* - * Current message block is full. Allocate another one. + * Current message block is full. Allocate another one, + * unless we have run out of MRU. */ + if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) { +#if DEBUG + cmn_err(CE_CONT, "ppp_ahdl: frame too long (%d)\n", + state->inlen); +#endif + state->flags |= IFLUSH; + continue; + } om = allocb(IFRAME_BSIZE, BPRI_MED); if (om == 0) { - freemsg(state->cur_frame); state->flags |= IFLUSH; continue; } @@ -571,18 +651,20 @@ unstuff_chars(q, mp) * but we do leave space for the decompressed fields and * arrange for the info field to start on a word boundary. */ - cp = om->b_rptr; - if (*cp == PPP_ALLSTATIONS) - cp += 2; - if ((*cp & 1) == 0) - ++cp; - /* cp is now pointing at the last byte of the ppp protocol field */ - offset = 3 - ((unsigned)cp & 3); + dp = om->b_rptr; + if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS + && PPP_CONTROL(dp) == PPP_UI) + dp += 2; + if ((*dp & 1) == 0) + ++dp; + /* dp is now pointing at the last byte of the ppp protocol field */ + offset = 3 - ((unsigned)dp & 3); if (offset > 0) { + dp = om->b_wptr; do { - cp[offset] = cp[0]; - --cp; - } while (cp >= om->b_rptr); + --dp; + dp[offset] = dp[0]; + } while (dp > om->b_rptr); om->b_rptr += offset; om->b_wptr += offset; } diff --git a/svr4/ppp_comp.c b/svr4/ppp_comp.c index 254a935..7eb54ec 100644 --- a/svr4/ppp_comp.c +++ b/svr4/ppp_comp.c @@ -1,5 +1,5 @@ /* - * ppp_comp.c - STREAMS module for kernel-level CCP support. + * ppp_comp.c - STREAMS module for kernel-level compression and CCP support. * * Copyright (c) 1994 The Australian National University. * All rights reserved. @@ -24,16 +24,11 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp_comp.c,v 1.1 1995/05/10 01:38:47 paulus Exp $ + * $Id: ppp_comp.c,v 1.2 1995/05/19 02:18:11 paulus Exp $ */ /* - * This file is used under SunOS 4.x, and OSF/1 on DEC Alpha. - * - * Beware that under OSF/1, the ioctl constants (SIOC*) end up - * as 64-bit (long) values, so an ioctl constant should be cast to - * int (32 bits) before being compared with the ioc_cmd field of - * an iocblk structure. + * This file is used under Solaris 2. */ #include @@ -45,10 +40,15 @@ #include #include #include +#include #include -#include +#include +#include +#include +#include +#include -#define ALLOCATE(n) kmem_zalloc((n), KM_NOSLEEP) +#define ALLOCATE(n) kmem_alloc((n), KM_NOSLEEP) #define FREE(p, n) kmem_free((p), (n)) #define PACKETPTR mblk_t * @@ -57,20 +57,22 @@ static int ppp_comp_open __P((queue_t *, dev_t *, int, int, cred_t *)); static int ppp_comp_close __P((queue_t *, int, cred_t *)); static int ppp_comp_rput __P((queue_t *, mblk_t *)); +static int ppp_comp_rsrv __P((queue_t *)); static int ppp_comp_wput __P((queue_t *, mblk_t *)); +static int ppp_comp_wsrv __P((queue_t *)); static void ppp_comp_ccp __P((queue_t *, mblk_t *, int)); static struct module_info minfo = { - 0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096, + 0xbadf, "ppp_comp", 0, INFPSZ, 16384, 4096, }; static struct qinit r_init = { - ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close, + ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close, NULL, &minfo, NULL }; static struct qinit w_init = { - ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL + ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL }; static struct streamtab ppp_compinfo = { @@ -101,11 +103,14 @@ struct ppp_comp_state { int flags; int mru; int mtu; + int unit; + int ierrors; struct compressor *xcomp; void *xstate; struct compressor *rcomp; void *rstate; struct vjcompress vj_comp; + int vj_last_ierrors; }; /* Bits in flags are as defined in pppio.h. */ @@ -153,9 +158,9 @@ _info(mip) * STREAMS module entry points. */ static int -ppp_comp_open(q, dev, flag, sflag, credp) +ppp_comp_open(q, devp, flag, sflag, credp) queue_t *q; - dev_t dev; + dev_t *devp; int flag, sflag; cred_t *credp; { @@ -165,21 +170,27 @@ ppp_comp_open(q, dev, flag, sflag, credp) cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state)); if (cp == NULL) return ENOSR; - OTHERQ(q)->q_ptr = q->q_ptr = cp; - cp->flags = 0; + WR(q)->q_ptr = q->q_ptr = cp; + bzero((caddr_t)cp, sizeof(struct ppp_comp_state)); cp->mru = PPP_MRU; + cp->mtu = PPP_MRU; cp->xstate = NULL; cp->rstate = NULL; + vj_compress_init(&cp->vj_comp, -1); + qprocson(q); } return 0; } static int -ppp_comp_close(q) +ppp_comp_close(q, flag, credp) queue_t *q; + int flag; + cred_t *credp; { struct ppp_comp_state *cp; + qprocsoff(q); cp = (struct ppp_comp_state *) q->q_ptr; if (cp != NULL) { if (cp->xstate != NULL) @@ -200,21 +211,168 @@ ppp_comp_wput(q, mp) { struct iocblk *iop; struct ppp_comp_state *cp; - mblk_t *cmp; - int error, len, proto, state; - struct ppp_option_data *odp; + int error, len; + int flags, mask; struct compressor **comp; struct ppp_comp_stats *pcp; + unsigned char *opt_data; + int nxslots, nrslots; cp = (struct ppp_comp_state *) q->q_ptr; switch (mp->b_datap->db_type) { case M_DATA: + putq(q, mp); + break; + + case M_IOCTL: + iop = (struct iocblk *) mp->b_rptr; + error = EINVAL; + switch (iop->ioc_cmd) { + + case PPPIO_CFLAGS: + /* set/get CCP state */ + if (iop->ioc_count != 2 * sizeof(int)) + break; + flags = ((int *) mp->b_cont->b_rptr)[0]; + mask = ((int *) mp->b_cont->b_rptr)[1]; + cp->flags = (cp->flags & ~mask) | (flags & mask); + if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) { + if (cp->xstate != NULL) { + (*cp->xcomp->comp_free)(cp->xstate); + cp->xstate = NULL; + } + if (cp->rstate != NULL) { + (*cp->rcomp->decomp_free)(cp->rstate); + cp->rstate = NULL; + } + cp->flags &= ~CCP_ISUP; + } + error = 0; + iop->ioc_count = sizeof(int); + ((int *) mp->b_cont->b_rptr)[0] = cp->flags; + mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int); + break; + + case PPPIO_VJINIT: + /* + * Initialize VJ compressor/decompressor + */ + if (iop->ioc_count != 2) + break; + nxslots = mp->b_cont->b_rptr[0] + 1; + nrslots = mp->b_cont->b_rptr[1] + 1; + if (nxslots > MAX_STATES || nrslots > MAX_STATES) + break; + vj_compress_init(&cp->vj_comp, nxslots); + cp->vj_last_ierrors = cp->ierrors; + error = 0; + iop->ioc_count = 0; + break; + + case PPPIO_XCOMP: + case PPPIO_RCOMP: + if (iop->ioc_count <= 0) + break; + opt_data = mp->b_cont->b_rptr; + len = mp->b_cont->b_wptr - opt_data; + if (len > iop->ioc_count) + len = iop->ioc_count; + if (opt_data[1] < 2 || opt_data[1] > len) + break; + for (comp = ppp_compressors; *comp != NULL; ++comp) + if ((*comp)->compress_proto == opt_data[0]) { + /* here's the handler! */ + error = 0; + if (iop->ioc_cmd == PPPIO_XCOMP) { + if (cp->xstate != NULL) + (*cp->xcomp->comp_free)(cp->xstate); + cp->xcomp = *comp; + cp->xstate = (*comp)->comp_alloc(opt_data, len); + if (cp->xstate == NULL) + error = ENOSR; + } else { + if (cp->rstate != NULL) + (*cp->rcomp->decomp_free)(cp->rstate); + cp->rcomp = *comp; + cp->rstate = (*comp)->decomp_alloc(opt_data, len); + if (cp->rstate == NULL) + error = ENOSR; + } + break; + } + iop->ioc_count = 0; + break; + + case PPPIO_MRU: + /* remember this value */ + if (iop->ioc_count == sizeof(int)) { + cp->mru = *(int *) mp->b_cont->b_rptr; + } + error = -1; + break; + + default: + error = -1; + break; + } + + if (error < 0) + putnext(q, mp); + else if (error == 0) { + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + } else { + mp->b_datap->db_type = M_IOCNAK; + iop->ioc_error = error; + iop->ioc_count = 0; + qreply(q, mp); + } + break; + + case M_CTL: + switch (*mp->b_rptr) { + case PPPCTL_MTU: + cp->mtu = ((unsigned short *)mp->b_rptr)[1]; + break; + case PPPCTL_MRU: + cp->mru = ((unsigned short *)mp->b_rptr)[1]; + break; + case PPPCTL_UNIT: + cp->unit = mp->b_rptr[1]; + break; + } + putnext(q, mp); + break; + + default: + putnext(q, mp); + } +} + +static int +ppp_comp_wsrv(q) + queue_t *q; +{ + mblk_t *mp, *cmp; + struct ppp_comp_state *cp; + int len, proto, type; + struct ip *ip; + unsigned char *vjhdr, *dp; + + cp = (struct ppp_comp_state *) q->q_ptr; + while ((mp = getq(q)) != 0) { + /* assert(mp->b_datap->db_type == M_DATA) */ + if (!canputnext(q)) { + putbq(q, mp); + return; + } + /* first find out what the protocol is */ if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN && !pullupmsg(mp, PPP_HDRLEN)) { freemsg(mp); /* give up on it */ - break; + continue; } proto = PPP_PROTOCOL(mp->b_rptr); @@ -229,7 +387,7 @@ ppp_comp_wput(q, mp) ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN); if (ip->ip_p == IPPROTO_TCP) { type = vj_compress_tcp(ip, len - PPP_HDRLEN, - cp->vj_comp, (cp->flags & COMP_VJCCID), + &cp->vj_comp, (cp->flags & COMP_VJCCID), &vjhdr); switch (type) { case TYPE_UNCOMPRESSED_TCP: @@ -279,99 +437,30 @@ ppp_comp_wput(q, mp) } putnext(q, mp); - break; - - case M_IOCTL: - iop = (struct iocblk *) mp->b_rptr; - error = -1; - switch (iop->ioc_cmd) { + } +} - case PPPIO_CFLAGS: - /* set CCP state */ - if (iop->ioc_count != sizeof(int)) { - error = EINVAL; - break; - } - state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN); - if ((state & CCP_ISOPEN) == 0) { - if (cp->xstate != NULL) { - (*cp->xcomp->comp_free)(cp->xstate); - cp->xstate = NULL; - } - if (cp->rstate != NULL) { - (*cp->rcomp->decomp_free)(cp->rstate); - cp->rstate = NULL; - } - cp->flags = 0; - } else { - cp->flags = (cp->flags & ~CCP_ISUP) | state; - } - error = 0; - iop->ioc_count = 0; - break; +static int +ppp_comp_rput(q, mp) + queue_t *q; + mblk_t *mp; +{ + struct ppp_comp_state *cp; - case SIOCGIFCOMP: - if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) { - error = ENOSR; - break; - } - *(int *)mp->b_cont->b_wptr = cp->flags; - mp->b_cont->b_wptr += iop->ioc_count = sizeof(int); - break; + cp = (struct ppp_comp_state *) q->q_ptr; + switch (mp->b_datap->db_type) { - case PPPIO_COMPRESS: - error = EINVAL; - if (iop->ioc_count != sizeof(struct ppp_option_data)) - break; - odp = (struct ppp_option_data *) mp->b_cont->b_rptr; - len = mp->b_cont->b_wptr - (unsigned char *) odp->opt_data; - if (len > odp->length) - len = odp->length; - if (odp->opt_data[1] < 2 || odp->opt_data[1] > len) - break; - for (comp = ppp_compressors; *comp != NULL; ++comp) - if ((*comp)->compress_proto == odp->opt_data[0]) { - /* here's the handler! */ - error = 0; - if (odp->transmit) { - if (cp->xstate != NULL) - (*cp->xcomp->comp_free)(cp->xstate); - cp->xcomp = *comp; - cp->xstate = (*comp)->comp_alloc(odp->opt_data, len); - if (cp->xstate == NULL) - error = ENOSR; - } else { - if (cp->rstate != NULL) - (*cp->rcomp->decomp_free)(cp->rstate); - cp->rcomp = *comp; - cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len); - if (cp->rstate == NULL) - error = ENOSR; - } - break; - } - iop->ioc_count = 0; - break; + case M_DATA: + putq(q, mp); + break; - case PPPIO_MRU: - /* remember this value */ - if (iop->ioc_count == sizeof(int)) { - cp->mru = *(int *) mp->b_cont->b_rptr; - } + case M_CTL: + switch (mp->b_rptr[0]) { + case PPPCTL_IERROR: + ++cp->ierrors; break; - - } - - if (error < 0) - putnext(q, mp); - else if (error == 0) { - mp->b_datap->db_type = M_IOCACK; - qreply(q, mp); - } else { - mp->b_datap->db_type = M_IOCNAK; - iop->ioc_count = 0; - qreply(q, mp); } + putnext(q, mp); break; default: @@ -380,18 +469,25 @@ ppp_comp_wput(q, mp) } static int -ppp_comp_rput(q, mp) +ppp_comp_rsrv(q) queue_t *q; - mblk_t *mp; { int proto, rv; - mblk_t *dmp; + mblk_t *mp, *dmp, *np; + unsigned char *dp, *iphdr; struct ppp_comp_state *cp; + int len, hlen, vjlen, iphlen; + int oldierrors; cp = (struct ppp_comp_state *) q->q_ptr; - switch (mp->b_datap->db_type) { + oldierrors = cp->ierrors; + while ((mp = getq(q)) != 0) { + /* assert(mp->b_datap->db_type == M_DATA) */ + if (!canputnext(q)) { + putbq(q, mp); + return; + } - case M_DATA: /* * First do address/control and protocol "decompression". */ @@ -399,9 +495,9 @@ ppp_comp_rput(q, mp) if (len > PPP_HDRLEN) len = PPP_HDRLEN; if (mp->b_wptr - mp->b_rptr < len && !pullupmsg(mp, len)) { - /* XXX reset VJ */ + ++cp->ierrors; freemsg(mp); - break; + continue; } dp = mp->b_rptr; if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS && PPP_CONTROL(dp) == PPP_UI) @@ -411,16 +507,18 @@ ppp_comp_rput(q, mp) proto = *dp++ << 8; /* grab high byte of protocol */ proto += *dp++; /* grab low byte of protocol */ if (dp > mp->b_wptr) { - freemsg(mp); /* short/bogus packet */ - break; + ++cp->ierrors; /* short/bogus packet */ + freemsg(mp); + continue; } if ((dp -= PPP_HDRLEN) < mp->b_datap->db_base) { /* yucko, need a new message block */ mp->b_rptr = dp; np = allocb(PPP_HDRLEN, BPRI_MED); if (np == 0) { + ++cp->ierrors; freemsg(mp); - break; + continue; } linkb(np, mp); mp = np; @@ -453,13 +551,14 @@ ppp_comp_rput(q, mp) case DECOMP_OK: /* no error, but no packet returned */ freemsg(mp); - mp = NULL; - break; + continue; case DECOMP_ERROR: cp->flags |= CCP_ERROR; + ++cp->ierrors; break; case DECOMP_FATALERROR: cp->flags |= CCP_FATALERROR; + ++cp->ierrors; break; } } @@ -471,14 +570,81 @@ ppp_comp_rput(q, mp) /* * Now do VJ decompression. */ + proto = PPP_PROTOCOL(mp->b_rptr); + if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) { + if ((cp->flags & DECOMP_VJC) == 0) { + ++cp->ierrors; /* ? */ + freemsg(mp); + continue; + } + if (cp->ierrors != cp->vj_last_ierrors) { + vj_uncompress_err(&cp->vj_comp); + cp->vj_last_ierrors = cp->ierrors; + } + len = msgdsize(mp); + hlen = (proto == PPP_VJC_COMP? MAX_VJHDR: MAX_IPHDR) + PPP_HDRLEN; + if (hlen > len) + hlen = len; + if (mp->b_wptr - mp->b_rptr < hlen && !pullupmsg(mp, hlen)) { + ++cp->ierrors; + freemsg(mp); + continue; + } - if (mp != NULL) - putnext(q, mp); - break; + if (proto == PPP_VJC_COMP) { + mp->b_rptr += PPP_HDRLEN; + vjlen = vj_uncompress_tcp(mp->b_rptr, mp->b_wptr - mp->b_rptr, + len - PPP_HDRLEN, &cp->vj_comp, + &iphdr, &iphlen); + if (vjlen < 0 + || (np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0) { + ++cp->ierrors; + freemsg(mp); + continue; + } + + mp->b_rptr += vjlen; /* drop off VJ header */ + dp = np->b_rptr; /* prepend mblk with TCP/IP hdr */ + dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */ + dp[1] = PPP_UI; + dp[2] = PPP_IP >> 8; + dp[3] = PPP_IP; + bcopy(iphdr, dp + PPP_HDRLEN, iphlen); + np->b_wptr = dp + iphlen + PPP_HDRLEN; + np->b_cont = mp; + + /* XXX there seems to be a bug which causes panics in strread + if we make an mbuf with only the IP header in it :-( */ + if (mp->b_wptr - mp->b_rptr > 4) { + bcopy(mp->b_rptr, np->b_wptr, 4); + mp->b_rptr += 4; + np->b_wptr += 4; + } else { + bcopy(mp->b_rptr, np->b_wptr, mp->b_wptr - mp->b_rptr); + np->b_wptr += mp->b_wptr - mp->b_rptr; + np->b_cont = mp->b_cont; + freeb(mp); + } + + mp = np; + + } else { + if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN, + &cp->vj_comp)) { + ++cp->ierrors; + freemsg(mp); + continue; + } + mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */ + } + } - default: putnext(q, mp); } +#if DEBUG + if (cp->ierrors != oldierrors) + cmn_err(CE_CONT, "ppp_comp_rsrv ierrors now %d\n", cp->ierrors); +#endif } /* @@ -519,13 +685,13 @@ ppp_comp_ccp(q, mp, rcvd) if (cp->xstate != NULL && (*cp->xcomp->comp_init) (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN, - 0, /* XXX: should be unit */ 0, 0)) + cp->unit, 0, 0)) cp->flags |= CCP_COMP_RUN; } else { if (cp->rstate != NULL && (*cp->rcomp->decomp_init) (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN, - 0/* unit */, 0, cp->mru, 0)) + cp->unit, 0, cp->mru, 0)) cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN; } @@ -548,3 +714,21 @@ ppp_comp_ccp(q, mp, rcvd) } } + +#if DEBUG +dump_msg(mp) + mblk_t *mp; +{ + dblk_t *db; + + while (mp != 0) { + db = mp->b_datap; + cmn_err(CE_CONT, "mp=%x cont=%x rptr=%x wptr=%x datap=%x\n", + mp, mp->b_cont, mp->b_rptr, mp->b_wptr, db); + cmn_err(CE_CONT, " base=%x lim=%x ref=%d type=%d struioflag=%d\n", + db->db_base, db->db_lim, db->db_ref, db->db_type, + db->db_struioflag); + mp = mp->b_cont; + } +} +#endif -- 2.39.2