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

📄 syncppp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))		return -EINVAL;	dev->mtu=new_mtu;	return 0;}/** *	sppp_do_ioctl - Ioctl handler for ppp/hdlc *	@dev: Device subject to ioctl *	@ifr: Interface request block from the user *	@cmd: Command that is being issued *	 *	This function handles the ioctls that may be issued by the user *	to control the settings of a PPP/HDLC link. It does both busy *	and security checks. This function is intended to be wrapped by *	callers who wish to add additional ioctl calls of their own. */ int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	struct sppp *sp = (struct sppp *)sppp_of(dev);	if(dev->flags&IFF_UP)		return -EBUSY;			if(!capable(CAP_NET_ADMIN))		return -EPERM;		switch(cmd)	{		case SPPPIOCCISCO:			sp->pp_flags|=PP_CISCO;			dev->type = ARPHRD_HDLC;			break;		case SPPPIOCPPP:			sp->pp_flags&=~PP_CISCO;			dev->type = ARPHRD_PPP;			break;		case SPPPIOCDEBUG:			sp->pp_flags&=~PP_DEBUG;			if(ifr->ifr_flags)				sp->pp_flags|=PP_DEBUG;			break;		case SPPPIOCGFLAGS:			if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags)))				return -EFAULT;			break;		case SPPPIOCSFLAGS:			if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags)))				return -EFAULT;			break;		default:			return -EINVAL;	}	return 0;}EXPORT_SYMBOL(sppp_do_ioctl);/** *	sppp_attach - attach synchronous PPP/HDLC to a device *	@pd:	PPP device to initialise * *	This initialises the PPP/HDLC support on an interface. At the *	time of calling the dev element must point to the network device *	that this interface is attached to. The interface should not yet *	be registered.  */ void sppp_attach(struct ppp_device *pd){	struct net_device *dev = pd->dev;	struct sppp *sp = &pd->sppp;	unsigned long flags;	/* Make sure embedding is safe for sppp_of */	BUG_ON(sppp_of(dev) != sp);	spin_lock_irqsave(&spppq_lock, flags);	/* Initialize keepalive handler. */	if (! spppq)	{		init_timer(&sppp_keepalive_timer);		sppp_keepalive_timer.expires=jiffies+10*HZ;		sppp_keepalive_timer.function=sppp_keepalive;		add_timer(&sppp_keepalive_timer);	}	/* Insert new entry into the keepalive list. */	sp->pp_next = spppq;	spppq = sp;	spin_unlock_irqrestore(&spppq_lock, flags);	sp->pp_loopcnt = 0;	sp->pp_alivecnt = 0;	sp->pp_seq = 0;	sp->pp_rseq = 0;	sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/	sp->lcp.magic = 0;	sp->lcp.state = LCP_STATE_CLOSED;	sp->ipcp.state = IPCP_STATE_CLOSED;	sp->pp_if = dev;	spin_lock_init(&sp->lock);		/* 	 *	Device specific setup. All but interrupt handler and	 *	hard_start_xmit.	 */	 	dev->hard_header = sppp_hard_header;	dev->rebuild_header = sppp_rebuild_header;	dev->tx_queue_len = 10;	dev->type = ARPHRD_HDLC;	dev->addr_len = 0;	dev->hard_header_len = sizeof(struct ppp_header);	dev->mtu = PPP_MTU;	/*	 *	These 4 are callers but MUST also call sppp_ functions	 */	dev->do_ioctl = sppp_do_ioctl;#if 0	dev->get_stats = NULL;		/* Let the driver override these */	dev->open = sppp_open;	dev->stop = sppp_close;#endif		dev->change_mtu = sppp_change_mtu;	dev->hard_header_cache = NULL;	dev->header_cache_update = NULL;	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;}EXPORT_SYMBOL(sppp_attach);/** *	sppp_detach - release PPP resources from a device *	@dev:	Network device to release * *	Stop and free up any PPP/HDLC resources used by this *	interface. This must be called before the device is *	freed. */ void sppp_detach (struct net_device *dev){	struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev);	unsigned long flags;	spin_lock_irqsave(&spppq_lock, flags);	/* Remove the entry from the keepalive list. */	for (q = &spppq; (p = *q); q = &p->pp_next)		if (p == sp) {			*q = p->pp_next;			break;		}	/* Stop keepalive handler. */	if (! spppq)		del_timer(&sppp_keepalive_timer);	sppp_clear_timeout (sp);	spin_unlock_irqrestore(&spppq_lock, flags);}EXPORT_SYMBOL(sppp_detach);/* * Analyze the LCP Configure-Request options list * for the presence of unknown options. * If the request contains unknown options, build and * send Configure-reject packet, containing only unknown options. */static intsppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,	int len, u32 *magic){	u8 *buf, *r, *p;	int rlen;	len -= 4;	buf = r = kmalloc (len, GFP_ATOMIC);	if (! buf)		return (0);	p = (void*) (h+1);	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {		switch (*p) {		case LCP_OPT_MAGIC:			/* Magic number -- extract. */			if (len >= 6 && p[1] == 6) {				*magic = (u32)p[2] << 24 |					(u32)p[3] << 16 | p[4] << 8 | p[5];				continue;			}			break;		case LCP_OPT_ASYNC_MAP:			/* Async control character map -- check to be zero. */			if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&			    ! p[4] && ! p[5])				continue;			break;		case LCP_OPT_MRU:			/* Maximum receive unit -- always OK. */			continue;		default:			/* Others not supported. */			break;		}		/* Add the option to rejected list. */		memcpy(r, p, p[1]);		r += p[1];		rlen += p[1];	}	if (rlen)		sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);	kfree(buf);	return (rlen == 0);}static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb){	struct lcp_header *h;	struct net_device *dev = sp->pp_if;	int len = skb->len;	if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {		if (sp->pp_flags & PP_DEBUG)			printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",				dev->name,  len);		return;	}	h = (struct lcp_header *)skb->data;	skb_pull(skb,sizeof(struct lcp_header));	if (sp->pp_flags & PP_DEBUG) {		printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh",			dev->name,  len,			sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));		if (len > 4)			sppp_print_bytes ((u8*) (h+1), len-4);		printk (">\n");	}	if (len > ntohs (h->len))		len = ntohs (h->len);	switch (h->type) {	default:		/* Unknown packet type -- send Code-Reject packet. */		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);		break;	case IPCP_CONF_REQ:		if (len < 4) {			if (sp->pp_flags & PP_DEBUG)				printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n",					dev->name, len);			return;		}		if (len > 4) {			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,				len-4, h+1);			switch (sp->ipcp.state) {			case IPCP_STATE_OPENED:				/* Initiate renegotiation. */				sppp_ipcp_open (sp);				/* fall through... */			case IPCP_STATE_ACK_SENT:				/* Go to closed state. */				sp->ipcp.state = IPCP_STATE_CLOSED;			}		} else {			/* Send Configure-Ack packet. */			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,				0, NULL);			/* Change the state. */			if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)				sp->ipcp.state = IPCP_STATE_OPENED;			else				sp->ipcp.state = IPCP_STATE_ACK_SENT;		}		break;	case IPCP_CONF_ACK:		if (h->ident != sp->ipcp.confid)			break;		sppp_clear_timeout (sp);		switch (sp->ipcp.state) {		case IPCP_STATE_CLOSED:			sp->ipcp.state = IPCP_STATE_ACK_RCVD;			sppp_set_timeout (sp, 5);			break;		case IPCP_STATE_ACK_SENT:			sp->ipcp.state = IPCP_STATE_OPENED;			break;		}		break;	case IPCP_CONF_NAK:	case IPCP_CONF_REJ:		if (h->ident != sp->ipcp.confid)			break;		sppp_clear_timeout (sp);			/* Initiate renegotiation. */		sppp_ipcp_open (sp);		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)			/* Go to closed state. */			sp->ipcp.state = IPCP_STATE_CLOSED;		break;	case IPCP_TERM_REQ:		/* Send Terminate-Ack packet. */		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL);		/* Go to closed state. */		sp->ipcp.state = IPCP_STATE_CLOSED;		/* Initiate renegotiation. */		sppp_ipcp_open (sp);		break;	case IPCP_TERM_ACK:		/* Ignore for now. */	case IPCP_CODE_REJ:		/* Ignore for now. */		break;	}}static void sppp_lcp_open (struct sppp *sp){	char opt[6];	if (! sp->lcp.magic)		sp->lcp.magic = jiffies;	opt[0] = LCP_OPT_MAGIC;	opt[1] = sizeof (opt);	opt[2] = sp->lcp.magic >> 24;	opt[3] = sp->lcp.magic >> 16;	opt[4] = sp->lcp.magic >> 8;	opt[5] = sp->lcp.magic;	sp->lcp.confid = ++sp->pp_seq;	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,		sizeof (opt), &opt);	sppp_set_timeout (sp, 2);}static void sppp_ipcp_open (struct sppp *sp){	sp->ipcp.confid = ++sp->pp_seq;	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL);	sppp_set_timeout (sp, 2);}/* * Process PPP control protocol timeouts. */ static void sppp_cp_timeout (unsigned long arg){	struct sppp *sp = (struct sppp*) arg;	unsigned long flags;	spin_lock_irqsave(&sp->lock, flags);	sp->pp_flags &= ~PP_TIMO;	if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) {		spin_unlock_irqrestore(&sp->lock, flags);		return;	}	switch (sp->lcp.state) {	case LCP_STATE_CLOSED:		/* No ACK for Configure-Request, retry. */		sppp_lcp_open (sp);		break;	case LCP_STATE_ACK_RCVD:		/* ACK got, but no Configure-Request for peer, retry. */		sppp_lcp_open (sp);		sp->lcp.state = LCP_STATE_CLOSED;		break;	case LCP_STATE_ACK_SENT:		/* ACK sent but no ACK for Configure-Request, retry. */		sppp_lcp_open (sp);		break;	case LCP_STATE_OPENED:		/* LCP is already OK, try IPCP. */		switch (sp->ipcp.state) {		case IPCP_STATE_CLOSED:			/* No ACK for Configure-Request, retry. */			sppp_ipcp_open (sp);			break;		case IPCP_STATE_ACK_RCVD:			/* ACK got, but no Configure-Request for peer, retry. */			sppp_ipcp_open (sp);			sp->ipcp.state = IPCP_STATE_CLOSED;			break;		case IPCP_STATE_ACK_SENT:			/* ACK sent but no ACK for Configure-Request, retry. */			sppp_ipcp_open (sp);			break;		case IPCP_STATE_OPENED:			/* IPCP is OK. */			break;		}		break;	}	spin_unlock_irqrestore(&sp->lock, flags);	sppp_flush_xmit();}static char *sppp_lcp_type_name (u8 type){	static char buf [8];	switch (type) {	case LCP_CONF_REQ:   return ("conf-req");	case LCP_CONF_ACK:   return ("conf-ack");	case LCP_CONF_NAK:   return ("conf-nack");	case LCP_CONF_REJ:   return ("conf-rej");	case LCP_TERM_REQ:   return ("term-req");	case LCP_TERM_ACK:   return ("term-ack");	case LCP_CODE_REJ:   return ("code-rej");	case LCP_PROTO_REJ:  return ("proto-rej");	case LCP_ECHO_REQ:   return ("echo-req");	case LCP_ECHO_REPLY: return ("echo-reply");	case LCP_DISC_REQ:   return ("discard-req");	}	sprintf (buf, "%xh", type);	return (buf);}static char *sppp_ipcp_type_name (u8 type){	static char buf [8];	switch (type) {	case IPCP_CONF_REQ:   return ("conf-req");	case IPCP_CONF_ACK:   return ("conf-ack");	case IPCP_CONF_NAK:   return ("conf-nack");	case IPCP_CONF_REJ:   return ("conf-rej");	case IPCP_TERM_REQ:   return ("term-req");	case IPCP_TERM_ACK:   return ("term-ack");	case IPCP_CODE_REJ:   return ("code-rej");	}	sprintf (buf, "%xh", type);	return (buf);}static void sppp_print_bytes (u_char *p, u16 len){	printk (" %x", *p++);	while (--len > 0)		printk ("-%x", *p++);}/** *	sppp_rcv -	receive and process a WAN PPP frame *	@skb:	The buffer to process *	@dev:	The device it arrived on *	@p: Unused *	@orig_dev: Unused * *	Protocol glue. This drives the deferred processing mode the poorer *	cards use. This can be called directly by cards that do not have *	timing constraints but is normally called from the network layer *	after interrupt servicing to process frames queued via netif_rx. */static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev){	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)		return NET_RX_DROP;	sppp_input(dev,skb);	return 0;}static struct packet_type sppp_packet_type = {	.type	= __constant_htons(ETH_P_WAN_PPP),	.func	= sppp_rcv,};static char banner[] __initdata = 	KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"	KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "		  "Jan \"Yenya\" Kasprzak.\n";static int __init sync_ppp_init(void){	if(debug)		debug=PP_DEBUG;	printk(banner);	skb_queue_head_init(&tx_queue);	dev_add_pack(&sppp_packet_type);	return 0;}static void __exit sync_ppp_cleanup(void){	dev_remove_pack(&sppp_packet_type);}module_init(sync_ppp_init);module_exit(sync_ppp_cleanup);module_param(debug, int, 0);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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