📄 mpc.c
字号:
#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 + -