+static int
+ppp_comp_wsrv(q)
+ queue_t *q;
+{
+ mblk_t *mp, *cmp, *np;
+ comp_state_t *cp;
+ int len, proto, type;
+ struct ip *ip;
+ unsigned char *vjhdr, *dp;
+
+ cp = (comp_state_t *) q->q_ptr;
+ while ((mp = getq(q)) != 0) {
+ /* assert(mp->b_datap->db_type == M_DATA) */
+ if (!canputnext(q)) {
+ putbq(q, mp);
+ return;
+ }
+
+ /*
+ * Make sure we've got a reasonable amount in the first
+ * mblk and that we are its only user.
+ * Then find out what the protocol is.
+ */
+ len = msgdsize(mp);
+ if (len > PPP_HDRLEN + MAX_IPHDR)
+ len = PPP_HDRLEN + MAX_IPHDR;
+ if (mp->b_wptr < mp->b_rptr + len || mp->b_datap->db_ref > 1) {
+ np = msgpullup(mp, len);
+ freemsg(mp);
+ if (np == 0) {
+#if DEBUG
+ cmn_err(CE_CONT, "ppp_comp_wsrv: msgpullup failed\n");
+#endif
+ cp->stats.ppp_oerrors++;
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ continue;
+ }
+ mp = np;
+ }
+ proto = PPP_PROTOCOL(mp->b_rptr);
+
+ /*
+ * Do VJ compression if requested.
+ */
+ if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
+ 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), &vjhdr);
+ switch (type) {
+ case TYPE_UNCOMPRESSED_TCP:
+ mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
+ break;
+ case TYPE_COMPRESSED_TCP:
+ dp = vjhdr - PPP_HDRLEN;
+ dp[1] = mp->b_rptr[1]; /* copy control field */
+ dp[0] = mp->b_rptr[0]; /* copy address field */
+ dp[2] = 0; /* set protocol field */
+ dp[3] = proto = PPP_VJC_COMP;
+ mp->b_rptr = dp;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Do packet compression if enabled.
+ */
+ if (proto == PPP_CCP)
+ ppp_comp_ccp(q, mp, 0);
+ else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
+ && cp->xstate != NULL) {
+ len = msgdsize(mp);
+ (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
+ (cp->flags & CCP_ISUP? cp->mtu: 0));
+ if (cmp != NULL) {
+ freemsg(mp);
+ mp = cmp;
+ }
+ }
+
+ /*
+ * Do address/control and protocol compression if enabled.
+ */
+ if (proto != PPP_LCP && (cp->flags & COMP_AC)) {
+ mp->b_rptr += 2; /* drop the address & ctrl fields */
+ if (proto < 0x100 && (cp->flags & COMP_PROT))
+ ++mp->b_rptr; /* drop the high protocol byte */
+ } else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
+ /* shuffle up the address & ctrl fields */
+ mp->b_rptr[2] = mp->b_rptr[1];
+ mp->b_rptr[1] = mp->b_rptr[0];
+ ++mp->b_rptr;
+ }
+
+ cp->stats.ppp_opackets++;
+ cp->stats.ppp_obytes += msgdsize(mp);
+ putnext(q, mp);
+ }
+}
+