⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ppp.c

📁 unix and linux net driver
💻 C
📖 第 1 页 / 共 5 页
字号:
		ppp->tty = ppp->backup_tty;		if (ppp_tty_push(ppp))			ppp_output_wakeup(ppp);		wake_up_interruptible(&ppp->read_wait);	} else {		ppp->tty = 0;		ppp->sc_xfer = 0;		if (ppp->flags & SC_DEBUG)			printk(KERN_INFO "ppp: channel %s closing.\n",			       ppp2dev(ppp)->name);		ppp_async_release(ppp);		ppp_release(ppp);		MOD_DEC_USE_COUNT;	}}/* * Read a PPP frame from the rcv_q list, * waiting if necessary */static rw_ret_tppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,	     rw_count_t nr){	struct ppp *ppp = tty2ppp (tty);	struct sk_buff *skb;	rw_ret_t len, err;	/*	 * Validate the pointers	 */	if (!ppp)		return -EIO;	CHECK_PPP(-ENXIO);	/*	 * Before we attempt to write the frame to the user, ensure that the	 * user has access to the pages for the total buffer length.	 */	err = verify_area(VERIFY_WRITE, buf, nr);	if (err != 0)		return (err);	/*	 * Wait for a frame to arrive if necessary.	 * We increment the module use count so that the module	 * can't go away while we're sleeping.	 */	MOD_INC_USE_COUNT;	skb = NULL;	for (;;) {		ppp = tty2ppp(tty);		err = 0;		if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse		    || tty != ppp->tty)			break;		skb = skb_dequeue(&ppp->rcv_q);		if (skb != 0)			break;		/*		 * If no frame is available, return -EAGAIN or wait.		 */		err = -EAGAIN;		if (file->f_flags & O_NONBLOCK)			break;		interruptible_sleep_on(&ppp->read_wait);		err = -EINTR;		if (signal_pending(current))			break;	}	MOD_DEC_USE_COUNT;	if (skb == 0)		return err;	/*	 * Ensure that the frame will fit within the caller's buffer.	 * If not, just discard the frame.	 */	len = skb->len;	if (len > nr) {		if (ppp->flags & SC_DEBUG)			printk(KERN_DEBUG			       "ppp: read of %lu bytes too small for %ld "			       "frame\n", (unsigned long) nr, (long) len);		ppp->stats.ppp_ierrors++;		err = -EOVERFLOW;		goto out;	}	/*	 * Copy the received data from the buffer to the caller's area.	 */	err = len;	if (COPY_TO_USER(buf, skb->data, len))		err = -EFAULT;out:	KFREE_SKB(skb);	return err;}/* * Writing to a tty in ppp line discipline sends a PPP frame. * Used by pppd to send control packets (LCP, etc.). */static rw_ret_tppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,	      rw_count_t count){	struct ppp *ppp = tty2ppp (tty);	__u8 *new_data;	struct sk_buff *skb;	/*	 * 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 + PPP_HDRLEN) {		if (ppp->flags & SC_DEBUG)			printk(KERN_WARNING			       "ppp_tty_write: truncating user packet "			       "from %lu to mtu %d\n", (unsigned long) count,			       PPP_MTU + PPP_HDRLEN);		count = PPP_MTU + PPP_HDRLEN;	}	/*	 * Allocate a buffer for the data and fetch it from the user space.	 */	skb = alloc_skb(count, GFP_KERNEL);	if (skb == NULL) {		printk(KERN_ERR "ppp_tty_write: no memory\n");		return 0;	}	LIBERATE_SKB(skb);	new_data = skb_put(skb, count);	/*	 * Retrieve the user's buffer	 */	if (COPY_FROM_USER(new_data, data, count)) {		KFREE_SKB(skb);		return -EFAULT;	}	/*	 * Send the frame	 */	ppp_send_ctrl(ppp, skb);	return (rw_ret_t) count;}/* * Process the IOCTL call for the tty device. * Only the ioctls that relate to using ppp on async serial lines * are processed here; the rest are handled by ppp_ioctl. */static intppp_tty_ioctl (struct tty_struct *tty, struct file * file,               unsigned int param2, unsigned long param3){	struct ppp *ppp = tty2ppp (tty);	register int temp_i = 0;	int error = -EFAULT;	/*	 * Verify the status of the PPP device.	 */	if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)		return -ENXIO;	/*	 * The user must have an euid of root to do these requests.	 */	if (!SUSER())		return -EPERM;	switch (param2) {	case PPPIOCGASYNCMAP:		/*		 * Retrieve the transmit async map		 */		if (PUT_USER(ppp->xmit_async_map[0], (int *) param3))			break;		error = 0;		break;	case PPPIOCSASYNCMAP:		/*		 * Set the transmit async map		 */		if (GET_USER(temp_i, (int *) param3))			break;		ppp->xmit_async_map[0] = temp_i;		if (ppp->flags & SC_DEBUG)			printk(KERN_INFO			       "ppp_tty_ioctl: set xmit asyncmap %x\n",			       ppp->xmit_async_map[0]);		error = 0;		break;	case PPPIOCSRASYNCMAP:		/*		 * Set the receive async map		 */		if (GET_USER(temp_i, (int *) param3))			break;		ppp->recv_async_map = temp_i;		if (ppp->flags & SC_DEBUG)			printk(KERN_INFO			       "ppp_tty_ioctl: set rcv asyncmap %x\n",			       ppp->recv_async_map);		error = 0;		break;	case PPPIOCGXASYNCMAP:		/*		 * Get the map of characters to be escaped on transmission.		 */		if (COPY_TO_USER((void *) param3, ppp->xmit_async_map,				 sizeof (ppp->xmit_async_map)))			break;		error = 0;		break;	case PPPIOCSXASYNCMAP:		/*		 * Set the map of characters to be escaped on transmission.		 */		{			__u32 temp_tbl[8];			if (COPY_FROM_USER(temp_tbl, (void *) param3,					   sizeof (temp_tbl)))				break;			temp_tbl[1]  =	0x00000000;			temp_tbl[2] &= ~0x40000000;			temp_tbl[3] |=	0x60000000;			memcpy(ppp->xmit_async_map, temp_tbl,			       sizeof (ppp->xmit_async_map));			if (ppp->flags & SC_DEBUG)				printk(KERN_INFO				       "ppp_tty_ioctl: set xasyncmap\n");			error = 0;		}		break;	case PPPIOCXFERUNIT:		/*		 * Set up this PPP unit to be used next time this		 * process sets a tty to PPP line discipline.		 */		ppp->backup_tty = tty;		ppp->sc_xfer = current->pid;		error = 0;		break;	case TCGETS:	case TCGETA:		/*		 * Allow users to read, but not set, the serial port parameters		 */		error = n_tty_ioctl (tty, file, param2, param3);		break;	case TCFLSH:		/*		 * Flush our buffers, then call the generic code to		 * flush the serial port's buffer.		 */		if (param3 == TCIFLUSH || param3 == TCIOFLUSH) {			struct sk_buff *skb;			while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)				KFREE_SKB(skb);		}		if (param3 == TCIOFLUSH || param3 == TCOFLUSH)			ppp_tty_flush_output(ppp);		error = n_tty_ioctl (tty, file, param2, param3);		break;	case FIONREAD:		/*		 * Returns how many bytes are available for a read().		 */		{			unsigned long flags;			struct sk_buff *skb;			int count = 0;			save_flags(flags);			cli();			skb = skb_peek(&ppp->rcv_q);			if (skb != 0)				count = skb->len;			restore_flags(flags);			if (PUT_USER(count, (int *) param3))				break;			error = 0;		}		break;	default:		/*		 *  All other ioctl() events will come here.		 */		error = ppp_ioctl(ppp, param2, param3);		break;	}	return error;}/* * TTY callback. * * Process the select() or poll() statement for the PPP device. */#if LINUX_VERSION_CODE < VERSION(2,1,23)static intppp_tty_select(struct tty_struct *tty, struct inode *inode,	       struct file *filp, int sel_type, select_table * wait){	struct ppp *ppp = tty2ppp(tty);	int result = 1;	/*	 * Verify the status of the PPP device.	 */	if (!ppp || tty != ppp->tty)		return -EBADF;	CHECK_PPP(-EBADF);	switch (sel_type) {	case SEL_IN:		/* The fd is readable if the receive queue isn't empty. */		if (skb_peek(&ppp->rcv_q) != NULL)			break;		/* fall through */	case SEL_EX:		/* Check for exceptions or read errors. */		/* Is this a pty link and the remote disconnected? */		if (tty->flags & (1 << TTY_OTHER_CLOSED))			break;		/* Is this a local link and the modem disconnected? */		if (tty_hung_up_p (filp))			break;		select_wait(&ppp->read_wait, wait);		result = 0;		break;	case SEL_OUT:		/* The fd is always writable. */		break;	}	return result;}#else	/* 2.1.23 or later */static unsigned intppp_tty_poll(struct tty_struct *tty, struct file *filp, poll_table * wait){	struct ppp *ppp = tty2ppp(tty);	unsigned int mask = 0;	if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) {		CHECK_PPP(0);		poll_wait(filp, &ppp->read_wait, wait);		if (skb_peek(&ppp->rcv_q) != NULL)			mask |= POLLIN | POLLRDNORM;		if (tty->flags & (1 << TTY_OTHER_CLOSED)		    || tty_hung_up_p(filp))			mask |= POLLHUP;		mask |= POLLOUT | POLLWRNORM;	}	return mask;}#endif	/* >= 2.1.23 *//* * 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. */static voidppp_tty_wakeup (struct tty_struct *tty){	struct ppp *ppp = tty2ppp (tty);	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);	if (!ppp)		return;	CHECK_PPP_VOID();	if (tty != ppp->tty)		return;	if (ppp_tty_push(ppp))		ppp_output_wakeup(ppp);}/* * Send a packet to the peer over a synchronous tty line. * All encoding and FCS are handled by hardware. * Addr/Ctrl and Protocol field compression implemented. * Returns -1 iff the packet could not be accepted at present, * 0 if the packet was accepted but we can't accept another yet, or * 1 if we can accept another packet immediately. * If this procedure returns 0, ppp_output_wakeup will be called * exactly once. */static intppp_sync_send(struct ppp *ppp, struct sk_buff *skb){	unsigned char *data;	int islcp;		CHECK_PPP(0);	if (ppp->tpkt != NULL)		return -1;	ppp->tpkt = skb;	data = ppp->tpkt->data;		/*	 * LCP packets with code values between 1 (configure-reqest)	 * and 7 (code-reject) must be sent as though no options	 * had been negotiated.	 */	islcp = PPP_PROTOCOL(data) == PPP_LCP		&& 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7;	/* only reset idle time for data packets */	if (PPP_PROTOCOL(data) < 0x8000)		ppp->last_xmit = jiffies;	++ppp->stats.ppp_opackets;	ppp->stats.ppp_ooctects += ppp->tpkt->len;	if ( !(data[2]) && (ppp->flags & SC_COMP_PROT) ) {		/* compress protocol field */		data[2] = data[1];		data[1] = data[0];		skb_pull(ppp->tpkt,1);		data = ppp->tpkt->data;	}		/*	 * Do address/control compression	 */	if ((ppp->flags & SC_COMP_AC) && !islcp	    && PPP_ADDRESS(data) == PPP_ALLSTATIONS	    && PPP_CONTROL(data) == PPP_UI) {		/* strip addr and control field */		skb_pull(ppp->tpkt,2);	}	return ppp_tty_sync_push(ppp);}/* * Push a synchronous frame out to the tty. * Returns 1 if frame accepted (or discarded), 0 otherwise. */static intppp_tty_sync_push(struct ppp *ppp){	int sent;	struct tty_struct *tty = ppp2tty(ppp);	unsigned long flags;			CHECK_PPP(0);	if (ppp->tpkt == NULL)		return 0;			/* prevent reentrancy with tty_pushing flag */			save_flags(flags);	cli();	if (ppp->tty_pushing) {		/* record wakeup attempt so we don't lose */		/* a wakeup call while doing push processing */		ppp->woke_up=1;		restore_flags(flags);		return 0;	}	ppp->tty_pushing = 1;	restore_flags(flags);		if (tty == NULL || tty->disc_data != (void *) ppp)		goto flush;			for(;;){		ppp->woke_up=0;				/* Note: Sync driver accepts complete frame or nothing */		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);		sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len);		if (sent < 0) {			/* write error (possible loss of CD) */			/* record error and discard current packet */			ppp->stats.ppp_oerrors++;			break;		}		ppp->stats.ppp_obytes += sent;		if (sent < ppp->tpkt->len) {			/* driver unable to accept frame just yet */			save_flags(flags);			cli();			if (ppp->woke_up) {				/* wake up called while processing */				/* try to send the frame again */				restore_flags(flags);				continue;			}			/* wait for wakeup callback to try send again */			ppp->tty_pushing = 0;			restore_flags(flags);			return 0;		}		break;	}flush:		/* done with current packet (sent or discarded) */	KFREE_SKB(ppp->tpkt);	ppp->tpkt = 0;	ppp->tty_pushing = 0;	return 1;}/* * Send a packet to the peer over an async tty line. * Returns -1 iff the packet could not be accepted at present, * 0 if the packet was accepted but we can't accept another yet, or * 1 if we can accept another packet immediately.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -