📄 ppp.c
字号:
malloced_data = 1; } else malloced_data = 0;#endif/* * Process the active decompressor. */ if ((ppp->sc_rc_state != (void *) 0) && (ppp->flags & SC_DECOMP_RUN) && ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) { if (proto == PPP_COMP) {/* * If the frame is compressed then decompress it. */ new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC); if (new_data == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_doframe: no memory\n"); slhc_toss (ppp->slcomp); (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, data, count);#ifndef NO_RMK_TEMP_FIX if (malloced_data) kfree (data);#endif return 1; }/* * Decompress the frame */ new_count = bsd_decompress (ppp->sc_rc_state, data, count, new_data, ppp->mru + 4); switch (new_count) { default: ppp_doframe_lower (ppp, new_data, new_count); kfree (new_data);#ifndef NO_RMK_TEMP_FIX if (malloced_data) kfree (data);#endif return 1; case DECOMP_OK: break; case DECOMP_ERROR: ppp->flags |= SC_DC_ERROR; break; case DECOMP_FATALERROR: ppp->flags |= SC_DC_FERROR; break; }/* * Log the error condition and discard the frame. */ if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_proto_comp: " "decompress err %d\n", new_count); kfree (new_data); slhc_toss (ppp->slcomp);#ifndef NO_RMK_TEMP_FIX if (malloced_data) kfree (data);#endif return 1; }/* * The frame is not special. Pass it through the compressor without * actually compressing the data */ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, data, count); }/* * Process the uncompressed frame. */ ppp_doframe_lower (ppp, data, count);#ifndef NO_RMK_TEMP_FIX if (malloced_data) kfree (data);#endif return 1;}/************************************************************* * LINE DISCIPLINE SUPPORT * The following functions form support user programs * which read and write data on a TTY with the PPP line * discipline. Reading is done from a circular queue, * filled by the lower TTY levels. *************************************************************//* read a PPP frame from the us_rbuff circular buffer, waiting if necessary*/static intppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, unsigned int nr){ struct ppp *ppp = tty2ppp (tty); __u8 c; int len, indx;#define GETC(c) \{ \ c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \ ppp->ubuf->tail &= ppp->ubuf->size; \}/* * Validate the pointers */ 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 " "(EAGAIN)\n"); return -EAGAIN; } 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. */ 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_user (PPP_ALLSTATIONS, buf++); put_user (PPP_UI, buf++); indx = len;/* * Copy the received data from the buffer to the caller's area. */ while (indx-- > 0) { GETC (c); put_user (c, buf); ++buf; } 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 voidppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, register __u8 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 escaping and send the * data to the remote system. */static voidppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, __u8 *data, int count, int non_ip){ __u16 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 intppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, __u8 *data, int count){ int proto; int address, control; __u8 *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 intsend_revise_frame (register struct ppp *ppp, __u8 *data, int len){ __u8 *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 = (__u8 *) &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 */ case PPP_CCP: ppp_proto_ccp (ppp, data + PPP_HARD_HDR_LEN, len - PPP_HARD_HDR_LEN, 0); break; default: break; } return len;}/* * write a frame with NR chars from BUF to TTY * we have to put the FCS field on ourselves */static intppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, unsigned int count){ struct ppp *ppp = tty2ppp (tty); __u8 *new_data; int status;/* * Verify the pointers. */ if (!ppp) return -EIO; if (ppp->magic != PPP_MAGIC) return -EIO; CHECK_PPP (-ENXIO);/* * Ensure that the caller does not wish to send too much. */ if (count > PPP_MTU) { if (ppp->flags & SC_DEBUG) printk (KERN_WARNING "ppp_tty_write: truncating user packet " "from %u to mtu %d\n", count, PPP_MTU); count = PPP_MTU; }/* * Allocate a buffer for the data and fetch it from the user space. */ new_data = kmalloc (count, GFP_KERNEL); if (new_data == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_tty_write: no memory\n"); return 0; }/* * lock this PPP unit so we will be the only writer; * sleep if necessary */ while (lock_buffer (ppp->tbuf) != 0) { current->timeout = 0; if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_write: sleeping\n"); interruptible_sleep_on (&ppp->write_wait); ppp = tty2ppp (tty); if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) { kfree (new_data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -