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

📄 mpc.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/init.h>#include <linux/bitops.h>/* We are an ethernet device */#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <net/sock.h>#include <linux/skbuff.h>#include <linux/ip.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#include <asm/checksum.h>   /* for ip_fast_csum() */#include <net/arp.h>#include <net/dst.h>#include <linux/proc_fs.h>/* And atm device */#include <linux/atmdev.h>#include <linux/atmlec.h>#include <linux/atmmpc.h>/* Modular too */#include <linux/config.h>#include <linux/module.h>#include "lec.h"#include "mpc.h"#include "resources.h"  /* for bind_vcc() *//* * mpc.c: Implementation of MPOA client kernel part  */#if 0#define dprintk printk   /* debug */#else#define dprintk(format,args...)#endif#if 0#define ddprintk printk  /* more debug */#else#define ddprintk(format,args...)#endif#define MPOA_TAG_LEN 4/* mpc_daemon -> kernel */static void MPOA_trigger_rcvd (struct k_message *msg, struct mpoa_client *mpc);static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc);static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc);static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc);static void mps_death(struct k_message *msg, struct mpoa_client *mpc);static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action);static void MPOA_cache_impos_rcvd(struct k_message *msg, struct mpoa_client *mpc);static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc);static void set_mps_mac_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc);static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac,			  uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type);static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry);static void send_set_mps_ctrl_addr(char *addr, struct mpoa_client *mpc);static void mpoad_close(struct atm_vcc *vcc);static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb);static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb);static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev);static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev);static void mpc_timer_refresh(void);static void mpc_cache_check( unsigned long checking_time  );static struct llc_snap_hdr llc_snap_mpoa_ctrl = {	0xaa, 0xaa, 0x03,	{0x00, 0x00, 0x5e},	{0x00, 0x03}         /* For MPOA control PDUs */};        static struct llc_snap_hdr llc_snap_mpoa_data = {	0xaa, 0xaa, 0x03,	{0x00, 0x00, 0x00},	{0x08, 0x00}         /* This is for IP PDUs only */};        static struct llc_snap_hdr llc_snap_mpoa_data_tagged = {	0xaa, 0xaa, 0x03,	{0x00, 0x00, 0x00},	{0x88, 0x4c}         /* This is for tagged data PDUs */};        static struct notifier_block mpoa_notifier = {	mpoa_event_listener,	NULL,	0};#ifdef CONFIG_PROC_FSextern int mpc_proc_init(void);extern void mpc_proc_clean(void);#endifstruct mpoa_client *mpcs = NULL; /* FIXME */static struct atm_mpoa_qos *qos_head = NULL;static struct timer_list mpc_timer;static struct mpoa_client *find_mpc_by_itfnum(int itf){	struct mpoa_client *mpc;		mpc = mpcs;  /* our global linked list */	while (mpc != NULL) {		if (mpc->dev_num == itf)			return mpc;		mpc = mpc->next;    	}	return NULL;   /* not found */}static struct mpoa_client *find_mpc_by_vcc(struct atm_vcc *vcc){	struct mpoa_client *mpc;		mpc = mpcs;  /* our global linked list */	while (mpc != NULL) {		if (mpc->mpoad_vcc == vcc)			return mpc;		mpc = mpc->next;	}	return NULL;   /* not found */}static struct mpoa_client *find_mpc_by_lec(struct net_device *dev){	struct mpoa_client *mpc;		mpc = mpcs;  /* our global linked list */	while (mpc != NULL) {		if (mpc->dev == dev)			return mpc;		mpc = mpc->next;	}	return NULL;   /* not found */}/* * Functions for managing QoS list *//* * Overwrites the old entry or makes a new one. */struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos){	struct atm_mpoa_qos *entry;	entry = atm_mpoa_search_qos(dst_ip);	if (entry != NULL) {		entry->qos = *qos;		return entry;	}	entry = kmalloc(sizeof(struct atm_mpoa_qos), GFP_KERNEL);	if (entry == NULL) {		printk("mpoa: atm_mpoa_add_qos: out of memory\n");		return entry;	}	entry->ipaddr = dst_ip;	entry->qos = *qos;	entry->next = qos_head;	qos_head = entry;	return entry;}struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip){	struct atm_mpoa_qos *qos;	qos = qos_head;	while( qos != NULL ){		if(qos->ipaddr == dst_ip) {			break;		}		qos = qos->next;	}	return qos;}        /* * Returns 0 for failure */int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry){	struct atm_mpoa_qos *curr;	if (entry == NULL) return 0;	if (entry == qos_head) {		qos_head = qos_head->next;		kfree(entry);		return 1;	}	curr = qos_head;	while (curr != NULL) {		if (curr->next == entry) {			curr->next = entry->next;			kfree(entry);			return 1;		}		curr = curr->next;	}	return 0;}void atm_mpoa_disp_qos(char *page, int *len){	unsigned char *ip;	char ipaddr[16];	struct atm_mpoa_qos *qos;	qos = qos_head;	*len += sprintf(page + *len, "QoS entries for shortcuts:\n");	*len += sprintf(page + *len, "IP address\n  TX:max_pcr pcr     min_pcr max_cdv max_sdu\n  RX:max_pcr pcr     min_pcr max_cdv max_sdu\n");	ipaddr[sizeof(ipaddr)-1] = '\0';	while (qos != NULL) {		ip = (unsigned char *)&qos->ipaddr;		sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(ip));		*len += sprintf(page + *len, "%u.%u.%u.%u\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",				NIPQUAD(ipaddr),				qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu,				qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu);		qos = qos->next;	}		return;}static struct net_device *find_lec_by_itfnum(int itf){	extern struct atm_lane_ops atm_lane_ops; /* in common.c */		if (atm_lane_ops.get_lecs == NULL)		return NULL;	return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */}static struct mpoa_client *alloc_mpc(void){	struct mpoa_client *mpc;	mpc = kmalloc(sizeof (struct mpoa_client), GFP_KERNEL);	if (mpc == NULL)		return NULL;	memset(mpc, 0, sizeof(struct mpoa_client));	mpc->ingress_lock = RW_LOCK_UNLOCKED;	mpc->egress_lock  = RW_LOCK_UNLOCKED;	mpc->next = mpcs;	atm_mpoa_init_cache(mpc);	mpc->parameters.mpc_p1 = MPC_P1;	mpc->parameters.mpc_p2 = MPC_P2;	memset(mpc->parameters.mpc_p3,0,sizeof(mpc->parameters.mpc_p3));	mpc->parameters.mpc_p4 = MPC_P4;	mpc->parameters.mpc_p5 = MPC_P5; 	mpc->parameters.mpc_p6 = MPC_P6;		mpcs = mpc;		return mpc;}/* * * start_mpc() puts the MPC on line. All the packets destined * to the lec underneath us are now being monitored and  * shortcuts will be established. * */static void start_mpc(struct mpoa_client *mpc, struct net_device *dev){		dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name); 	if (dev->hard_start_xmit == NULL) {		printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n",		       dev->name);		return;	}	mpc->old_hard_start_xmit = dev->hard_start_xmit;	dev->hard_start_xmit = mpc_send_packet;	return;}static void stop_mpc(struct mpoa_client *mpc){		dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name); 	/* Lets not nullify lec device's dev->hard_start_xmit */	if (mpc->dev->hard_start_xmit != mpc_send_packet) {		dprintk(" mpc already stopped, not fatal\n");		return;	}	dprintk("\n");	mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit;	mpc->old_hard_start_xmit = NULL;	/* close_shortcuts(mpc);    ??? FIXME */		return;}static const char * __attribute__ ((unused)) mpoa_device_type_string(char type){	switch(type) {	case NON_MPOA:		return "non-MPOA device";		break;	case MPS:		return "MPS";		break;	case MPC:		return "MPC";		break;	case MPS_AND_MPC:		return "both MPS and MPC";		break;	default:		return "unspecified (non-MPOA) device";		break;	}	return ""; /* not reached */}/* * lec device calls this via its dev->priv->lane2_ops->associate_indicator() * when it sees a TLV in LE_ARP packet. * We fill in the pointer above when we see a LANE2 lec initializing * See LANE2 spec 3.1.5 * * Quite a big and ugly function but when you look at it * all it does is to try to locate and parse MPOA Device * Type TLV. * We give our lec a pointer to this function and when the * lec sees a TLV it uses the pointer to call this function. * */static void lane2_assoc_ind(struct net_device *dev, uint8_t *mac_addr,			    uint8_t *tlvs, uint32_t sizeoftlvs){	uint32_t type;	uint8_t length, mpoa_device_type, number_of_mps_macs;	uint8_t *end_of_tlvs;	struct mpoa_client *mpc;		mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */	dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name);	dprintk("total length of all TLVs %d\n", sizeoftlvs);	mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */	if (mpc == NULL) {		printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name);		return;	}	end_of_tlvs = tlvs + sizeoftlvs;	while (end_of_tlvs - tlvs >= 5) {		type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3];		length = tlvs[4];		tlvs += 5;		dprintk("    type 0x%x length %02x\n", type, length);		if (tlvs + length > end_of_tlvs) {			printk("TLV value extends past its buffer, aborting parse\n");			return;		}				if (type == 0) {			printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name);			return;		}		if (type != TLV_MPOA_DEVICE_TYPE) {			tlvs += length;			continue;  /* skip other TLVs */		}		mpoa_device_type = *tlvs++;		number_of_mps_macs = *tlvs++;		dprintk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type));		if (mpoa_device_type == MPS_AND_MPC &&		    length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */			printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",			       dev->name);			continue;		}		if ((mpoa_device_type == MPS || mpoa_device_type == MPC)		    && length < 22 + number_of_mps_macs*ETH_ALEN) {			printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",				dev->name);			continue;		}		if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) {			dprintk("ignoring non-MPS device\n");			if (mpoa_device_type == MPC) tlvs += 20;			continue;  /* we are only interested in MPSs */		}		if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) {			printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name);			continue;  /* someone should read the spec */		}		dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs);				/* ok, now we can go and tell our daemon the control address of MPS */		send_set_mps_ctrl_addr(tlvs, mpc);				tlvs = copy_macs(mpc, mac_addr, tlvs, number_of_mps_macs, mpoa_device_type);		if (tlvs == NULL) return;	}	if (end_of_tlvs - tlvs != 0)		printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n",		       dev->name, end_of_tlvs - tlvs);	return;}/* * Store at least advertizing router's MAC address * plus the possible MAC address(es) to mpc->mps_macs. * For a freshly allocated MPOA client mpc->mps_macs == 0. */static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac,			  uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type){	int num_macs;	num_macs = (mps_macs > 1) ? mps_macs : 1;	if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */		if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs);		mpc->number_of_mps_macs = 0;		mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL);		if (mpc->mps_macs == NULL) {			printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name);			return NULL;		}	}	memcpy(mpc->mps_macs, router_mac, ETH_ALEN);	tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20;	if (mps_macs > 0)		memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN);	tlvs += mps_macs*ETH_ALEN;	mpc->number_of_mps_macs = num_macs;	return tlvs;}static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc){	in_cache_entry *entry;	struct iphdr *iph;	char *buff;	uint32_t ipaddr = 0;	static struct {		struct llc_snap_hdr hdr;		uint32_t tag;	} tagged_llc_snap_hdr = {		{0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}},		0	};	buff = skb->data + mpc->dev->hard_header_len;	iph = (struct iphdr *)buff;	ipaddr = iph->daddr;	ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr);        	entry = mpc->in_ops->get(ipaddr, mpc);	if (entry == NULL) {		entry = mpc->in_ops->add_entry(ipaddr, mpc);		if (entry != NULL) mpc->in_ops->put(entry);		return 1;	}	if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){   /* threshold not exceeded or VCC not ready */

⌨️ 快捷键说明

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