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

📄 ppp_async.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78};EXPORT_SYMBOL(ppp_crc16_table);#define fcstab	ppp_crc16_table		/* for PPP_FCS macro *//* * Procedure to encode the data for async serial transmission. * Does octet stuffing (escaping), puts the address/control bytes * on if A/C compression is disabled, and does protocol compression. * Assumes ap->tpkt != 0 on entry. * Returns 1 if we finished the current frame, 0 otherwise. */#define PUT_BYTE(ap, buf, c, islcp)	do {		\	if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\		*buf++ = PPP_ESCAPE;			\		*buf++ = c ^ 0x20;			\	} else						\		*buf++ = c;				\} while (0)static intppp_async_encode(struct asyncppp *ap){	int fcs, i, count, c, proto;	unsigned char *buf, *buflim;	unsigned char *data;	int islcp;	buf = ap->obuf;	ap->olim = buf;	ap->optr = buf;	i = ap->tpkt_pos;	data = ap->tpkt->data;	count = ap->tpkt->len;	fcs = ap->tfcs;	proto = (data[0] << 8) + data[1];	/*	 * LCP packets with code values between 1 (configure-reqest)	 * and 7 (code-reject) must be sent as though no options	 * had been negotiated.	 */	islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;	if (i == 0) {		if (islcp)			async_lcp_peek(ap, data, count, 0);		/*		 * Start of a new packet - insert the leading FLAG		 * character if necessary.		 */		if (islcp || flag_time == 0		    || jiffies - ap->last_xmit >= flag_time)			*buf++ = PPP_FLAG;		ap->last_xmit = jiffies;		fcs = PPP_INITFCS;		/*		 * Put in the address/control bytes if necessary		 */		if ((ap->flags & SC_COMP_AC) == 0 || islcp) {			PUT_BYTE(ap, buf, 0xff, islcp);			fcs = PPP_FCS(fcs, 0xff);			PUT_BYTE(ap, buf, 0x03, islcp);			fcs = PPP_FCS(fcs, 0x03);		}	}	/*	 * 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 = ap->obuf + OBUFSIZE - 6;	while (i < count && buf < buflim) {		c = data[i++];		if (i == 1 && c == 0 && (ap->flags & SC_COMP_PROT))			continue;	/* compress protocol field */		fcs = PPP_FCS(fcs, c);		PUT_BYTE(ap, buf, c, islcp);	}	if (i < count) {		/*		 * Remember where we are up to in this packet.		 */		ap->olim = buf;		ap->tpkt_pos = i;		ap->tfcs = fcs;		return 0;	}	/*	 * We have finished the packet.  Add the FCS and flag.	 */	fcs = ~fcs;	c = fcs & 0xff;	PUT_BYTE(ap, buf, c, islcp);	c = (fcs >> 8) & 0xff;	PUT_BYTE(ap, buf, c, islcp);	*buf++ = PPP_FLAG;	ap->olim = buf;	kfree_skb(ap->tpkt);	ap->tpkt = 0;	return 1;}/* * Transmit-side routines. *//* * Send a packet to the peer over an async tty line. * Returns 1 iff the packet was accepted. * If the packet was not accepted, we will call ppp_output_wakeup * at some later time. */static intppp_async_send(struct ppp_channel *chan, struct sk_buff *skb){	struct asyncppp *ap = chan->private;	ppp_async_push(ap);	if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags))		return 0;	/* already full */	ap->tpkt = skb;	ap->tpkt_pos = 0;	ppp_async_push(ap);	return 1;}/* * Push as much data as possible out to the tty. */static intppp_async_push(struct asyncppp *ap){	int avail, sent, done = 0;	struct tty_struct *tty = ap->tty;	int tty_stuffed = 0;	set_bit(XMIT_WAKEUP, &ap->xmit_flags);	if (!spin_trylock_bh(&ap->xmit_lock))		return 0;	for (;;) {		if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))			tty_stuffed = 0;		if (!tty_stuffed && ap->optr < ap->olim) {			avail = ap->olim - ap->optr;			set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);			sent = tty->driver.write(tty, 0, ap->optr, avail);			if (sent < 0)				goto flush;	/* error, e.g. loss of CD */			ap->optr += sent;			if (sent < avail)				tty_stuffed = 1;			continue;		}		if (ap->optr == ap->olim && ap->tpkt != 0) {			if (ppp_async_encode(ap)) {				/* finished processing ap->tpkt */				clear_bit(XMIT_FULL, &ap->xmit_flags);				done = 1;			}			continue;		}		/* haven't made any progress */		spin_unlock_bh(&ap->xmit_lock);		if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)		      || (!tty_stuffed && ap->tpkt != 0)))			break;		if (!spin_trylock_bh(&ap->xmit_lock))			break;	}	return done;flush:	if (ap->tpkt != 0) {		kfree_skb(ap->tpkt);		ap->tpkt = 0;		clear_bit(XMIT_FULL, &ap->xmit_flags);		done = 1;	}	ap->optr = ap->olim;	spin_unlock_bh(&ap->xmit_lock);	return done;}/* * Flush output from our internal buffers. * Called for the TCFLSH ioctl. */static voidppp_async_flush_output(struct asyncppp *ap){	int done = 0;	spin_lock_bh(&ap->xmit_lock);	ap->optr = ap->olim;	if (ap->tpkt != NULL) {		kfree_skb(ap->tpkt);		ap->tpkt = 0;		clear_bit(XMIT_FULL, &ap->xmit_flags);		done = 1;	}	spin_unlock_bh(&ap->xmit_lock);	if (done)		ppp_output_wakeup(&ap->chan);}/* * Receive-side routines. *//* see how many ordinary chars there are at the start of buf */static inline intscan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count){	int i, c;	for (i = 0; i < count; ++i) {		c = buf[i];		if (c == PPP_ESCAPE || c == PPP_FLAG		    || (c < 0x20 && (ap->raccm & (1 << c)) != 0))			break;	}	return i;}/* called when a flag is seen - do end-of-packet processing */static inline voidprocess_input_packet(struct asyncppp *ap){	struct sk_buff *skb;	unsigned char *p;	unsigned int len, fcs, proto;	int code = 0;	skb = ap->rpkt;	ap->rpkt = 0;	if ((ap->state & (SC_TOSS | SC_ESCAPE)) || skb == 0) {		ap->state &= ~(SC_TOSS | SC_ESCAPE);		if (skb != 0)			kfree_skb(skb);		return;	}	/* check the FCS */	p = skb->data;	len = skb->len;	if (len < 3)		goto err;	/* too short */	fcs = PPP_INITFCS;	for (; len > 0; --len)		fcs = PPP_FCS(fcs, *p++);	if (fcs != PPP_GOODFCS)		goto err;	/* bad FCS */	skb_trim(skb, skb->len - 2);	/* check for address/control and protocol compression */	p = skb->data;	if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {		/* chop off address/control */		if (skb->len < 3)			goto err;		p = skb_pull(skb, 2);	}	proto = p[0];	if (proto & 1) {		/* protocol is compressed */		skb_push(skb, 1)[0] = 0;	} else {		if (skb->len < 2)			goto err;		proto = (proto << 8) + p[1];		if (proto == PPP_LCP)			async_lcp_peek(ap, p, skb->len, 1);	}	/* all OK, give it to the generic layer */	ppp_input(&ap->chan, skb);	return; err:	kfree_skb(skb);	ppp_input_error(&ap->chan, code);}static inline voidinput_error(struct asyncppp *ap, int code){	ap->state |= SC_TOSS;	ppp_input_error(&ap->chan, code);}/* called when the tty driver has data for us. */static voidppp_async_input(struct asyncppp *ap, const unsigned char *buf,		char *flags, int count){	struct sk_buff *skb;	int c, i, j, n, s, f;	unsigned char *sp;	/* update bits used for 8-bit cleanness detection */	if (~ap->rbits & SC_RCV_BITS) {		s = 0;		for (i = 0; i < count; ++i) {			c = buf[i];			if (flags != 0 && flags[i] != 0)				continue;			s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0;			c = ((c >> 4) ^ c) & 0xf;			s |= (0x6996 & (1 << c))? SC_RCV_ODDP: SC_RCV_EVNP;		}		ap->rbits |= s;	}	while (count > 0) {		/* scan through and see how many chars we can do in bulk */		if ((ap->state & SC_ESCAPE) && buf[0] == PPP_ESCAPE)			n = 1;		else			n = scan_ordinary(ap, buf, count);		f = 0;		if (flags != 0 && (ap->state & SC_TOSS) == 0) {			/* check the flags to see if any char had an error */			for (j = 0; j < n; ++j)				if ((f = flags[j]) != 0)					break;		}		if (f != 0) {			/* start tossing */			input_error(ap, f);		} else if (n > 0 && (ap->state & SC_TOSS) == 0) {			/* stuff the chars in the skb */			skb = ap->rpkt;			if (skb == 0) {				skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);				if (skb == 0)					goto nomem;				/* Try to get the payload 4-byte aligned */				if (buf[0] != PPP_ALLSTATIONS)					skb_reserve(skb, 2 + (buf[0] & 1));				ap->rpkt = skb;			}			if (n > skb_tailroom(skb)) {				/* packet overflowed MRU */				input_error(ap, 1);			} else {				sp = skb_put(skb, n);				memcpy(sp, buf, n);				if (ap->state & SC_ESCAPE) {					sp[0] ^= 0x20;					ap->state &= ~SC_ESCAPE;				}			}		}		if (n >= count)			break;		c = buf[n];		if (c == PPP_FLAG) {			process_input_packet(ap);		} else if (c == PPP_ESCAPE) {			ap->state |= SC_ESCAPE;		}		/* otherwise it's a char in the recv ACCM */		++n;		buf += n;		if (flags != 0)			flags += n;		count -= n;	}	return; nomem:	printk(KERN_ERR "PPPasync: no memory (input pkt)\n");	input_error(ap, 0);}/* * We look at LCP frames going past so that we can notice * and react to the LCP configure-ack from the peer. * In the situation where the peer has been sent a configure-ack * already, LCP is up once it has sent its configure-ack * so the immediately following packet can be sent with the * configured LCP options.  This allows us to process the following * packet correctly without pppd needing to respond quickly. * * We only respond to the received configure-ack if we have just * sent a configure-request, and the configure-ack contains the * same data (this is checked using a 16-bit crc of the data). */#define CONFREQ		1	/* LCP code field values */#define CONFACK		2#define LCP_MRU		1	/* LCP option numbers */#define LCP_ASYNCMAP	2static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,			   int len, int inbound){	int dlen, fcs, i, code;	u32 val;	data += 2;		/* skip protocol bytes */	len -= 2;	if (len < 4)		/* 4 = code, ID, length */		return;	code = data[0];	if (code != CONFACK && code != CONFREQ)		return;	dlen = (data[2] << 8) + data[3];	if (len < dlen)		return;		/* packet got truncated or length is bogus */	if (code == (inbound? CONFACK: CONFREQ)) {		/*		 * sent confreq or received confack:		 * calculate the crc of the data from the ID field on.		 */		fcs = PPP_INITFCS;		for (i = 1; i < dlen; ++i)			fcs = PPP_FCS(fcs, data[i]);		if (!inbound) {			/* outbound confreq - remember the crc for later */			ap->lcp_fcs = fcs;			return;		}		/* received confack, check the crc */		fcs ^= ap->lcp_fcs;		ap->lcp_fcs = -1;		if (fcs != 0)			return;	} else if (inbound)		return;	/* not interested in received confreq */	/* process the options in the confack */	data += 4;	dlen -= 4;	/* data[0] is code, data[1] is length */	while (dlen >= 2 && dlen >= data[1]) {		switch (data[0]) {		case LCP_MRU:			val = (data[2] << 8) + data[3];			if (inbound)				ap->mru = val;			else				ap->chan.mtu = val;			break;		case LCP_ASYNCMAP:			val = (data[2] << 24) + (data[3] << 16)				+ (data[4] << 8) + data[5];			if (inbound)				ap->raccm = val;			else				ap->xaccm[0] = val;			break;		}		dlen -= data[1];		data += data[1];	}}void __exit ppp_async_cleanup(void){	if (tty_register_ldisc(N_PPP, NULL) != 0)		printk(KERN_ERR "failed to unregister PPP line discipline\n");}module_init(ppp_async_init);module_exit(ppp_async_cleanup);

⌨️ 快捷键说明

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