+ /*
+ * Limit queue length by dropping old frames.
+ */
+ skb_queue_tail(&ppp->rcv_q, skb);
+ while (ppp->rcv_q.qlen > PPP_MAX_RCV_QLEN) {
+ struct sk_buff *skb = skb_dequeue(&ppp->rcv_q);
+ if (skb)
+ kfree_skb(skb);
+ }
+
+ wake_up_interruptible (&ppp->read_wait);
+ if (ppp->tty->fasync != NULL)
+ kill_fasync (ppp->tty->fasync, SIGIO);
+
+ return 1;
+}
+
+/*************************************************************
+ * TRANSMIT-SIDE ROUTINES
+ *************************************************************/
+
+/* local function to store a value into the LQR frame */
+extern inline __u8 * store_long (register __u8 *p, register int value) {
+ *p++ = (__u8) (value >> 24);
+ *p++ = (__u8) (value >> 16);
+ *p++ = (__u8) (value >> 8);
+ *p++ = (__u8) value;
+ return p;
+}
+
+/*
+ * Compress and send an frame to the peer.
+ * Should be called with dev->tbusy == 1, having been set by the caller.
+ * That is, we use dev->tbusy as a lock to prevent reentry of this
+ * procedure.
+ */
+static void
+ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
+{
+ int proto;
+ __u8 *data;
+ int count;
+ __u8 *p;
+ int ret;
+
+ CHECK_PPP_VOID();
+ data = skb->data;
+ count = skb->len;
+
+ /* dump the buffer */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("write frame", data, count);
+
+ /*
+ * Handle various types of protocol-specific compression
+ * and other processing, including:
+ * - VJ TCP header compression
+ * - updating LQR packets
+ * - updating CCP state on CCP packets
+ */
+ proto = PPP_PROTOCOL(data);
+ switch (proto) {
+ case PPP_IP:
+ if ((ppp->flags & SC_COMP_TCP) && ppp->slcomp != NULL)
+ skb = ppp_vj_compress(ppp, skb);
+ break;
+
+ 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->dev.tbusy = 0;
+ return;
+ }
+
+ /* 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->dev.tbusy = 0;
+ } else if (ret < 0) {
+ /* this can't happen, since the caller got the tbusy lock */
+ printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n");
+ }