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

📄 ppp.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		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;	}	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 (ssize_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 (!capable(CAP_NET_ADMIN))		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 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 poll() statement for the PPP device. */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;}/* * 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 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. * If this procedure returns 0, ppp_output_wakeup will be called * exactly once. */static intppp_async_send(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	ppp_tty_push(ppp);	if (ppp->tpkt != NULL)		return -1;	ppp->tpkt = skb;	ppp->tpkt_pos = 0;	return ppp_tty_push(ppp);}/* * Push as much data as possible out to the tty. * Returns 1 if we finished encoding the current frame, 0 otherwise. */static intppp_tty_push(struct ppp *ppp){	int avail, sent, done = 0;	struct tty_struct *tty = ppp2tty(ppp);	CHECK_PPP(0);	if (ppp->tty_pushing)		return 0;	if (tty == NULL || tty->disc_data != (void *) ppp)		goto flush;	while (ppp->optr < ppp->olim || ppp->tpkt != 0) {		ppp->tty_pushing = 1;		avail = ppp->olim - ppp->optr;		if (avail > 0) {			tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);			sent = tty->driver.write(tty, 0, ppp->optr, avail);			if (sent < 0)				goto flush;	/* error, e.g. loss of CD */			ppp->stats.ppp_obytes += sent;			ppp->optr += sent;			if (sent < avail) {				ppp->tty_pushing = 0;				return done;			}		}		if (ppp->tpkt != 0)			done = ppp_async_encode(ppp);		ppp->tty_pushing = 0;	}	return done;flush:	ppp->tty_pushing = 1;	ppp->stats.ppp_oerrors++;	if (ppp->tpkt != 0) {		kfree_skb(ppp->tpkt);		ppp->tpkt = 0;		done = 1;	}	ppp->optr = ppp->olim;	ppp->tty_pushing = 0;	return done;}/* * Procedure to encode the data for async serial transmission. * Does octet stuffing (escaping) and address/control * and protocol compression. * Assumes ppp->opkt != 0 on entry. * Returns 1 if we finished the current frame, 0 otherwise. */static intppp_async_encode(struct ppp *ppp){	int fcs, i, count, c;	unsigned char *buf, *buflim;	unsigned char *data;	int islcp;	CHECK_PPP(0);	buf = ppp->obuf;	ppp->olim = buf;	ppp->optr = buf;	i = ppp->tpkt_pos;	data = ppp->tpkt->data;	count = ppp->tpkt->len;	fcs = ppp->tfcs;	/*	 * 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;	if (i == 0) {		/*		 * Start of a new packet - insert the leading FLAG		 * character if necessary.		 */		if (islcp || flag_time == 0		    || jiffies - ppp->last_xmit >= flag_time)			*buf++ = PPP_FLAG;		/* only reset idle time for data packets */		if (PPP_PROTOCOL(data) < 0x8000)			ppp->last_xmit = jiffies;		fcs = PPP_INITFCS;		++ppp->stats.ppp_opackets;		ppp->stats.ppp_ooctects += count;		/*		 * Do address/control compression		 */		if ((ppp->flags & SC_COMP_AC) != 0 && !islcp		    && PPP_ADDRESS(data) == PPP_ALLSTATIONS		    && PPP_CONTROL(data) == PPP_UI)			i += 2;	}	/*	 * Once we put in the last byte, we need to put in the FCS	 * and closing flag, so make sure there is at least 7 bytes	 * of free space in the output buffer.	 */	buflim = buf + OBUFSIZE - 6;	while (i < count && buf < buflim) {		c = data[i++];		if (i == 3 && c == 0 && (ppp->flags & SC_COMP_PROT))			continue;	/* compress protocol field */		fcs = PPP_FCS(fcs, c);		if (in_xmap(ppp, c) || (islcp && c < 0x20)) {			*buf++ = PPP_ESCAPE;			c ^= 0x20;		}		*buf++ = c;	}	if (i == count) {		/*		 * We have finished the packet.  Add the FCS and flag.		 */		fcs = ~fcs;		c = fcs & 0xff;		if (in_xmap(ppp, c) || (islcp && c < 0x20)) {			*buf++ = PPP_ESCAPE;			c ^= 0x20;		}		*buf++ = c;		c = (fcs >> 8) & 0xff;		if (in_xmap(ppp, c) || (islcp && c < 0x20)) {			*buf++ = PPP_ESCAPE;			c ^= 0x20;		}		*buf++ = c;		*buf++ = PPP_FLAG;		ppp->olim = buf;		kfree_skb(ppp->tpkt);		ppp->tpkt = 0;		return 1;	}	/*	 * Remember where we are up to in this packet.	 */	ppp->olim = buf;	ppp->tpkt_pos = i;	ppp->tfcs = fcs;	return 0;}/* * 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);	struct sk_buff *skb;	int chr, flg;	unsigned char *p;	if (ppp != 0)		CHECK_PPP_VOID();	/*	 * This can happen if stuff comes in on the backup tty.	 */	if (ppp == 0 || tty != ppp->tty)		return;	/*	 * Verify the table pointer and ensure that the line is	 * still in PPP discipline.	 */	if (ppp->magic != PPP_MAGIC) {		if (ppp->flags & SC_DEBUG)			printk(KERN_DEBUG			       "PPP: tty_receive called but couldn't find "			       "PPP struct.\n");		return;	}	/*	 * Print the buffer if desired	 */	if (ppp->flags & SC_LOG_RAWIN)		ppp_print_buffer ("receive buffer", data, count);	ppp->stats.ppp_ibytes += count;	skb = ppp->rpkt;	while (count-- > 0) {		/*		 * Collect the character and error condition for the character.		 * Set the toss flag for the first character error.		 */		chr = *data++;		if (flags) {			flg = *flags++;			if (flg) {				if (ppp->toss == 0)					ppp->toss = flg;				switch (flg) {				case TTY_OVERRUN:					++ppp->estats.rx_fifo_errors;					break;				case TTY_FRAME:				case TTY_BREAK:					++ppp->estats.rx_frame_errors;					break;				}				continue;			}		}		/*		 * Set the flags for d7 being 0/1 and parity being		 * even/odd so that the normal processing would have		 * all flags set at the end of the session.  A		 * missing flag bit indicates an error condition.		 */#ifdef CHECK_CHARACTERS		if (chr & 0x80)			ppp->flags |= SC_RCV_B7_1;		else			ppp->flags |= SC_RCV_B7_0;		if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))			ppp->flags |= SC_RCV_ODDP;		else			ppp->flags |= SC_RCV_EVNP;#endif		if (chr == PPP_FLAG) {			/*			 * FLAG. This is the end of the block. If the block			 * ends with ESC FLAG, then the block is to be ignored.			 */			if (ppp->escape)				ppp->toss |= 0x80;			/*			 * Process the frame if it was received correctly.			 * If there was an error, let the VJ decompressor know.			 * There are 4 cases here:			 * skb != NULL, toss != 0: error in frame			 * skb != NULL, toss == 0: frame ok			 * skb == NULL, toss != 0: very first frame,			 *	error on 1st char, or alloc_skb failed			 * skb == NULL, toss == 0: empty frame (~~)			 */			if (ppp->toss || !ppp_receive_frame(ppp, skb)) {				if (ppp->toss && (ppp->flags & SC_DEBUG))					printk(KERN_DEBUG					       "ppp: tossing frame (%x)\n",					       ppp->toss);				if (skb != NULL)					kfree_skb(skb);				if (!(ppp->toss == 0xE0 || ppp->toss == 0x80))					++ppp->stats.ppp_ierrors;				ppp_receive_error(ppp);			}			/*			 * Reset for the next frame.			 */			skb = NULL;			ppp->rfcs = PPP_INITFCS;			ppp->escape = 0;			ppp->toss = 0;			continue;		}		/* If we're tossing, look no further. */		if (ppp->toss != 0)			continue;		/* If this is a control char to be ignored, do so */		if (in_rmap(ppp, chr))			continue;		/*		 * Modify the next character if preceded by escape.		 * The escape character (0x7d) could be an escaped		 * 0x5d, if it follows an escape :-)		 */		if (ppp->escape) {			chr ^= PPP_TRANS;

⌨️ 快捷键说明

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