-/* read a PPP frame from the us_rbuff circular buffer,
- waiting if necessary
-*/
-
-static int
-ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
- unsigned int nr)
-{
- struct ppp *ppp = tty2ppp (tty);
- u_char c;
- int len, indx;
-
-#define GETC(c) \
-{ \
- c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \
- ppp->ubuf->tail &= ppp->ubuf->size; \
-}
-
-/*
- * Validate the pointer to the PPP structure
- */
- if (!ppp)
- return -EIO;
-
- if (ppp->magic != PPP_MAGIC)
- return -EIO;
-
- CHECK_PPP (-ENXIO);
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: called buf=%p nr=%u\n",
- buf, nr);
-/*
- * Acquire the read lock.
- */
- for (;;) {
- ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
- return 0;
-
- if (set_bit (0, &ppp->ubuf->locked) != 0) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(ubuf)\n");
-
- current->timeout = 0;
- current->state = TASK_INTERRUPTIBLE;
- schedule ();
-
- if (current->signal & ~current->blocked)
- return -EINTR;
- continue;
- }
-/*
- * Before we attempt to write the frame to the user, ensure that the
- * user has access to the pages for the total buffer length.
- */
- indx = verify_area (VERIFY_WRITE, buf, nr);
- if (indx != 0)
- return (indx);
-/*
- * Fetch the length of the buffer from the first two bytes.
- */
- if (ppp->ubuf->head == ppp->ubuf->tail)
- len = 0;
- else {
- GETC (c);
- len = c << 8;
- GETC (c);
- len += c;
- }
-/*
- * If there is no length then wait for the data to arrive.
- */
- if (len == 0) {
- /* no data */
- clear_bit (0, &ppp->ubuf->locked);
- if (file->f_flags & O_NONBLOCK) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: no data "
- "(EWOULDBLOCK)\n");
- return -EWOULDBLOCK;
- }
- current->timeout = 0;
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(read_wait)\n");
-
- interruptible_sleep_on (&ppp->read_wait);
- if (current->signal & ~current->blocked)
- return -EINTR;
- continue;
- }
-/*
- * Reset the time of the last read operation.
- */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
-/*
- * Ensure that the frame will fit within the caller's buffer. If not, then
- * discard the frame from the input buffer and return an error to the caller.
- */
- if (len + 2 > nr) {
- /* Can't copy it, update us_rbuff_head */
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp: read of %u bytes too small for %d "
- "frame\n", nr, len + 2);
- ppp->ubuf->tail += len;
- ppp->ubuf->tail &= ppp->ubuf->size;
- clear_bit (0, &ppp->ubuf->locked);
- ppp->stats.ppp_ierrors++;
- return -EOVERFLOW;
- }
-/*
- * Before we attempt to write the frame to the user, ensure that the
- * page tables are proper.
- */
- indx = verify_area (VERIFY_WRITE, buf, len + 2);
- if (indx != 0) {
- ppp->ubuf->tail += len;
- ppp->ubuf->tail &= ppp->ubuf->size;
- clear_bit (0, &ppp->ubuf->locked);
- return (indx);
- }
-/*
- * Fake the insertion of the ADDRESS and CONTROL information because these
- * were not saved in the buffer.
- */
- put_byte_user (PPP_ALLSTATIONS, buf++);
- put_byte_user (PPP_UI, buf++);
-
- indx = len;
-/*
- * Copy the received data from the buffer to the caller's area.
- */
- while (indx-- > 0) {
- GETC (c);
- put_byte_user (c, buf);
- ++buf;
- }
-/*
- * Release the lock and return the character count in the buffer area.
- */
- clear_bit (0, &ppp->ubuf->locked);
- len += 2; /* Account for ADDRESS and CONTROL bytes */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: passing %d bytes up\n", len);
- return len;
- }
-#undef GETC
-}
-
-/* stuff a character into the transmit buffer, using PPP's way of escaping
- special characters.
- also, update fcs to take account of new character */
-
-extern inline void
-ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
- register u_char chr)
-{
-/*
- * The buffer should not be full.
- */
- if (ppp->flags & SC_DEBUG) {
- if ((buf->count < 0) || (buf->count > 3000))
- printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
- (unsigned int) buf->count,
- (unsigned int) chr);
- }
-/*
- * Update the FCS and if the character needs to be escaped, do it.
- */
- buf->fcs = PPP_FCS (buf->fcs, chr);
- if (in_xmap (ppp, chr)) {
- chr ^= PPP_TRANS;
- ins_char (buf, PPP_ESCAPE);
- }
-/*
- * Add the character to the buffer.
- */
- ins_char (buf, chr);
-}
-
-/*
- * 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;
- int address, control;
- int proto;
-/*
- * Insert the leading FLAG character
- */
- buf->count = 0;
-
- if (non_ip || flag_time == 0)
- ins_char (buf, PPP_FLAG);
- else {
- if (jiffies - ppp->last_xmit > flag_time)
- ins_char (buf, PPP_FLAG);
- }
- ppp->last_xmit = jiffies;
- buf->fcs = PPP_INITFCS;
-/*
- * Emit the address/control information if needed
- */
- address = PPP_ADDRESS (data);
- control = PPP_CONTROL (data);
- proto = PPP_PROTOCOL (data);
-
- if (address != PPP_ALLSTATIONS ||
- control != PPP_UI ||
- (ppp->flags & SC_COMP_AC) == 0) {
- ppp_stuff_char (ppp, buf, address);
- ppp_stuff_char (ppp, buf, control);
- }
-/*
- * Emit the protocol (compressed if possible)
- */
- if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
- ppp_stuff_char (ppp, buf, proto >> 8);
-
- ppp_stuff_char (ppp, buf, proto);
-/*
- * Insert the data
- */
- data += 4;
- count -= 4;
-
- 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.
- */
-
-static int
-ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
- u_char *data, int count)
-{
- int proto;
- int address, control;
- 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.
- */
- proto = PPP_PROTOCOL (data);
- address = PPP_ADDRESS (data);
- control = PPP_CONTROL (data);
-
- 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 += new_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);
- }
-/*
- * 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;
-/*
- * 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;