summaryrefslogtreecommitdiff
path: root/drivers/net/bih/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bih/map.c')
-rw-r--r--drivers/net/bih/map.c351
1 files changed, 351 insertions, 0 deletions
diff --git a/drivers/net/bih/map.c b/drivers/net/bih/map.c
new file mode 100644
index 00000000..4f7a9097
--- /dev/null
+++ b/drivers/net/bih/map.c
@@ -0,0 +1,351 @@
+/*
+ * Bump in the Host (BIH)
+ * http://code.google.com/p/bump-in-the-host/source/
+ * ----------------------------------------------------------
+ *
+ * Copyrighted (C) 2010,2011 by the China Mobile Communications
+ * Corporation <bih.cmcc@gmail.com>;
+ * See the COPYRIGHT file for full details.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+#include "voslist.h"
+#include "map.h"
+#define TIMEOUTSEC 60
+#define MAP_ARRAY_NUM 13
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+
+#define BIH_DEBUG printk
+struct map_node *map_array[MAP_ARRAY_NUM];
+struct timer_list map_timer;
+unsigned long map_timeout=1800;
+DEFINE_SPINLOCK(map_lock);
+
+int map_init(void);
+int map_uninit(void);
+int map_timeout_func(void);
+struct map_node *map_find(struct in6_addr in6addr);
+struct map_node *map_search(unsigned int id);
+struct map_node *map_new(unsigned int id);
+struct map_node *map_add(unsigned int in4addr,struct in6_addr in6addr);
+int map_del(unsigned int id);
+int map_free(struct map_node *node);
+void map_shownode(struct map_node *node);
+int map_show(unsigned int id);
+char *map_showrun(void);
+int map_timeout_set(unsigned int secs);
+
+/*
+ Initiate the map-node, and set a timer for the node;
+ when the node is expired, call map_timeout_func().
+*/
+int map_init(void)
+{
+ init_timer(&map_timer);
+ map_timer.data = 0;
+ map_timer.function = (void (*)(unsigned long))map_timeout_func;
+ map_timer.expires = jiffies + TIMEOUTSEC*HZ;
+ add_timer(&map_timer);
+ return(0);
+}
+
+/*
+ Delete the timer named map_timer, and destroy the timer's mapping relationship.
+*/
+int map_uninit(void)
+{
+ del_timer(&map_timer);
+ map_free(NULL);
+ return(0);
+}
+
+/*
+ Check the map_array[] array, and call map_free() to delete the node which is expired(30 minutes).
+*/
+int map_timeout_func(void)
+{
+ int i;
+ unsigned long now;
+ struct map_node *node,*delnode;
+
+ now=jiffies;
+ map_timer.expires = jiffies + TIMEOUTSEC*HZ;
+ add_timer(&map_timer);
+// spin_lock_bh(&map_lock);
+ for(i=0;i<MAP_ARRAY_NUM;i++)
+ {
+ for(node=map_array[i];node;)
+ {
+ delnode=node;
+ node=node->next;
+ if(time_after(now,delnode->last_time+HZ*map_timeout))
+ {
+ map_free(delnode);
+ }
+ }
+ }
+// spin_unlock_bh(&map_lock);
+ return(0);
+}
+
+/*
+ Check the node in the whole map_array[] array with 'in6_addr',
+ if there is an appropriate result, return the node,
+ otherwise, return NULL.
+*/
+struct map_node *map_find(struct in6_addr in6addr)
+{
+ int i;
+ struct map_node *node;
+
+ for(i=0;i<MAP_ARRAY_NUM;i++)
+ {
+ for(node=map_array[i];node;node=node->next)
+ {
+ if(memcmp(&in6addr,&(node->in6addr),sizeof(struct in6_addr))==0)
+ {
+ node->last_time=jiffies;
+ return(node);
+ }
+ }
+ }
+ return(NULL);
+}
+
+/*
+ Check the linked list with 'id',
+ if there is an appropriate result, set the 'last_time' as jiffies, and return the node.
+*/
+struct map_node *map_search(unsigned int id)
+{
+ struct map_node *node;
+ node=(struct map_node *)listnode_find((struct listnode *)map_array[id%MAP_ARRAY_NUM],id);
+ if(node)
+ node->last_time=jiffies;
+ return(node);
+}
+
+/*
+ Insert a map_node into the map with a certain id,
+ if there is a node with this id already exists in the map, set the node's 'last_time' as jiffies and return the node,
+ otherwise, make a new map_node, and insert this new node into the linked list.
+*/
+struct map_node *map_new(unsigned int id)
+{
+ struct map_node *node;
+
+ if(id==0)
+ {
+ BIH_DEBUG("bih: map_new argument error\n");
+ lprintf(0,"argument error\n");
+ return(NULL);
+ }
+ node=map_search(id);
+ if(node)
+ {
+ return(node);
+ }
+ node=(struct map_node *)vmalloc(sizeof(struct map_node));
+ if(node==NULL)
+ {
+ BIH_DEBUG("bih: map_new vmalloc error\n");
+ lprintf(0,"vmalloc error\n");
+ return(NULL);
+ }
+ memset(node,0,sizeof(struct map_node));
+ node->id=id;
+ node->start_time=jiffies;
+ node->last_time=node->start_time;
+ spin_lock_bh(&map_lock);
+ if(listnode_insert((struct listnode **)&(map_array[id%MAP_ARRAY_NUM]),(struct listnode *)node))
+ {
+ spin_unlock_bh(&map_lock);
+ vfree(node);
+ BIH_DEBUG("bih: map_new listnode_insert error\n");
+ lprintf(0,"listnode_insert error\n");
+ return(NULL);
+ }
+ spin_unlock_bh(&map_lock);
+ return(node);
+}
+
+/*
+ Insert or upgrade the IPv6 address,
+ find the node with 'id' or 'key', and then make a new mapping relationship.
+*/
+struct map_node *map_add(unsigned int in4addr,struct in6_addr in6addr)
+{
+ struct map_node *node;
+ if(in4addr==0)
+ {
+ BIH_DEBUG("bih: map_add argument error\n");
+ lprintf(0,"argument error\n");
+ return(NULL);
+ }
+ node=map_search(in4addr);
+ if(node==NULL)
+ node=map_new(in4addr);
+ memcpy(&(node->in6addr), &in6addr, sizeof(struct in6_addr));
+ node->last_time=jiffies;
+ return(node);
+}
+
+/*
+ Call the map_free() to delete the certain node with 'id',
+ or, clear the whole map_array[].
+*/
+int map_del(unsigned int id)
+{
+ struct map_node *node;
+ node=map_search(id);
+ if(node)
+ {
+ map_free(node);
+ }
+ return(0);
+}
+
+/*
+ Called by the map_del().
+*/
+int map_free(struct map_node *node)
+{
+ unsigned long now;
+ char buff[64];
+ now=jiffies;
+ if(node==NULL)
+ {
+ int i;
+ struct map_node *delnode;
+ for(i=0;i<MAP_ARRAY_NUM;i++)
+ {
+ for(node=map_array[i];node;)
+ {
+ delnode=node;
+ node=node->next;
+ map_free(delnode);
+ }
+ }
+ }
+ else
+ {
+ inet_ntop6((unsigned char *)&(node->in6addr), buff, sizeof(buff)-1);
+ lprintf(1,"MAP: (%u.%u.%u.%u-%s) timeout: used(%lu) unused(%lu)\n",
+ NIPQUAD(node->id),buff,(now-node->start_time)/HZ,(now-node->last_time)/HZ);
+ spin_lock_bh(&map_lock);
+ listnode_uninsert((struct listnode **)&(map_array[node->id%MAP_ARRAY_NUM]),(struct listnode *)node);
+ vfree(node);
+ spin_unlock_bh(&map_lock);
+ }
+ return(0);
+}
+
+/*
+ Called by the map_show() and print the information of a certain map_node.
+*/
+void map_shownode(struct map_node *node)
+{
+ unsigned long now;
+ char buff[64];
+ if(node==NULL)
+ return;
+ now=jiffies;
+ inet_ntop6((unsigned char *)&(node->in6addr), buff, sizeof(buff)-1);
+ BIH_DEBUG("bih: %u.%u.%u.%u-%s : used(%lu) unused(%lu)\n",
+ NIPQUAD(node->id),buff,(now-node->start_time)/HZ,(now-node->last_time)/HZ);
+ lprintf(5,"%u.%u.%u.%u-%s : used(%lu) unused(%lu)\n",
+ NIPQUAD(node->id),buff,(now-node->start_time)/HZ,(now-node->last_time)/HZ);
+ return;
+}
+
+/*
+ Print the information of a certain node or all the nodes.
+*/
+int map_show(unsigned int id)
+{
+ struct map_node *node;
+ if(id==0)
+ {
+ int i;
+ lprintf(5,"==================== MAP TABLE ====================\n");
+ for(i=0;i<MAP_ARRAY_NUM;i++)
+ {
+ for(node=map_array[i];node;node=node->next)
+ {
+ map_shownode(node);
+ }
+ }
+ }
+ else
+ {
+ node=map_search(id);
+ if(node==NULL)
+ {
+ lprintf(0,"id(%u.%u.%u.%u) error\n",NIPQUAD(id));
+ return(-1);
+ }
+ map_shownode(node);
+ }
+ return(0);
+}
+
+/*
+ Print the infomation of mapping-address,
+ such as the time used and left.
+*/
+char *map_showrun(void)
+{
+ int i;
+ struct map_node *node;
+ unsigned long now=jiffies;
+ char strbuff[64];
+ SHOW2BUF_DEF;
+ SHOW2BUF_INIT();
+ spin_lock_bh(&map_lock);
+ for(i=0;i<MAP_ARRAY_NUM;i++)
+ {
+ for(node=map_array[i];node;node=node->next)
+ {
+ inet_ntop6((unsigned char *)&(node->in6addr), strbuff, sizeof(strbuff)-1);
+ SHOW2BUF("[%d]: %u.%u.%u.%u-%s : used(%lu) unused(%lu)\n",
+ i,NIPQUAD(node->id),strbuff,(now-node->start_time)/HZ,(now-node->last_time)/HZ);
+ }
+ }
+ spin_unlock_bh(&map_lock);
+ SHOW2BUF_RET;
+}
+
+int map_timeout_set(unsigned int secs)
+{
+ map_timeout=secs;
+ return(0);
+}