📄 ppp.c
字号:
extern inline intlock_buffer (register struct ppp_buffer *buf){ register int state; int flags;/* * Save the current state and if free then set it to the "busy" state */ save_flags (flags); cli (); state = buf->locked; if (state == 0) buf->locked = 2; restore_flags (flags); return (state);}/* * MTU has been changed by the IP layer. Unfortunately we are not told * about this, but we spot it ourselves and fix things up. We could be * in an upcall from the tty driver, or in an ip packet queue. */static intppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru){ struct device *dev; struct ppp_buffer *new_rbuf; struct ppp_buffer *new_wbuf; struct ppp_buffer *new_cbuf; struct ppp_buffer *new_tbuf; struct ppp_buffer *old_rbuf; struct ppp_buffer *old_wbuf; struct ppp_buffer *old_cbuf; struct ppp_buffer *old_tbuf; int mtu, mru;/* * Allocate the buffer from the kernel for the data */ dev = ppp2dev (ppp); mru = new_mru; /* allow for possible escaping of every character */ mtu = (new_mtu * 2) + 20; /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */ if (mru < PPP_MRU) mru = PPP_MRU; mru += 10; if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n", dev->name, new_mtu, new_mru); new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR); new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR); new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD); new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN, BUFFER_TYPE_VJ);/* * If the buffers failed to allocate then complain and release the partial * allocations. */ if (new_wbuf == NULL || new_tbuf == NULL || new_rbuf == NULL || new_cbuf == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp: failed to allocate new buffers\n"); ppp_free_buf (new_wbuf); ppp_free_buf (new_tbuf); ppp_free_buf (new_rbuf); ppp_free_buf (new_cbuf); return 0; }/* * Update the pointers to the new buffer structures. */ cli (); old_wbuf = ppp->wbuf; old_rbuf = ppp->rbuf; old_cbuf = ppp->cbuf; old_tbuf = ppp->tbuf; ppp->wbuf = new_wbuf; ppp->rbuf = new_rbuf; ppp->cbuf = new_cbuf; ppp->tbuf = new_tbuf; ppp->rbuf->size -= 80; /* reserve space for vj header expansion */ dev->mem_start = (unsigned long) buf_base (new_wbuf); dev->mem_end = (unsigned long) (dev->mem_start + mtu); dev->rmem_start = (unsigned long) buf_base (new_rbuf); dev->rmem_end = (unsigned long) (dev->rmem_start + mru);/* * Update the parameters for the new buffer sizes */ ppp->toss = 0xE0; /* To ignore characters until new FLAG */ ppp->escape = 0; /* No pending escape character */ dev->mtu = ppp->mtu = new_mtu; ppp->mru = new_mru; ppp->s1buf = NULL; ppp->s2buf = NULL; ppp->xbuf = NULL; ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); ppp->flags &= ~SC_XMIT_BUSY; sti ();/* * Release old buffer pointers */ ppp_free_buf (old_rbuf); ppp_free_buf (old_wbuf); ppp_free_buf (old_cbuf); ppp_free_buf (old_tbuf); return 1;}/* * CCP is down; free (de)compressor state if necessary. */static voidppp_ccp_closed (struct ppp *ppp){ if (ppp->sc_xc_state) { (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state); ppp->sc_xc_state = NULL; } if (ppp->sc_rc_state) { (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state); ppp->sc_rc_state = NULL; }}/* * Called to release all of the information in the current PPP structure. * * It is called when the ppp device goes down or if it is unable to go * up. */static voidppp_release (struct ppp *ppp){ struct tty_struct *tty; struct device *dev; tty = ppp2tty (ppp); dev = ppp2dev (ppp); ppp_ccp_closed (ppp); /* Ensure that the pppd process is not hanging on select() */ wake_up_interruptible (&ppp->read_wait); wake_up_interruptible (&ppp->write_wait); if (tty != NULL && tty->disc_data == ppp) tty->disc_data = NULL; /* Break the tty->ppp link */ if (dev && dev->flags & IFF_UP) { dev_close (dev); /* close the device properly */ dev->flags &= ~IFF_UP; /* prevent recursion */ } ppp_free_buf (ppp->rbuf); ppp_free_buf (ppp->wbuf); ppp_free_buf (ppp->cbuf); ppp_free_buf (ppp->ubuf); ppp_free_buf (ppp->tbuf); ppp->rbuf = ppp->wbuf = ppp->cbuf = ppp->tbuf = ppp->xbuf = ppp->s1buf = ppp->s2buf = ppp->ubuf = NULL; if (ppp->slcomp) { slhc_free (ppp->slcomp); ppp->slcomp = NULL; } ppp->inuse = 0; ppp->tty = NULL;}/* * Device callback. * * Called when the PPP device goes down in response to an ifconfig request. */static voidppp_tty_close_local (struct tty_struct *tty, int sc_xfer){ struct ppp *ppp = tty2ppp (tty); if (ppp != NULL) { if (ppp->magic != PPP_MAGIC) { if (ppp->flags & SC_DEBUG) printk (KERN_WARNING "ppp: trying to close unopened tty!\n"); } else { CHECK_PPP_VOID(); ppp->sc_xfer = sc_xfer; if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp: channel %s closing.\n", ppp2dev(ppp) -> name); ppp_release (ppp); MOD_DEC_USE_COUNT; } }}static voidppp_tty_close (struct tty_struct *tty){ ppp_tty_close_local (tty, 0);}/* * TTY callback. * * Called when the tty discipline is switched to PPP. */static intppp_tty_open (struct tty_struct *tty){ struct ppp *ppp = tty2ppp (tty); int indx;/* * There should not be an existing table for this slot. */ if (ppp) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_tty_open: gack! tty already associated to %s!\n", ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name : "unknown"); return -EEXIST; }/* * Allocate the structure from the system */ ppp = ppp_find(current->pid); if (ppp == NULL) { ppp = ppp_find(0); if (ppp == NULL) ppp = ppp_alloc(); } if (ppp == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_tty_open: couldn't allocate ppp channel\n"); return -ENFILE; }/* * Initialize the control block */ ppp_init_ctrl_blk (ppp); ppp->tty = tty; tty->disc_data = ppp;/* * Flush any pending characters in the driver and discipline. */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty);/* * Allocate space for the default VJ header compression slots */ ppp->slcomp = slhc_init (16, 16); if (ppp->slcomp == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_tty_open: no space for compression buffers!\n"); ppp_release (ppp); return -ENOMEM; }/* * Allocate space for the MTU and MRU buffers */ if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) { ppp_release (ppp); return -ENOMEM; }/* * Allocate space for a user level buffer */ ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD); if (ppp->ubuf == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_tty_open: no space for user receive buffer\n"); ppp_release (ppp); return -ENOMEM; } if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp: channel %s open\n", ppp2dev(ppp)->name); for (indx = 0; indx < NUM_NP; ++indx) ppp->sc_npmode[indx] = NPMODE_PASS; MOD_INC_USE_COUNT; return (ppp->line);}/* * Local function to send the next portion of the buffer. * * Called by the tty driver's tty_wakeup function should it be entered * because the partial buffer was transmitted. * * Called by kick_tty to send the initial portion of the buffer. * * Completion processing of the buffer transmission is handled here. */static voidppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, struct ppp_buffer *xbuf){ register int count, actual;/* * Prevent re-entrancy by ensuring that this routine is called only once. */ cli (); if (ppp->flags & SC_XMIT_BUSY) { sti (); return; } ppp->flags |= SC_XMIT_BUSY; sti ();/* * Send the next block of data to the modem */ count = xbuf->count - xbuf->tail; actual = tty->driver.write (tty, 0, buf_base (xbuf) + xbuf->tail, count);/* * Terminate transmission of any block which may have an error. * This could occur should the carrier drop. */ if (actual < 0) { ppp->stats.ppp_oerrors++; actual = count; } else ppp->bytes_sent += actual;/* * If the buffer has been transmitted then clear the indicators. */ xbuf->tail += actual; if (actual == count) { xbuf = NULL; ppp->flags &= ~SC_XMIT_BUSY;/* * Complete the transmission on the current buffer. */ xbuf = ppp->xbuf; if (xbuf != NULL) { tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); xbuf->locked = 0; ppp->xbuf = NULL;/* * If the completed buffer came from the device write, then complete the * transmission block. */ if (ppp2dev (ppp) -> flags & IFF_UP) { if (xbuf->type == BUFFER_TYPE_DEV_WR) ppp2dev (ppp)->tbusy = 0; mark_bh (NET_BH); }/* * Wake up the transmission queue for all completion events. */ wake_up_interruptible (&ppp->write_wait);/* * Look at the priorities. Choose a daemon write over the device driver. */ cli(); xbuf = ppp->s1buf; ppp->s1buf = NULL; if (xbuf == NULL) { xbuf = ppp->s2buf; ppp->s2buf = NULL; } sti();/* * If there is a pending buffer then transmit it now. */ if (xbuf != NULL) { ppp->flags &= ~SC_XMIT_BUSY; ppp_kick_tty (ppp, xbuf); return; } } }/* * Clear the re-entry flag */ ppp->flags &= ~SC_XMIT_BUSY;}/* * This function is called by the tty driver when the transmit buffer has * additional space. It is used by the ppp code to continue to transmit * the current buffer should the buffer have been partially sent. * * In addition, it is used to send the first part of the buffer since the * logic and the inter-locking would be identical. */static voidppp_tty_wakeup (struct tty_struct *tty){ struct ppp_buffer *xbuf; struct ppp *ppp = tty2ppp (tty); if (!ppp) return; if (ppp->magic != PPP_MAGIC) return;/* * Ensure that there is a transmission pending. Clear the re-entry flag if * there is no pending buffer. Otherwise, send the buffer. */ xbuf = ppp->xbuf; if (xbuf == NULL) tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); else ppp_tty_wakeup_code (ppp, tty, xbuf);}/* * This function is called to transmit a buffer to the remote. The buffer * is placed on the pending queue if there is presently a buffer being * sent or it is transmitted with the aid of ppp_tty_wakeup. */static voidppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf){ register int flags;/* * Hold interrupts. */ save_flags (flags); cli ();/* * Control the flags which are best performed with the interrupts masked. */ xbuf->locked = 1; xbuf->tail = 0;/* * If the transmitter is busy then place the buffer on the appropriate * priority queue. */ if (ppp->xbuf != NULL) { if (xbuf->type == BUFFER_TYPE_TTY_WR) ppp->s1buf = xbuf; else ppp->s2buf = xbuf; restore_flags (flags); return; }/* * If the transmitter is not busy then this is the highest priority frame */ ppp->flags &= ~SC_XMIT_BUSY; ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); ppp->xbuf = xbuf; restore_flags (flags);/* * Do the "tty wakeup_code" to actually send this buffer. */ ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);}/************************************************************* * TTY INPUT * The following functions handle input that arrives from * the TTY. It recognizes PPP frames and either hands them * to the network layer or queues them for delivery to a * user process reading this TTY. *************************************************************//* * Callback function from tty driver. Return the amount of space left * in the receiver's buffer to decide if remote transmitter is to be * throttled. */static intppp_tty_room (struct tty_struct *tty){ return 65536; /* We can handle an infinite amount of data. :-) */}/* * Callback function when data is available at the tty driver. */static voidppp_tty_receive (struct tty_struct *tty, const __u8 * data, char *flags, int count){ register struct ppp *ppp = tty2ppp (tty); register struct ppp_buffer *buf = NULL; __u8 chr;/* * Fetch the pointer to the buffer. Be careful about race conditions. */ if (ppp != NULL) buf = ppp->rbuf; if (buf == NULL) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -