+/*
+ * Procedure to encode the data with the proper escapement and send the
+ * data to the remote system.
+ */
+
+static void
+ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
+ u_char *data, int count, int non_ip)
+{
+ unsigned short int write_fcs;
+/*
+ * Insert the leading FLAG character
+ */
+ buf->count = 0;
+
+#ifdef OPTIMIZE_FLAG_TIME
+ if (non_ip)
+ ins_char (buf, PPP_FLAG);
+ else {
+ if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
+ ins_char (buf, PPP_FLAG);
+ }
+ ppp->last_xmit = jiffies;
+#else
+ ins_char (buf, PPP_FLAG);
+#endif
+
+ buf->fcs = PPP_INITFCS;
+/*
+ * Insert the data
+ */
+ while (count-- > 0)
+ ppp_stuff_char (ppp, buf, *data++);
+/*
+ * Add the trailing CRC and the final flag character
+ */
+ write_fcs = buf->fcs ^ 0xFFFF;
+ ppp_stuff_char (ppp, buf, write_fcs);
+ ppp_stuff_char (ppp, buf, write_fcs >> 8);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
+ write_fcs);
+/*
+ * Add the trailing flag character
+ */
+ ins_char (buf, PPP_FLAG);
+/*
+ * Print the buffer
+ */
+ if (ppp->flags & SC_LOG_FLUSH)
+ ppp_print_buffer ("ppp flush", buf_base (buf),
+ buf->count);
+ else {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_dev_xmit: writing %d chars\n",
+ buf->count);
+ }
+/*
+ * Send the block to the tty driver.
+ */
+ ppp->stats.ppp_obytes += buf->count;
+ ppp_kick_tty (ppp, buf);
+}
+
+/*
+ * Send an frame to the remote with the proper bsd compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
+ */
+
+int
+ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
+ u_char *data, int count)
+{
+ int address, control;
+ int proto;
+ u_char *new_data;
+ int new_count;
+/*
+ * Print the buffer
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("write frame", data, count);
+/*
+ * Determine if the frame may be compressed. Attempt to compress the
+ * frame if possible.
+ */
+ address = PPP_ADDRESS (data);
+ control = PPP_CONTROL (data);
+ proto = PPP_PROTOCOL (data);
+
+#ifdef PPP_COMPRESS
+ if ((ppp->flags & SC_COMP_RUN != 0) &&
+ (ppp->sc_xc_state != (void *) 0) &&
+ (address == PPP_ALLSTATIONS) &&
+ (control == PPP_UI) &&
+ (proto != PPP_LCP) &&
+ (proto != PPP_CCP)) {
+ new_data = kmalloc (count, GFP_ATOMIC);
+ if (new_data == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit_frame: no memory\n");
+ return 1;
+ }
+
+ new_count = bsd_compress (ppp->sc_xc_state,
+ data,
+ new_data,
+ count,
+ count);
+
+ if (new_count > 0) {
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += count;
+
+ ppp_dev_xmit_lower (ppp, buf, new_data,
+ new_count, 0);
+ kfree (new_data);
+ return 0;
+ }
+/*
+ * The frame could not be compressed.
+ */
+ kfree (new_data);
+ }
+#endif
+/*
+ * The frame may not be compressed. Update the statistics before the
+ * count field is destroyed. The frame will be transmitted.
+ */
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += count;
+/*
+ * Do not compress the protocol id if not possible
+ */
+ if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xFF00)) {
+ --data;
+ ++count;
+ }
+
+ data += 3;
+ count -= 3;
+/*
+ * Do not compress the address/control if not possible.
+ */
+ if (address != PPP_ALLSTATIONS ||
+ control != PPP_UI ||
+ !(ppp->flags & SC_COMP_AC)) {
+ *--data = control;
+ *--data = address;
+ count += 2;
+ }
+/*
+ * Go to the escape encoding
+ */
+ ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
+ return 0;
+}
+
+/*
+ * Revise the tty frame for specific protocols.
+ */
+
+static int
+send_revise_frame (register struct ppp *ppp, u_char *data, int len)
+{
+ u_char *p;
+
+ switch (PPP_PROTOCOL (data)) {
+/*
+ * Update the LQR frame with the current MIB information. This saves having
+ * the daemon read old MIB data from the driver.
+ */
+ case PPP_LQR:
+ len = 48; /* total size of this frame */
+ p = (u_char *) &data [40]; /* Point to last two items. */
+ p = store_long (p, ppp->stats.ppp_opackets + 1);
+ p = store_long (p, ppp->stats.ppp_ooctects + len);
+ break;
+/*
+ * Outbound compression frames
+ */
+#ifdef PPP_COMPRESS
+ case PPP_COMP:
+ ppp_proto_ccp (ppp, data, len, 0);
+ break;
+#endif
+
+/*
+ * All other frame types
+ */
+ default:
+ break;
+ }
+
+ return len;
+}
+