+ case PPP_LQR:
+ /*
+ * Update the LQR frame with the current MIB information.
+ * This way the information is accurate and up-to-date.
+ */
+ if (count < 48)
+ break;
+ p = data + 40; /* Point to last two items. */
+ p = store_long(p, ppp->stats.ppp_opackets + 1);
+ p = store_long(p, ppp->stats.ppp_ooctects + count);
+ ++ppp->stats.ppp_olqrs;
+ break;
+
+ case PPP_CCP:
+ /*
+ * Outbound compression control frames
+ */
+ ppp_proto_ccp(ppp, data + PPP_HDRLEN, count - PPP_HDRLEN, 0);
+ break;
+ }
+ data = skb->data;
+ count = skb->len;
+
+ /*
+ * Compress the whole frame if possible.
+ */
+ if (((ppp->flags & SC_COMP_RUN) != 0) &&
+ (ppp->sc_xc_state != (void *) 0) &&
+ (proto != PPP_LCP) &&
+ (proto != PPP_CCP)) {
+ struct sk_buff *new_skb;
+ int new_count;
+
+ /* Allocate an skb for the compressed frame. */
+ new_skb = alloc_skb(ppp->mtu + PPP_HDRLEN, GFP_ATOMIC);
+ if (new_skb == NULL) {
+ printk(KERN_ERR "ppp_send_frame: no memory\n");
+ KFREE_SKB(skb);
+ ppp->xmit_busy = 0;
+ return;
+ }
+ LIBERATE_SKB(new_skb);
+
+ /* Compress the frame. */
+ new_count = (*ppp->sc_xcomp->compress)
+ (ppp->sc_xc_state, data, new_skb->data,
+ count, ppp->mtu + PPP_HDRLEN);
+
+ /* Did it compress? */
+ if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
+ skb_put(new_skb, new_count);
+ KFREE_SKB(skb);
+ skb = new_skb;
+ } else {
+ /*
+ * The frame could not be compressed, or it could not
+ * be sent in compressed form because CCP is down.
+ */
+ KFREE_SKB(new_skb);
+ }
+ }
+
+ /*
+ * Send the frame
+ */
+ ret = ppp_async_send(ppp, skb);
+ if (ret > 0) {
+ /* we can release the lock */
+ ppp->xmit_busy = 0;
+ } else if (ret < 0) {
+ /* can't happen, since the caller got the xmit_busy lock */
+ printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n");
+ }
+}
+
+/*
+ * Apply VJ TCP header compression to a packet.
+ */
+static struct sk_buff *
+ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb)
+{
+ __u8 *orig_data, *data;
+ struct sk_buff *new_skb;
+ int len, proto;
+
+ new_skb = alloc_skb(skb->len, GFP_ATOMIC);
+ if (new_skb == NULL) {
+ printk(KERN_ERR "ppp: no memory for vj compression\n");
+ return skb;
+ }
+ LIBERATE_SKB(new_skb);
+
+ orig_data = data = skb->data + PPP_HDRLEN;
+ len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN,
+ new_skb->data + PPP_HDRLEN, &data,
+ (ppp->flags & SC_NO_TCP_CCID) == 0);
+
+ if (data == orig_data) {
+ /* Couldn't compress the data */
+ KFREE_SKB(new_skb);
+ return skb;
+ }
+
+ /* The data has been changed */
+ if (data[0] & SL_TYPE_COMPRESSED_TCP) {
+ proto = PPP_VJC_COMP;
+ data[0] ^= SL_TYPE_COMPRESSED_TCP;
+ } else {
+ if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+ proto = PPP_VJC_UNCOMP;
+ else
+ proto = PPP_IP;
+ data[0] = orig_data[0];
+ }
+
+ data = skb_put(new_skb, len + PPP_HDRLEN);
+ data[0] = PPP_ALLSTATIONS;
+ data[1] = PPP_UI;
+ data[2] = 0;
+ data[3] = proto;
+
+ KFREE_SKB(skb);
+ return new_skb;
+}
+
+static inline void
+ppp_send_frames(struct ppp *ppp)
+{
+ struct sk_buff *skb;
+
+ while (!test_and_set_bit(0, &ppp->xmit_busy)) {
+ skb = skb_dequeue(&ppp->xmt_q);
+ if (skb == NULL) {
+ ppp->xmit_busy = 0;
+ break;
+ }
+ ppp_send_frame(ppp, skb);
+ }
+ if (!ppp->xmit_busy && ppp->dev.tbusy) {
+ ppp->dev.tbusy = 0;
+ mark_bh(NET_BH);
+ }