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

📄 syncppp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	NET3:	A (fairly minimal) implementation of synchronous PPP for Linux *		as well as a CISCO HDLC implementation. See the copyright  *		message below for the original source. * *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License *	as published by the Free Software Foundation; either version *	2 of the license, or (at your option) any later version. * *	Note however. This code is also used in a different form by FreeBSD. *	Therefore when making any non OS specific change please consider *	contributing it back to the original author under the terms *	below in addition. *		-- Alan * *	Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz> *//* * Synchronous PPP/Cisco link level subroutines. * Keepalive protocol implemented in both Cisco and PPP modes. * * Copyright (C) 1994 Cronyx Ltd. * Author: Serge Vakulenko, <vak@zebub.msk.su> * * This software is distributed with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Authors grant any other persons or organisations permission to use * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * * Version 1.9, Wed Oct  4 18:58:15 MSK 1995 * * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $ */#undef DEBUG#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/if_arp.h>#include <linux/skbuff.h>#include <linux/route.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/random.h>#include <linux/pkt_sched.h>#include <linux/spinlock.h>#include <linux/rcupdate.h>#include <net/syncppp.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#define MAXALIVECNT     6               /* max. alive packets */#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */#define PPP_UI          0x03            /* Unnumbered Information */#define PPP_IP          0x0021          /* Internet Protocol */#define PPP_ISO         0x0023          /* ISO OSI Protocol */#define PPP_XNS         0x0025          /* Xerox NS Protocol */#define PPP_IPX         0x002b          /* Novell IPX Protocol */#define PPP_LCP         0xc021          /* Link Control Protocol */#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */#define LCP_CONF_REQ    1               /* PPP LCP configure request */#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */#define LCP_CONF_REJ    4               /* PPP LCP configure reject */#define LCP_TERM_REQ    5               /* PPP LCP terminate request */#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */#define LCP_CODE_REJ    7               /* PPP LCP code reject */#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */#define LCP_ECHO_REQ    9               /* PPP LCP echo request */#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */#define LCP_DISC_REQ    11              /* PPP LCP discard request */#define LCP_OPT_MRU             1       /* maximum receive unit */#define LCP_OPT_ASYNC_MAP       2       /* async control character map */#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */#define LCP_OPT_MAGIC           5       /* magic number */#define LCP_OPT_RESERVED        6       /* reserved */#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */#define CISCO_UNICAST           0x0f    /* Cisco unicast address */#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */#define CISCO_ADDR_REQ          0       /* Cisco address request */#define CISCO_ADDR_REPLY        1       /* Cisco address reply */#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */struct ppp_header {	u8 address;	u8 control;	u16 protocol;};#define PPP_HEADER_LEN          sizeof (struct ppp_header)struct lcp_header {	u8 type;	u8 ident;	u16 len;};#define LCP_HEADER_LEN          sizeof (struct lcp_header)struct cisco_packet {	u32 type;	u32 par1;	u32 par2;	u16 rel;	u16 time0;	u16 time1;};#define CISCO_PACKET_LEN 18#define CISCO_BIG_PACKET_LEN 20static struct sppp *spppq;static struct timer_list sppp_keepalive_timer;static DEFINE_SPINLOCK(spppq_lock);/* global xmit queue for sending packets while spinlock is held */static struct sk_buff_head tx_queue;static void sppp_keepalive (unsigned long dummy);static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,	u8 ident, u16 len, void *data);static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m);static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m);static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m);static void sppp_lcp_open (struct sppp *sp);static void sppp_ipcp_open (struct sppp *sp);static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,	int len, u32 *magic);static void sppp_cp_timeout (unsigned long arg);static char *sppp_lcp_type_name (u8 type);static char *sppp_ipcp_type_name (u8 type);static void sppp_print_bytes (u8 *p, u16 len);static int debug;/* Flush global outgoing packet queue to dev_queue_xmit(). * * dev_queue_xmit() must be called with interrupts enabled * which means it can't be called with spinlocks held. * If a packet needs to be sent while a spinlock is held, * then put the packet into tx_queue, and call sppp_flush_xmit() * after spinlock is released. */static void sppp_flush_xmit(void){	struct sk_buff *skb;	while ((skb = skb_dequeue(&tx_queue)) != NULL)		dev_queue_xmit(skb);}/* *	Interface down stub */	static void if_down(struct net_device *dev){	struct sppp *sp = (struct sppp *)sppp_of(dev);	sp->pp_link_state=SPPP_LINK_DOWN;}/* * Timeout routine activations. */static void sppp_set_timeout(struct sppp *p,int s) {	if (! (p->pp_flags & PP_TIMO)) 	{		init_timer(&p->pp_timer);		p->pp_timer.function=sppp_cp_timeout;		p->pp_timer.expires=jiffies+s*HZ;		p->pp_timer.data=(unsigned long)p;		p->pp_flags |= PP_TIMO;		add_timer(&p->pp_timer);	}}static void sppp_clear_timeout(struct sppp *p){	if (p->pp_flags & PP_TIMO) 	{		del_timer(&p->pp_timer);		p->pp_flags &= ~PP_TIMO; 	}}/** *	sppp_input -	receive and process a WAN PPP frame *	@skb:	The buffer to process *	@dev:	The device it arrived on * *	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(). * *	We process the options in the card. If the frame is destined for *	the protocol stacks then it requeues the frame for the upper level *	protocol. If it is a control from it is processed and discarded *	here. */ static void sppp_input (struct net_device *dev, struct sk_buff *skb){	struct ppp_header *h;	struct sppp *sp = (struct sppp *)sppp_of(dev);	unsigned long flags;	skb->dev=dev;	skb->mac.raw=skb->data;	if (dev->flags & IFF_RUNNING)	{		/* Count received bytes, add FCS and one flag */		sp->ibytes+= skb->len + 3;		sp->ipkts++;	}	if (!pskb_may_pull(skb, PPP_HEADER_LEN)) {		/* Too small packet, drop it. */		if (sp->pp_flags & PP_DEBUG)			printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",				dev->name, skb->len);		kfree_skb(skb);		return;	}	/* Get PPP header. */	h = (struct ppp_header *)skb->data;	skb_pull(skb,sizeof(struct ppp_header));	spin_lock_irqsave(&sp->lock, flags);		switch (h->address) {	default:        /* Invalid PPP packet. */		goto invalid;	case PPP_ALLSTATIONS:		if (h->control != PPP_UI)			goto invalid;		if (sp->pp_flags & PP_CISCO) {			if (sp->pp_flags & PP_DEBUG)				printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n",					dev->name,					h->address, h->control, ntohs (h->protocol));			goto drop;		}		switch (ntohs (h->protocol)) {		default:			if (sp->lcp.state == LCP_STATE_OPENED)				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,					++sp->pp_seq, skb->len + 2,					&h->protocol);			if (sp->pp_flags & PP_DEBUG)				printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n",					dev->name,					h->address, h->control, ntohs (h->protocol));			goto drop;		case PPP_LCP:			sppp_lcp_input (sp, skb);			goto drop;		case PPP_IPCP:			if (sp->lcp.state == LCP_STATE_OPENED)				sppp_ipcp_input (sp, skb);			else				printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n");			goto drop;		case PPP_IP:			if (sp->ipcp.state == IPCP_STATE_OPENED) {				if(sp->pp_flags&PP_DEBUG)					printk(KERN_DEBUG "Yow an IP frame.\n");				skb->protocol=htons(ETH_P_IP);				netif_rx(skb);				dev->last_rx = jiffies;				goto done;			}			break;#ifdef IPX		case PPP_IPX:			/* IPX IPXCP not implemented yet */			if (sp->lcp.state == LCP_STATE_OPENED) {				skb->protocol=htons(ETH_P_IPX);				netif_rx(skb);				dev->last_rx = jiffies;				goto done;			}			break;#endif		}		break;	case CISCO_MULTICAST:	case CISCO_UNICAST:		/* Don't check the control field here (RFC 1547). */		if (! (sp->pp_flags & PP_CISCO)) {			if (sp->pp_flags & PP_DEBUG)				printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n",					dev->name,					h->address, h->control, ntohs (h->protocol));			goto drop;		}		switch (ntohs (h->protocol)) {		default:			goto invalid;		case CISCO_KEEPALIVE:			sppp_cisco_input (sp, skb);			goto drop;#ifdef CONFIG_INET		case ETH_P_IP:			skb->protocol=htons(ETH_P_IP);			netif_rx(skb);			dev->last_rx = jiffies;			goto done;#endif#ifdef CONFIG_IPX		case ETH_P_IPX:			skb->protocol=htons(ETH_P_IPX);			netif_rx(skb);			dev->last_rx = jiffies;			goto done;#endif		}		break;	}	goto drop;invalid:	if (sp->pp_flags & PP_DEBUG)		printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n",			dev->name, h->address, h->control, ntohs (h->protocol));drop:	kfree_skb(skb);done:	spin_unlock_irqrestore(&sp->lock, flags);	sppp_flush_xmit();	return;}/* *	Handle transmit packets. */ static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,		void *daddr, void *saddr, unsigned int len){	struct sppp *sp = (struct sppp *)sppp_of(dev);	struct ppp_header *h;	skb_push(skb,sizeof(struct ppp_header));	h=(struct ppp_header *)skb->data;	if(sp->pp_flags&PP_CISCO)	{		h->address = CISCO_UNICAST;		h->control = 0;	}	else	{		h->address = PPP_ALLSTATIONS;		h->control = PPP_UI;	}	if(sp->pp_flags & PP_CISCO)	{		h->protocol = htons(type);	}	else switch(type)	{		case ETH_P_IP:			h->protocol = htons(PPP_IP);			break;		case ETH_P_IPX:			h->protocol = htons(PPP_IPX);			break;	}	return sizeof(struct ppp_header);}static int sppp_rebuild_header(struct sk_buff *skb){	return 0;}/* * Send keepalive packets, every 10 seconds. */static void sppp_keepalive (unsigned long dummy){	struct sppp *sp;	unsigned long flags;	spin_lock_irqsave(&spppq_lock, flags);	for (sp=spppq; sp; sp=sp->pp_next) 	{		struct net_device *dev = sp->pp_if;		/* Keepalive mode disabled or channel down? */		if (! (sp->pp_flags & PP_KEEPALIVE) ||		    ! (dev->flags & IFF_UP))			continue;		spin_lock(&sp->lock);		/* No keepalive in PPP mode if LCP not opened yet. */		if (! (sp->pp_flags & PP_CISCO) &&		    sp->lcp.state != LCP_STATE_OPENED) {			spin_unlock(&sp->lock);			continue;		}		if (sp->pp_alivecnt == MAXALIVECNT) {			/* No keepalive packets got.  Stop the interface. */			printk (KERN_WARNING "%s: protocol down\n", dev->name);			if_down (dev);			if (! (sp->pp_flags & PP_CISCO)) {				/* Shut down the PPP link. */				sp->lcp.magic = jiffies;				sp->lcp.state = LCP_STATE_CLOSED;				sp->ipcp.state = IPCP_STATE_CLOSED;				sppp_clear_timeout (sp);				/* Initiate negotiation. */				sppp_lcp_open (sp);			}		}		if (sp->pp_alivecnt <= MAXALIVECNT)			++sp->pp_alivecnt;		if (sp->pp_flags & PP_CISCO)			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,				sp->pp_rseq);		else if (sp->lcp.state == LCP_STATE_OPENED) {			long nmagic = htonl (sp->lcp.magic);			sp->lcp.echoid = ++sp->pp_seq;			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,				sp->lcp.echoid, 4, &nmagic);		}		spin_unlock(&sp->lock);	}	spin_unlock_irqrestore(&spppq_lock, flags);	sppp_flush_xmit();	sppp_keepalive_timer.expires=jiffies+10*HZ;	add_timer(&sppp_keepalive_timer);}/* * Handle incoming PPP Link Control Protocol packets. */ static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb){	struct lcp_header *h;	struct net_device *dev = sp->pp_if;	int len = skb->len;	u8 *p, opt[6];	u32 rmagic;	if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {		if (sp->pp_flags & PP_DEBUG)			printk (KERN_WARNING "%s: invalid lcp 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) 	{		char state = '?';		switch (sp->lcp.state) {		case LCP_STATE_CLOSED:   state = 'C'; break;		case LCP_STATE_ACK_RCVD: state = 'R'; break;		case LCP_STATE_ACK_SENT: state = 'S'; break;		case LCP_STATE_OPENED:   state = 'O'; break;		}		printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh",			dev->name, state, len,			sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));		if (len > 4)

⌨️ 快捷键说明

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