summaryrefslogtreecommitdiff
path: root/drivers/net/bih
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bih')
-rw-r--r--drivers/net/bih/Kconfig9
-rw-r--r--drivers/net/bih/Makefile3
-rw-r--r--drivers/net/bih/bih_module.c1068
-rw-r--r--drivers/net/bih/config.sh34
-rw-r--r--drivers/net/bih/map.c351
-rw-r--r--drivers/net/bih/map.h50
-rw-r--r--drivers/net/bih/pool.c283
-rw-r--r--drivers/net/bih/pool.h34
-rw-r--r--drivers/net/bih/translate.c1585
-rw-r--r--drivers/net/bih/translate.h176
-rw-r--r--drivers/net/bih/voslist.c835
-rw-r--r--drivers/net/bih/voslist.h249
12 files changed, 4677 insertions, 0 deletions
diff --git a/drivers/net/bih/Kconfig b/drivers/net/bih/Kconfig
new file mode 100644
index 00000000..d75ded32
--- /dev/null
+++ b/drivers/net/bih/Kconfig
@@ -0,0 +1,9 @@
+config BIH
+ tristate "Bump-in-the-stack"
+ depends on NET || IPV6 || IPV4
+ help
+ This driver supports BIH based on Copyright 2010, 2011 China
+ Mobile Communications Corporation, Inc. ("CMCC")
+
+ To compile this driver as a module, choose M here. The module
+ will be called sfc.
diff --git a/drivers/net/bih/Makefile b/drivers/net/bih/Makefile
new file mode 100644
index 00000000..84517b60
--- /dev/null
+++ b/drivers/net/bih/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_BIH) += bih.o
+bih-objs := translate.o bih_module.o voslist.o pool.o map.o
diff --git a/drivers/net/bih/bih_module.c b/drivers/net/bih/bih_module.c
new file mode 100644
index 00000000..e4ff51cd
--- /dev/null
+++ b/drivers/net/bih/bih_module.c
@@ -0,0 +1,1068 @@
+/*
+ * 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; 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.
+ *
+ */
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/kernel.h> /* Needed for KERN_ALERT */
+#include <linux/init.h> /* Needed for the macros */
+#include <linux/list.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+#include <linux/proc_fs.h> /* Necessary because we use proc fs */
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/nsproxy.h>
+#include <net/route.h>
+#include <net/ip6_route.h>
+#include <net/ip_fib.h>
+#include <net/ip6_fib.h>
+#include <net/flow.h>
+#include <net/addrconf.h>
+#include <asm/uaccess.h> /* for get_user and put_user */
+#include "translate.h"
+#include "voslist.h"
+#include "pool.h"
+#include "map.h"
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+#define BIH_OPS_BASIC 128
+#define BIH_SET BIH_OPS_BASIC
+#define BIH_GET BIH_OPS_BASIC
+#define BIH_MAX BIH_OPS_BASIC+1
+#define MODULE_NAME "bih"
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ZHAODAYI");
+MODULE_DESCRIPTION("BIH");
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+extern int BIHMODE,NETWORKTYPE;
+extern unsigned int PRIVATEADDR;
+extern char *inet_ntop6(unsigned char *src, char *dst, size_t size);
+extern int inet_pton6(char *src,unsigned char *dst);
+extern int bih_xmit(struct sk_buff *skb,struct net_device *dev);
+static struct proc_dir_entry *proc_dir=NULL,*proc_file_bis,*proc_file_mode,*proc_file_pool,*proc_file_map,*proc_file_network,*proc_file_private;
+struct net_device *bihdev=NULL;
+
+#define RT_OPS_BASIC 130
+#define RT_QUERY RT_OPS_BASIC
+#define SP_QUERY RT_OPS_BASIC+1
+#define RT_MAX RT_OPS_BASIC+2
+
+#ifndef CONFIG_IP_MULTIPLE_TABLES
+struct fib_table *dev_fib_get_table(struct net *net, u32 id)
+{
+ struct hlist_head *ptr;
+
+ ptr = id == RT_TABLE_LOCAL ?
+ &net->ipv4.fib_table_hash[0] :
+ &net->ipv4.fib_table_hash[1];
+ return hlist_entry(ptr->first, struct fib_table, tb_hlist);
+}
+
+int dev_fib_lookup(struct flowi *flp,struct fib_result *res)
+{
+ struct fib_table *table;
+ struct net *net=&init_net;
+ table = dev_fib_get_table(net, RT_TABLE_LOCAL);
+ if (!table->tb_lookup(table, flp, res))
+ return 0;
+
+ table = dev_fib_get_table(net, RT_TABLE_MAIN);
+ if (!table->tb_lookup(table, flp, res))
+ return 0;
+ return -ENETUNREACH;
+}
+#else
+struct fib_table *dev_fib_get_table(struct net *net, u32 id)
+{
+ struct fib_table *tb;
+ struct hlist_head *head;
+ unsigned int h;
+
+ if (id == 0)
+ id = RT_TABLE_MAIN;
+ h = id & (FIB_TABLE_HASHSZ - 1);
+
+ rcu_read_lock();
+ head = &net->ipv4.fib_table_hash[h];
+ hlist_for_each_entry_rcu(tb, head, tb_hlist) {
+ if (tb->tb_id == id) {
+ rcu_read_unlock();
+ return tb;
+ }
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+
+int dev_fib_lookup(struct flowi *flp, struct fib_result *res)
+{
+ struct fib_lookup_arg arg = {
+ .result = res,
+ };
+ struct net *net=&init_net;
+ int err;
+
+ err = fib_rules_lookup(net->ipv4.rules_ops, flp, 0, &arg);
+#ifdef CONFIG_IP_ROUTE_CLASSID
+ if (arg.rule)
+ res->tclassid = ((struct fib4_rule *)arg.rule)->tclassid;
+ else
+ res->tclassid = 0;
+#endif
+ return err;
+}
+#endif
+
+int dev_get_addr6(struct net_device *dev, struct in6_addr *addr)
+{
+ struct inet6_dev *idev;
+ int err = -EADDRNOTAVAIL;
+
+ if ((idev = __in6_dev_get(dev)) != NULL) {
+ struct inet6_ifaddr *ifp;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifp, &idev->addr_list, if_list){
+ if (ifp->scope != IFA_LINK/* && !(ifp->flags&IFA_F_TENTATIVE)*/)
+ {
+ //ipv6_addr_copy(addr, &ifp->addr);
+ *addr = ifp->addr;
+ err = 0;
+ break;
+ }
+ }
+ read_unlock_bh(&idev->lock);
+ }
+ return err;
+}
+
+int dev_get_addr(struct net_device *dev, unsigned int *addr)
+{
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa = NULL;
+
+ if ((in_dev = __in_dev_get_rtnl(dev)) != NULL)
+ {
+ for(ifa=in_dev->ifa_list;ifa!=NULL;ifa=ifa->ifa_next)
+ {
+ if(ifa->ifa_local!=0)
+ {
+ *addr=ifa->ifa_local;
+ return(0);
+ }
+ }
+ }
+ return(-1);
+}
+
+char *ipaddr_show(unsigned char *addr,int len)
+{
+ static char strbuf[128];
+ if(len==4)
+ inet_ntop4(addr,strbuf,sizeof(strbuf)-1);
+ else if(len==16)
+ inet_ntop6(addr,strbuf,sizeof(strbuf)-1);
+ else
+ return(NULL);
+ return(strbuf);
+}
+
+static int rt_query(struct sock *sk, int cmd, void *user, int *len)
+{
+ switch(cmd)
+ {
+ case RT_QUERY:
+ {
+ struct
+ {
+ unsigned char dst[16];
+ unsigned char src[16];
+ unsigned char gw[16];
+ char dev[32];
+ }argu;
+ struct flowi fl;
+ struct fib_result res;
+ struct net_device *dev = NULL;
+ struct rtable *rp;
+ int ret;
+ memset(&argu,0,sizeof(argu));
+ memset(&fl,0,sizeof(fl));
+ memset(&res,0,sizeof(res));
+ memset(&rp,0,sizeof(rp));
+ copy_from_user(&argu, user, sizeof(argu));
+ if(memcmp(argu.dst+4,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",12)==0)
+ {
+ unsigned int addr;
+ memcpy(&addr,argu.dst,4);
+ fl.u.ip4.daddr=addr;
+/*
+ rp = __ip_route_output_key(current->nsproxy->net_ns, &fl.u.ip4);
+ if (IS_ERR(rp))
+ return PTR_ERR(rp);
+
+ if(ret==0)
+ {
+ ip_rt_put(rp);
+ addr=rp->rt_src;
+ memset(argu.src,0,sizeof(argu.src));
+ memcpy(argu.src,&addr,4);
+ copy_to_user(user,&argu, sizeof(argu));
+ }
+*/
+ ret=dev_fib_lookup(&fl, &res);
+ if(ret==0)
+ {
+ dev = FIB_RES_DEV(res);
+ strncpy(argu.dev,dev->name,sizeof(argu.dev)-1);
+ dev_get_addr(dev,&addr);
+ memset(argu.src,0,sizeof(argu.src));
+ memcpy(argu.src,&addr,4);
+ addr=FIB_RES_GW(res);
+ memcpy(argu.gw,&addr,4);
+ copy_to_user(user,&argu, sizeof(argu));
+ return(0);
+ }
+ }
+ else
+ {
+ //struct fib6_table *tb=fib6_get_table(&init_net,RT6_TABLE_MAIN);
+ struct rt6_info *rt;
+ rt = rt6_lookup(&init_net, (const struct in6_addr *)argu.dst, NULL, 0, 1);
+ if(rt)
+ {
+ //dev = rt->rt6i_dev;
+ dev = rt->dst.dev;
+ dst_release(&rt->dst);
+ strncpy(argu.dev,dev->name,sizeof(argu.dev)-1);
+ dev_get_addr6(dev,(struct in6_addr *)argu.src);
+ memcpy(argu.gw,rt->rt6i_gateway.s6_addr,16);
+ copy_to_user(user,&argu, sizeof(argu));
+ return(0);
+ }
+ }
+ break;
+ }
+ case SP_QUERY:
+ {
+ struct
+ {
+ unsigned char dst[16];
+ unsigned char src[16];
+ unsigned char gw[16];
+ char dev[32];
+ }argu;
+ struct flowi fl;
+ struct fib_result res;
+ struct net_device *dev = NULL;
+ struct rtable *rp=NULL;
+ int ret;
+ memset(&argu,0,sizeof(argu));
+ memset(&fl,0,sizeof(fl));
+ memset(&res,0,sizeof(res));
+ memset(&rp,0,sizeof(rp));
+ copy_from_user(&argu, user, sizeof(argu));
+ if(memcmp(argu.dst+4,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",12)==0)
+ {
+ unsigned int addr;
+ memcpy(&addr,argu.dst,4);
+ fl.u.ip4.daddr=addr;
+ rp = __ip_route_output_key(current->nsproxy->net_ns, &fl.u.ip4);
+ if (IS_ERR(rp))
+ return PTR_ERR(rp);
+ /*
+ if (!fl.u.ip4.saddr)
+ fl.u.ip4.saddr = rp->rt_src;
+ if (!fl.u.ip4.daddr)
+ fl.u.ip4.daddr = rp->rt_dst;
+ */
+ ret = xfrm_lookup(&init_net,(struct dst_entry **)&rp, &fl, NULL,0);
+ if(ret==-EREMOTE)
+ {
+ dev=dev_get_by_index(&init_net, rp->rt_iif);
+ if(dev)
+ strncpy(argu.dev,dev->name,sizeof(argu.dev)-1);
+ /*
+ addr=rp->rt_src;
+ */
+ addr=fl.u.ip4.saddr;
+ memset(argu.src,0,sizeof(argu.src));
+ memcpy(argu.src,&addr,4);
+ addr=rp->rt_gateway;
+ memcpy(argu.gw,&addr,4);
+ ip_rt_put(rp);
+ copy_to_user(user,&argu, sizeof(argu));
+ return(0);
+ }
+ }
+ else
+ {
+ struct rt6_info *rt;
+ rt = rt6_lookup(&init_net, (const struct in6_addr *)argu.dst, NULL, 0, 1);
+ if(rt)
+ {
+ dev = rt->dst.dev;
+ //dev = rt->rt6i_dev;
+ dev_get_addr6(dev,(struct in6_addr *)argu.src);
+ memcpy(&fl.u.ip6.daddr,argu.dst,16);
+ memcpy(&fl.u.ip6.saddr,argu.src,16);
+ ret = xfrm_lookup(&init_net,(struct dst_entry **)&rt, &fl, NULL,0);
+ if(ret==-EREMOTE)
+ {
+ dev = rt->dst.dev;
+ //dev = rt->rt6i_dev;
+ dst_release(&rt->dst);
+ strncpy(argu.dev,dev->name,sizeof(argu.dev)-1);
+ dev_get_addr6(dev,(struct in6_addr *)argu.src);
+ memcpy(argu.gw,rt->rt6i_gateway.s6_addr,16);
+ copy_to_user(user,&argu, sizeof(argu));
+ return(0);
+ }
+ }
+ }
+ break;
+ }
+ }
+ return -1;
+}
+
+static struct nf_sockopt_ops rt_sockops =
+{
+ .pf = PF_INET,
+ .get_optmin = RT_QUERY,
+ .get_optmax = RT_MAX,
+ .get = rt_query,
+};
+
+static int data_to_kernel(struct sock *sk, int cmd, void *user,unsigned int len)
+{
+ switch(cmd)
+ {
+ case BIH_SET:
+ {
+ char umsg[64];
+ memset(umsg, 0, sizeof(char)*64);
+ copy_from_user(umsg, user, sizeof(char)*64);
+ printk("umsg: %s", umsg);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int data_from_kernel(struct sock *sk, int cmd, void *user, int *len)
+{
+ switch(cmd)
+ {
+ case BIH_GET:
+ {
+ struct
+ {
+ unsigned int in4addr;
+ struct in6_addr in6addr;
+ }argu;
+ char strbuff[128];
+ memset(&argu,0,sizeof(argu));
+ copy_from_user(&argu, user, sizeof(argu));
+ argu.in4addr=pool_addr_assign(&argu.in6addr);
+ inet_ntop6((unsigned char *)&argu.in6addr, strbuff, sizeof(strbuff)-1);
+ printk("%u.%u.%u.%u %s\n",NIPQUAD(argu.in4addr),strbuff);
+ copy_to_user(user,&argu, sizeof(argu));
+ }
+ break;
+ }
+ return 0;
+}
+
+static struct nf_sockopt_ops bih_sockops =
+{
+ .pf = PF_INET,
+ .set_optmin = BIH_SET,
+ .set_optmax = BIH_MAX,
+ .set = data_to_kernel,
+ .get_optmin = BIH_GET,
+ .get_optmax = BIH_MAX,
+ .get = data_from_kernel,
+};
+
+static unsigned int hook_func6(unsigned int hookunm,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *))
+{
+ int ret;
+ printk("bih: hook_func6 bih_xmit start\n");
+ ret=bih_xmit(skb,(struct net_device *)in);
+ if(ret==0)
+ return(NF_STOLEN);
+ else
+ return(NF_ACCEPT);
+}
+
+static unsigned int hook_func4(unsigned int hookunm,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *))
+{
+ int ret;
+ printk("bih: hook_func4 bih_xmit start\n");
+ ret=bih_xmit(skb,(struct net_device *)out);
+ if(ret==0)
+ return(NF_STOLEN);
+ else
+ return(NF_ACCEPT);
+}
+
+struct nf_hook_ops nfho_ipv4 = {
+ .hook = hook_func4,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = 4,
+ .priority = NF_IP_PRI_FIRST,
+};
+
+struct nf_hook_ops nfho_ipv6 = {
+ .hook = hook_func6,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = 0,
+ .priority = NF_IP6_PRI_FIRST,
+};
+
+int hook_init(void)
+{
+ int ret;
+ ret=nf_register_hook(&nfho_ipv4);
+ if(ret!=0)
+ {
+ printk("nf_register_hook(ipv4) error\n");
+ return(-1);
+ }
+ ret=nf_register_hook(&nfho_ipv6);
+ if(ret!=0)
+ {
+ printk("nf_register_hook(ipv6) error\n");
+ nf_unregister_hook(&nfho_ipv4);
+ return(-1);
+ }
+ return 0;
+}
+
+int hook_exit(void)
+{
+ nf_unregister_hook(&nfho_ipv4);
+ nf_unregister_hook(&nfho_ipv6);
+ return 0;
+}
+
+static int proc_show_bis(struct seq_file *m, void *v)
+{
+ if(BIHMODE==1)
+ seq_printf(m, "ENABLE\n");
+ else
+ seq_printf(m, "DISABLE\n");
+ return(0);
+}
+
+static int proc_open_bis(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_show_bis, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_file_bis_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_open_bis,
+ .read = seq_read,
+ .write = seq_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+
+};
+
+static int proc_init_bis(char *name,mode_t mode)
+{
+ if(proc_dir == NULL)
+ {
+ printk("proc_dir error\n");
+ return(-1);
+ }
+
+ proc_file_bis = proc_create(name, mode, proc_dir, &proc_file_bis_fops);
+ if(!proc_file_bis)
+ {
+ return(-1);
+ }
+ return (0);
+}
+
+static int proc_show_mode(struct seq_file *m, void *v)
+{
+ switch(BIHMODE)
+ {
+ case 0:
+ seq_printf(m, "NULL\n");
+ break;
+ case 1:
+ seq_printf(m, "BIS\n");
+ break;
+ case 2:
+ seq_printf(m, "BIA\n");
+ break;
+ default:
+ seq_printf(m, "ERROR\n");
+ break;
+ }
+ return (0);
+}
+static int proc_write_mode(struct file *file, const char __user *buffer,size_t count, loff_t *ofs)
+{
+ int len;
+ char buff[32];
+
+ if(count >= sizeof(buff))
+ len = sizeof(buff)-1;
+ else
+ len = count;
+ if(copy_from_user(buff, buffer, len))
+ {
+ printk("copy_from_user error\n");
+ return -1;
+ }
+ buff[len] = 0;
+ if(strncmp(buff,"NULL",4)==0)
+ BIHMODE=0;
+ else if(strncmp(buff,"BIS",3)==0)
+ BIHMODE=1;
+ else if(strncmp(buff,"BIA",3)==0)
+ {
+ if(BIHMODE!=2)
+ {
+ BIHMODE=2;
+ }
+ }
+ else
+ {
+ printk("buff(%s) error\n",buff);
+ return(-1);
+ }
+ return len;
+}
+
+static int proc_open_mode(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_show_mode, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_file_mode_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_open_mode,
+ .read = seq_read,
+ .write = proc_write_mode,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_init_mode(char *name,mode_t mode)
+{
+ if(proc_dir == NULL)
+ {
+ printk("proc_dir error\n");
+ return(-1);
+ }
+
+ proc_file_mode = proc_create(name, mode,proc_dir, &proc_file_mode_fops);
+ if(!proc_file_mode)
+ {
+ return(-1);
+ }
+ return (0);
+}
+
+static int proc_show_pool(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%s\n",pool_addr_show());
+ return 0;
+}
+static int proc_write_pool(struct file *file, const char __user *buffer,size_t count, loff_t *ofs)
+{
+ int len,cmdlen=0,slen;
+ char buff[512],*cmd=NULL,*argu=NULL;
+ unsigned int addr;
+ if(count >= sizeof(buff))
+ len = sizeof(buff)-1;
+ else
+ len = count;
+ if(copy_from_user(buff, buffer, len))
+ {
+ printk("copy_from_user error\n");
+ return -1;
+ }
+ buff[len] = 0;
+ slen=strlen(buff);
+ if(buff[slen-1]=='\n')
+ {
+ slen--;
+ buff[slen]=0;
+ }
+ if(buff[slen-1]=='\r')
+ {
+ slen--;
+ buff[slen]=0;
+ }
+ msg_field2(buff,slen,0,&cmd,&cmdlen,' ');
+ argu=buff+cmdlen+1;
+ if(strncmp(cmd,"ADD",cmdlen)==0)
+ pool_addr_add2(argu);
+ else if(strncmp(cmd,"DEL",cmdlen)==0)
+ pool_addr_del2(argu);
+ else if(strncmp(cmd,"SHOW",cmdlen)==0)
+ printk("%s\n",pool_addr_show());
+ else if(strncmp(cmd,"ASSIGN",cmdlen)==0)
+ {
+ struct in6_addr in6addr;
+ char *pstr,strbuff[64];
+ int pstrlen;
+ if(msg_field2(buff,slen,1,&pstr,&pstrlen,' ')==0)
+ {
+ snprintf(buff,sizeof(buff)-1,"%.*s",pstrlen,pstr);
+ memset(&in6addr,0,sizeof(struct in6_addr));
+ inet_pton6(buff,in6addr.s6_addr);
+ addr=pool_addr_assign(&in6addr);
+ inet_ntop6((unsigned char *)&in6addr, strbuff, sizeof(strbuff)-1);
+ printk("%u.%u.%u.%u %s\n",NIPQUAD(addr),strbuff);
+ }
+ else
+ {
+ addr=pool_addr_assign(NULL);
+ printk("%u.%u.%u.%u\n",NIPQUAD(addr));
+ }
+ }
+ else
+ pool_addr_add2(buff);
+ return len;
+}
+
+static int proc_open_pool(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_show_pool, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_file_pool_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_open_pool,
+ .read = seq_read,
+ .write = proc_write_pool,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_init_pool(char *name,mode_t mode)
+{
+ if(proc_dir == NULL)
+ {
+ printk("proc_dir error\n");
+ return(-1);
+ }
+
+ proc_file_pool = proc_create(name, mode,proc_dir, &proc_file_pool_fops);
+ if(!proc_file_pool)
+ {
+ return(-1);
+ }
+ return (0);
+}
+
+static int proc_show_map(struct seq_file *m, void *v)
+{
+ seq_printf(m,"%s",map_showrun());
+ return (0);
+}
+
+static int proc_write_map(struct file *file, const char __user *buffer,size_t count, loff_t *ofs)
+{
+ int len,slen,in4len,in6len,cmdlen;
+ char buff[512],*str,*cmdstr,*in4str,*in6str;
+ unsigned int in4addr;
+ struct in6_addr in6addr;
+
+ if(count >= sizeof(buff))
+ len = sizeof(buff)-1;
+ else
+ len = count;
+ if(copy_from_user(buff, buffer, len))
+ {
+ printk("copy_from_user error\n");
+ return -1;
+ }
+ buff[len] = 0;
+ slen=strlen(buff);
+ if(buff[slen-1]=='\n')
+ {
+ slen--;
+ buff[slen]=0;
+ }
+ if(buff[slen-1]=='\r')
+ {
+ slen--;
+ buff[slen]=0;
+ }
+
+ if(msg_field2(buff,slen,0,&cmdstr,&cmdlen,' ')!=0)
+ {
+ printk("msg_field2 error\n");
+ return -1;
+ }
+ if(strncmp(cmdstr,"ADD",cmdlen)==0)
+ {
+ if(msg_field2(buff,slen,1,&in4str,&in4len,' ')==0&&
+ msg_field2(buff,slen,2,&in6str,&in6len,' ')==0)
+ {
+ str=buff2String(in4str,in4len);
+ inet_pton4(str,(unsigned char *)&in4addr);
+ str=buff2String(in6str,in6len);
+ inet_pton6(str,in6addr.s6_addr);
+ if(map_add(in4addr,in6addr)==NULL)
+ {
+ printk("map_add error\n");
+ return -1;
+ }
+ }
+ else
+ {
+ printk("msg_field2 error\n");
+ return -1;
+ }
+ }
+ else if(strncmp(cmdstr,"DEL",cmdlen)==0)
+ {
+ if(msg_field2(buff,slen,1,&in4str,&in4len,' ')==0)
+ {
+ str=buff2String(in4str,in4len);
+ inet_pton4(str,(unsigned char *)&in4addr);
+ map_del(in4addr);
+ }
+ else
+ {
+ printk("msg_field2 error\n");
+ return -1;
+ }
+ }
+ else if(strncmp(cmdstr,"CLEAR",cmdlen)==0)
+ {
+ map_free(NULL);
+ }
+ else
+ {
+ printk("cmd(%.*s error\n",cmdlen,cmdstr);
+ return -1;
+ }
+ return len;
+}
+
+static int proc_open_map(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_show_map, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_file_map_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_open_map,
+ .read = seq_read,
+ .write = proc_write_map,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_init_map(char *name,mode_t mode)
+{
+ if(proc_dir == NULL)
+ {
+ printk("proc_dir error\n");
+ return(-1);
+ }
+
+ proc_file_map = proc_create(name, mode,proc_dir, &proc_file_map_fops);
+ if(!proc_file_map)
+ {
+ return(-1);
+ }
+ return (0);
+}
+
+static int proc_show_network(struct seq_file *m, void *v)
+{
+ switch(NETWORKTYPE)
+ {
+ case 1:
+ seq_printf(m, "V4\n");
+ break;
+ case 2:
+ seq_printf(m, "V6\n");
+ break;
+ case 3:
+ seq_printf(m, "DS\n");
+ break;
+ default:
+ seq_printf(m, "ERR\n");
+ break;
+ }
+ return 0;
+}
+static int proc_write_network(struct file *file, const char __user *buffer,size_t count, loff_t *ofs)
+{
+ int len;
+ char buff[32];
+
+ if(count >= sizeof(buff))
+ len = sizeof(buff)-1;
+ else
+ len = count;
+ if(copy_from_user(buff, buffer, len))
+ {
+ printk("copy_from_user error\n");
+ return -1;
+ }
+ buff[len] = 0;
+ if(strncmp(buff,"V4",2)==0)
+ NETWORKTYPE=1;
+ else if(strncmp(buff,"V6",2)==0)
+ NETWORKTYPE=2;
+ else if(strncmp(buff,"DS",2)==0)
+ {
+ NETWORKTYPE=3;
+ }
+ else
+ {
+ printk("buff(%s) error\n",buff);
+ return(-1);
+ }
+ return len;
+}
+
+static int proc_open_network(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_show_network, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_file_network_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_open_network,
+ .read = seq_read,
+ .write = proc_write_network,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_init_network(char *name,mode_t mode)
+{
+ if(proc_dir == NULL)
+ {
+ printk("proc_dir error\n");
+ return(-1);
+ }
+
+ proc_file_network = proc_create(name, mode,proc_dir, &proc_file_network_fops);
+ if(!proc_file_network)
+ {
+ return(-1);
+ }
+ return (0);
+}
+
+static int proc_show_private(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%u.%u.%u.%u\n",NIPQUAD(PRIVATEADDR));
+ return 0;
+}
+static int proc_write_private(struct file *file, const char __user *buffer,size_t count, loff_t *ofs)
+{
+ int len;
+ char buff[32];
+
+ if(count >= sizeof(buff))
+ len = sizeof(buff)-1;
+ else
+ len = count;
+ if(copy_from_user(buff, buffer, len))
+ {
+ printk("copy_from_user error\n");
+ return -1;
+ }
+ buff[len] = 0;
+ PRIVATEADDR=sk_inet_addr(buff);
+ return len;
+}
+
+static int proc_open_private(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_show_private, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_file_private_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_open_private,
+ .read = seq_read,
+ .write = proc_write_private,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_init_private(char *name,mode_t mode)
+{
+ if(proc_dir == NULL)
+ {
+ printk("proc_dir error\n");
+ return(-1);
+ }
+
+ proc_file_private = proc_create(name, mode,proc_dir, &proc_file_private_fops);
+ if(!proc_file_private)
+ {
+ return(-1);
+ }
+ return (0);
+}
+
+extern int ipv6_get_addr(struct net_device *dev, struct in6_addr *addr);
+int get_lladdr(char *devname)
+{
+ struct in6_addr addr;
+ struct net_device *dev;
+ char buff[64];
+ int ret;
+
+ dev=dev_get_by_name(&init_net,devname);
+ if(dev==NULL)
+ {
+ printk("dev_get_by_name error\n");
+ return(-1);
+ }
+ ret=ipv6_get_addr(dev,&addr);
+ if(ret!=0)
+ {
+ printk("ipv6_get_addr(%s) error\n",dev->name);
+ return(-1);
+ }
+ if(inet_ntop6(addr.s6_addr, buff, sizeof(buff)-1)==NULL)
+ {
+ printk("inet_ntop6 error\n");
+ return(-1);
+ }
+// printk("addr=%s\n",buff);
+ return(0);
+}
+
+static int __init init_procfs(void) //initiate file
+{
+ int ret = 0;
+ bihdev=dev_get_by_name(&init_net,"lo");
+ if(bihdev==NULL)
+ {
+ printk("dev_get_by_name error\n");
+ return(-1);
+ }
+ proc_dir= proc_mkdir(MODULE_NAME, NULL);
+ if(proc_dir == NULL)
+ {
+ printk("proc_mkdir error\n");
+ return(-1);
+ }
+// proc_dir->owner = THIS_MODULE;
+ ret=proc_init_bis("bis",06444);
+ if(ret!=0)
+ {
+ remove_proc_entry(MODULE_NAME, NULL);
+ return(-1);
+ }
+ ret=proc_init_mode("mode",06444);
+ if(ret!=0)
+ {
+ remove_proc_entry("bis", proc_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+ return(-1);
+ }
+ ret=proc_init_pool("pool",06444);
+ if(ret!=0)
+ {
+ remove_proc_entry("bis", proc_dir);
+ remove_proc_entry("mode", proc_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+ return(-1);
+ }
+ ret=proc_init_map("map",06444);
+ if(ret!=0)
+ {
+ remove_proc_entry("pool", proc_dir);
+ remove_proc_entry("bis", proc_dir);
+ remove_proc_entry("mode", proc_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+ return(-1);
+ }
+ ret=proc_init_network("network",06444);
+ if(ret!=0)
+ {
+ remove_proc_entry("map", proc_dir);
+ remove_proc_entry("pool", proc_dir);
+ remove_proc_entry("bis", proc_dir);
+ remove_proc_entry("mode", proc_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+ return(-1);
+ }
+ ret=proc_init_private("private",06444);
+ if(ret!=0)
+ {
+ remove_proc_entry("map", proc_dir);
+ remove_proc_entry("pool", proc_dir);
+ remove_proc_entry("bis", proc_dir);
+ remove_proc_entry("mode", proc_dir);
+ remove_proc_entry("network", proc_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+ return(-1);
+ }
+// get_lladdr("eth0");
+ hook_init();
+ map_init();
+ nf_register_sockopt(&bih_sockops);
+ nf_register_sockopt(&rt_sockops);
+ return(0);
+}
+
+static void __exit cleanup_procfs(void)
+{
+ remove_proc_entry("map", proc_dir);
+ remove_proc_entry("pool", proc_dir);
+ remove_proc_entry("bis", proc_dir);
+ remove_proc_entry("mode", proc_dir);
+ remove_proc_entry("network", proc_dir);
+ remove_proc_entry("private", proc_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+ map_uninit();
+ hook_exit();
+ nf_unregister_sockopt(&bih_sockops);
+ nf_unregister_sockopt(&rt_sockops);
+}
+
+module_init(init_procfs); //programe entry
+module_exit(cleanup_procfs); //programe exit
diff --git a/drivers/net/bih/config.sh b/drivers/net/bih/config.sh
new file mode 100644
index 00000000..750652f1
--- /dev/null
+++ b/drivers/net/bih/config.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+v4addr=192.168.1.34
+v6addr=2001:da8:bf:1010::c0a8:122
+v6gw=2001:da8:bf:1010::c0a8:101
+nameserver=2001:da8:bf:1010::1
+pool=192.168.3.40-192.168.3.100
+#map="192.168.1.35 2001:da8:bf:1010::c0a8:123"
+#map="192.168.1.200 2001:da8:bf:1010::c0a8:1c8"
+#map="192.168.1.40 2001:da8:bf:1010::c0a8:128"
+#################################################
+dev=`ifconfig|grep ^eth|awk '{print $1}'|tail -1`
+if [ "X$v6addr" != "X" ] ; then
+ ifconfig $dev inet6 add $v6addr/64
+fi
+if [ "X$v4addr" != "X" ] ; then
+ ifconfig $dev $v4addr
+fi
+if [ "X$v6gw" != "X" ] ; then
+ route -Ainet6 add default gw $v6gw
+fi
+if [ "X$nameserver" != "X" ] ; then
+ echo "nameserver $nameserver" > /etc/resolv.conf
+fi
+rmmod bih > /dev/null 2>&1
+insmod `pwd`/kernel-module/bih.ko
+if [ "X$pool" != "X" ] ; then
+ echo ADD $pool > /proc/bih/pool
+fi
+if [ "X$map" != "X" ] ; then
+ echo ADD $map > /proc/bih/map
+fi
+route add default dev $dev
+echo "1" > /proc/sys/net/ipv6/conf/all/forwarding
+echo "BIS" > /proc/bih/mode
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);
+}
diff --git a/drivers/net/bih/map.h b/drivers/net/bih/map.h
new file mode 100644
index 00000000..3972b5c4
--- /dev/null
+++ b/drivers/net/bih/map.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ */
+#ifndef _MAP_H
+#define _MAP_H
+struct map_node
+{
+ struct map_node *next;
+ struct map_node *prev;
+ unsigned int id;
+ struct in6_addr in6addr;
+ unsigned long start_time;
+ unsigned long last_time;
+};
+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);
+
+#endif
diff --git a/drivers/net/bih/pool.c b/drivers/net/bih/pool.c
new file mode 100644
index 00000000..e5cc2f49
--- /dev/null
+++ b/drivers/net/bih/pool.c
@@ -0,0 +1,283 @@
+/*
+ * 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>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+#include "voslist.h"
+#include "map.h"
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+struct pool_node
+{
+ struct listnode *addr;
+ struct listnode *currnode;
+ unsigned int curraddr;
+}ADDRPOOL;
+
+int pool_addr_add(unsigned int first,unsigned int last);
+int pool_addr_add2(char *string);
+int pool_addr_del(unsigned int first,unsigned int last);
+int pool_addr_del2(char *string);
+char *pool_addr_show(void);
+unsigned int pool_addr_assign(struct in6_addr *in6addr);
+
+/*
+ Insert an address block(from 'first' to 'last') into the address pool.
+*/
+int pool_addr_add(unsigned int first,unsigned int last)
+{
+ struct pool_node *node=&ADDRPOOL;
+ struct listnode *listnode;
+
+ if(ntohl(first)>ntohl(last))
+ {
+ lprintf(0,"argument error\n");
+ return(-1);
+ }
+ listnode=listnode_find(node->addr,first);
+ if(listnode)
+ {
+ listnode->data=(void *)last;
+ return(0);
+ }
+ listnode=listnode_add(&(node->addr),first,(void *)last,0);
+ if(listnode==NULL)
+ {
+ lprintf(0,"listnode_add error \n");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ Insert an address block into the address pool, not numbers but characters.
+*/
+int pool_addr_add2(char *string)
+{
+ unsigned int first,last;
+ char *pstr,*firststr,*laststr;
+ int ret,slen,num=0,pstrlen,firststrlen,laststrlen;
+
+ if(string==NULL)
+ {
+ lprintf(0,"arguments error\n");
+ return(-1);
+ }
+ slen=strlen(string);
+ if(string[slen-1]=='\n')
+ {
+ slen--;
+ string[slen]=0;
+ }
+ if(string[slen-1]=='\r')
+ {
+ slen--;
+ string[slen]=0;
+ }
+ ret=0;
+ while(msg_field2(string,slen,num++,&pstr,&pstrlen,',')==0)
+ {
+ if(msg_field2(pstr,pstrlen,0,&firststr,&firststrlen,'-')==0&&
+ msg_field2(pstr,pstrlen,1,&laststr,&laststrlen,'-')==0)
+ {
+ first=sk_inet_addr(buff2String(firststr,firststrlen));
+ last=sk_inet_addr(buff2String(laststr,laststrlen));
+ ret=pool_addr_add(first,last);
+ if(ret!=0)
+ lprintf(0,"\"%.*s\" error\n",pstrlen,pstr);
+ }
+ else
+ lprintf(0,"addr(%.*s) error\n",pstrlen,pstr);
+ }
+ return(0);
+}
+
+/*
+ Delete the address block from 'first' to 'last'.
+*/
+int pool_addr_del(unsigned int first,unsigned int last)
+{
+ struct pool_node *node=&ADDRPOOL;
+ struct listnode *listnode;
+
+ if(ntohl(first)>ntohl(last))
+ {
+ lprintf(0,"argument error\n");
+ return(-1);
+ }
+ listnode=listnode_find(node->addr,first);
+ if(listnode&&listnode->data==(void *)last)
+ {
+ listnode_del(&(node->addr),first,NULL);
+ return(0);
+ }
+ lprintf(0,"\"%u.%u.%u.%u-%u.%u.%u.%u\" is not exist\n",NIPQUAD(first),NIPQUAD(last));
+ return(-1);
+}
+
+/*
+ Delete the address block.
+*/
+int pool_addr_del2(char *string)
+{
+ unsigned int first,last;
+ char *pstr,*firststr,*laststr;
+ int ret,slen,num=0,pstrlen,firststrlen,laststrlen;
+
+ if(string==NULL)
+ {
+ lprintf(0,"arguments error\n");
+ return(-1);
+ }
+ slen=strlen(string);
+ if(string[slen-1]=='\n')
+ {
+ slen--;
+ string[slen]=0;
+ }
+ if(string[slen-1]=='\r')
+ {
+ slen--;
+ string[slen]=0;
+ }
+ ret=0;
+ while(msg_field2(string,slen,num++,&pstr,&pstrlen,',')==0)
+ {
+ if(msg_field2(pstr,pstrlen,0,&firststr,&firststrlen,'-')==0&&
+ msg_field2(pstr,pstrlen,1,&laststr,&laststrlen,'-')==0)
+ {
+ first=sk_inet_addr(buff2String(firststr,firststrlen));
+ last=sk_inet_addr(buff2String(laststr,laststrlen));
+ ret=pool_addr_del(first,last);
+ if(ret!=0)
+ lprintf(0,"\"%.*s\" error\n",pstrlen,pstr);
+ }
+ else
+ lprintf(0,"addr(%.*s) error\n",pstrlen,pstr);
+ }
+ return(0);
+}
+
+/*
+ Print the information of the address block.
+*/
+char *pool_addr_show(void)
+{
+ struct listnode *node,*head=ADDRPOOL.addr;
+ unsigned int first,last;
+ SHOW2BUF_DEF;
+ SHOW2BUF_INIT();
+ node=head;
+ while(node)
+ {
+ first=node->key;
+ last=(unsigned int)(node->data);
+ if(node!=head)
+ SHOW2BUF(",");
+ SHOW2BUF("%u.%u.%u.%u-%u.%u.%u.%u %u.%u.%u.%u",NIPQUAD(first),NIPQUAD(last),NIPQUAD(ADDRPOOL.curraddr));
+ node=node->next;
+ }
+ SHOW2BUF_RET;
+}
+
+/*
+ If there is a new IPv6 address arrival:
+ 1. If this IPv6 address already exists in the mapping relationship, return the IPv4 address;
+ 2. Otherwise, check the address block to find a free IPv4 address to make a mapping relationship with this IPv6 address;
+ 3. If there is no free IPv4 address, then check the next address block, and repeat step 2;
+ 4. If there is no free IPv4 address in all the address blocks, start from the first block and repeate step 2;
+ 5. If there is no free IPv4 address in the address pool, print the error message 'There is on free ip address'.
+*/
+unsigned int pool_addr_assign(struct in6_addr *in6addr)
+{
+ struct pool_node *node=&ADDRPOOL;
+ struct listnode *list_node;
+ unsigned int addr,first_addr,last_addr;
+ struct map_node *mapnode;
+
+ if((node==NULL)||(node->addr==NULL))
+ {
+ lprintf(0,"argument error\n");
+ return(0);
+ }
+ if(node->currnode==NULL)
+ node->currnode=node->addr;
+ list_node=node->currnode;
+ if(in6addr)
+ {
+ mapnode=map_find(*in6addr);
+ if(mapnode)
+ return(mapnode->id);
+ }
+ do
+ {
+ first_addr=list_node->key;
+ last_addr=(unsigned int)(list_node->data);
+ if(node->curraddr==0)
+ {
+ node->curraddr=first_addr;
+ addr=node->curraddr;
+ }
+ else
+ {
+ addr=htonl(ntohl(node->curraddr)+1);
+ }
+ do
+ {
+ if(ntohl(addr)>ntohl(last_addr))
+ addr=first_addr;
+ if(map_search(addr)==NULL)
+ {
+ node->currnode=list_node;
+ node->curraddr=addr;
+ if(in6addr)
+ map_add(addr,*in6addr);
+ return(addr);
+ }
+ else
+ {
+ addr=htonl(ntohl(addr)+1);
+ }
+ }
+ while(addr!=node->curraddr);
+ list_node=list_node->next;
+ if(list_node==NULL)
+ list_node=node->addr;
+ }
+ while(list_node!=node->currnode);
+ lprintf(0,"There is no free ip address\n");
+ return(0);
+}
diff --git a/drivers/net/bih/pool.h b/drivers/net/bih/pool.h
new file mode 100644
index 00000000..eb46e1d7
--- /dev/null
+++ b/drivers/net/bih/pool.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ */
+#ifndef _POOL_H
+#define _POOL_H
+int pool_addr_add(unsigned int first,unsigned int last);
+int pool_addr_add2(char *string);
+int pool_addr_del(unsigned int first,unsigned int last);
+int pool_addr_del2(char *string);
+char *pool_addr_show(void);
+unsigned int pool_addr_assign(struct in6_addr *in6addr);
+
+#endif
diff --git a/drivers/net/bih/translate.c b/drivers/net/bih/translate.c
new file mode 100644
index 00000000..ddd18c0d
--- /dev/null
+++ b/drivers/net/bih/translate.c
@@ -0,0 +1,1585 @@
+/*
+ * 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.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/slab.h>
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+#include <linux/random.h>
+#include <linux/in.h>
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/inetdevice.h>
+#include <net/ip.h> /* struct iphdr */
+#include <net/icmp.h> /* struct icmphdr */
+#include <net/ipv6.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <linux/in6.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <net/addrconf.h>
+#include "translate.h"
+#include "map.h"
+#include "pool.h"
+#include "voslist.h"
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+#define __BIHDEBUG__
+
+#define BIH_DEBUG printk
+/*
+ * If tos_ignore_flag != 0, we don't copy TOS and Traffic Class
+ * from origin paket and set it to 0
+ */
+int tos_ignore_flag = 0;
+int BIHMODE,NETWORKTYPE=0;
+unsigned int PRIVATEADDR=0;
+extern struct net_device *bihdev;
+
+int ip6option(int type)
+{
+ int i,optarray[8]={IPPROTO_HOPOPTS,IPPROTO_IPV6,IPPROTO_ROUTING,IPPROTO_FRAGMENT,
+ IPPROTO_ESP,IPPROTO_AH,IPPROTO_DSTOPTS,IPPROTO_NONE};
+ for(i=0;i<8;i++)
+ {
+ if(type==optarray[i])
+ return(optarray[i]);
+ }
+ return(0);
+}
+
+unsigned char *getipv6uppkg(unsigned char *ippkg,unsigned char *protocol,int *uppkglen)
+{
+ unsigned char *ippkgpos=ippkg+40;
+ struct ip6_hdr *hdr=(struct ip6_hdr *)ippkg;
+ struct ip6_opthdr *opthdr;
+ int ip6hdrlen;
+
+ if(ip6option(hdr->ip6_nxt))
+ {
+ opthdr=(struct ip6_opthdr *)ippkgpos;
+ while(ip6option(opthdr->nxt))
+ {
+ ippkgpos+=opthdr->len;
+ opthdr=(struct ip6_opthdr *)ippkgpos;
+ }
+ if(protocol)
+ *protocol=opthdr->nxt;
+ ippkgpos+=opthdr->len;
+ }
+ else
+ if(protocol)
+ *protocol=hdr->ip6_nxt;
+ ip6hdrlen=ippkgpos-ippkg;
+ if(uppkglen)
+ *uppkglen=ntohs(hdr->ip6_plen)+40-ip6hdrlen;
+ return(ippkgpos);
+}
+
+unsigned short chksum(unsigned short *data,int len)
+{
+ unsigned short answer=0,*p=data;
+ int nleft=len,sum=0;
+ while(nleft>1)
+ {
+ sum+=*p++;
+ nleft-=2;
+ }
+ if(nleft==1)
+ {
+ *(unsigned char *)(&answer)=*(unsigned char *)p;
+ sum+=answer;
+ }
+ sum=(sum>>16)+(sum&0xffff);
+ sum+=(sum>>16);
+ answer=~sum;
+ return(answer);
+}
+
+unsigned short tcpchksum6(unsigned char *src,unsigned char *dst,unsigned char *tcppkg,int tcppkglen)
+{
+ struct tcp *th;
+ static unsigned char *tmpbuf=NULL;
+ unsigned char *bufpos;
+ int tmpbuflen;
+
+ if(tmpbuf==NULL)
+ {
+ tmpbuf=kmalloc(2048,GFP_KERNEL);
+ if(tmpbuf==NULL)
+ {
+ lprintf(0,"kmalloc error\n");
+ return(0);
+ }
+ }
+ bufpos=tmpbuf;
+ th=(struct tcp *)tcppkg;
+ th->check=0;
+ memcpy(bufpos,src,16);
+ bufpos+=16;
+ memcpy(bufpos,dst,16);
+ bufpos+=16;
+ *bufpos++=0;
+ *bufpos++=IPPROTO_TCP;
+ PKG_PUT_SHORT(tcppkglen,bufpos);
+ memcpy(bufpos,tcppkg,tcppkglen);
+ bufpos+=tcppkglen;
+ tmpbuflen=bufpos-tmpbuf;
+ return(chksum((unsigned short *)tmpbuf,tmpbuflen));
+}
+
+unsigned short tcpchksum(unsigned char *src,unsigned char *dst,unsigned char *tcppkg,int tcppkglen)
+{
+ struct tcp *th;
+ static unsigned char *tmpbuf=NULL;
+ unsigned char *bufpos;
+ int tmpbuflen;
+
+ if(tmpbuf==NULL)
+ {
+ tmpbuf=kmalloc(2048,GFP_KERNEL);
+ if(tmpbuf==NULL)
+ {
+ lprintf(0,"kmalloc error\n");
+ return(0);
+ }
+ }
+ bufpos=tmpbuf;
+ th=(struct tcp *)tcppkg;
+ th->check=0;
+ memcpy(bufpos,src,4);
+ bufpos+=4;
+ memcpy(bufpos,dst,4);
+ bufpos+=4;
+ *bufpos++=0;
+ *bufpos++=IPPROTO_TCP;
+ PKG_PUT_SHORT(tcppkglen,bufpos);
+ memcpy(bufpos,tcppkg,tcppkglen);
+ bufpos+=tcppkglen;
+ tmpbuflen=bufpos-tmpbuf;
+ return(chksum((unsigned short *)tmpbuf,tmpbuflen));
+}
+
+int ipv6_get_addr(struct net_device *dev, struct in6_addr *addr)
+{
+ struct inet6_dev *idev;
+ int err = -EADDRNOTAVAIL;
+
+ BIH_DEBUG("bih: ipv6_get_addr start\n");
+ if ((idev = __in6_dev_get(dev)) != NULL) {
+ struct inet6_ifaddr *ifp;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifp, &idev->addr_list, if_list){
+ char dst[64];//test
+ inet_ntop6((unsigned char *)&ifp->addr, dst, sizeof(dst)-1);//test
+ BIH_DEBUG("bih: ipv6_get_addr addr=%s and if->scope=%d ifp->flags=%d\n",dst ,ifp->scope, ifp->flags);
+ if (ifp->scope != IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE))
+ {
+ //ipv6_addr_copy(addr, &ifp->addr);
+ *addr = ifp->addr;
+ err = 0;
+ break;
+ }
+ }
+ read_unlock_bh(&idev->lock);
+ }
+ return err;
+}
+
+int ipv6_get_laddr(struct net_device *dev, struct in6_addr *addr)
+{
+ struct inet6_dev *idev;
+ int err = -EADDRNOTAVAIL;
+
+ BIH_DEBUG("bih: ipv6_get_laddr start\n");
+ if ((idev = __in6_dev_get(dev)) != NULL) {
+ struct inet6_ifaddr *ifp;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ char dst[64];//test
+ inet_ntop6((unsigned char *)&ifp->addr, dst, sizeof(dst)-1);//test
+ BIH_DEBUG("bih: ipv6_get_addr linklocal addr=%s and if->scope=%d ifp->flags=%d\n",dst ,ifp->scope, ifp->flags);
+ if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE))
+ {
+ //ipv6_addr_copy(addr, &ifp->addr); //
+ *addr = ifp->addr;
+ err = 0;
+ break;
+ }
+ }
+ read_unlock_bh(&idev->lock);
+ }
+ return err;
+}
+
+int ipv4_get_addr(struct net_device *dev, unsigned int *addr)
+{
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa = NULL;
+
+ BIH_DEBUG("bih: ipv4_get_addr start\n");
+ if ((in_dev = __in_dev_get_rtnl(dev)) != NULL)
+ {
+ for(ifa=in_dev->ifa_list;ifa!=NULL;ifa=ifa->ifa_next)
+ {
+ if(ifa->ifa_local!=0)
+ {
+ *addr=ifa->ifa_local;
+ return(0);
+ }
+ }
+ }
+ return(-1);
+}
+
+int ip_show(struct ip *ip)
+{
+ if(ip==NULL)
+ return 0;
+ BIH_DEBUG("bih: v(%u) hl(%u) tos(%u) len(%u) id(%u) off(%u) ",
+ ip->ip_v,ip->ip_hl<<2,ip->ip_tos,ntohs(ip->ip_len),ntohs(ip->ip_id),ntohs(ip->ip_off));
+ lprintf(1,"v(%u) hl(%u) tos(%u) len(%u) id(%u) off(%u) ",
+ ip->ip_v,ip->ip_hl<<2,ip->ip_tos,ntohs(ip->ip_len),ntohs(ip->ip_id),ntohs(ip->ip_off));
+ switch(ip->ip_p)
+ {
+ case IPPROTO_TCP:
+ lprintf(1,"TCP ");
+ break;
+ case IPPROTO_UDP:
+ lprintf(1,"UDP ");
+ break;
+ case IPPROTO_ICMP:
+ lprintf(1,"ICMP ");
+ break;
+ default:
+ lprintf(1,"%u ",ip->ip_p);
+ break;
+ }
+ BIH_DEBUG("bih: sum(%04X) %u.%u.%u.%u --> %u.%u.%u.%u\n",ntohs(ip->ip_sum),NIPQUAD(ip->ip_src),NIPQUAD(ip->ip_dst));
+ lprintf(1,"sum(%04X) %u.%u.%u.%u --> %u.%u.%u.%u\n",ntohs(ip->ip_sum),NIPQUAD(ip->ip_src),NIPQUAD(ip->ip_dst));
+ return(0);
+}
+
+int ipv6_show(struct ipv6hdr *ipv6)
+{
+ char dst[64],src[64];
+ if(ipv6==NULL)
+ return 0;
+ dst[0]=src[0]=0;
+ inet_ntop6((unsigned char *)&ipv6->daddr, dst, sizeof(dst)-1);
+ inet_ntop6((unsigned char *)&ipv6->saddr, src, sizeof(src)-1);
+ BIH_DEBUG("bih: v(%u) p(%u) plen(%d) proto(%d) hlimit(%d) %s --> %s\n",
+ ipv6->version,ipv6->priority,ntohs(ipv6->payload_len),ipv6->nexthdr,ipv6->hop_limit,src,dst);
+ lprintf(1,"v(%u) p(%u) plen(%d) proto(%d) hlimit(%d) %s --> %s\n",
+ ipv6->version,ipv6->priority,ntohs(ipv6->payload_len),ipv6->nexthdr,ipv6->hop_limit,src,dst);
+ return(0);
+}
+
+int tcp_show(struct tcp *tcp)
+{
+ if(tcp==NULL)
+ return(0);
+ BIH_DEBUG("bih: SPORT(%d) DPORT(%d) SEQ(%u) ACKSEQ(%u) HEADLEN(%d) FIN(%d) SYN(%d) RST(%d) PSH(%d) WINDOW(%d) SUM(%04x) URGPRT(%d)\n",
+ ntohs(tcp->sport),ntohs(tcp->dport),ntohl(tcp->seq),ntohl(tcp->ack_seq),tcp->doff<<2,
+ tcp->fin,tcp->syn,tcp->rst,tcp->psh,ntohs(tcp->window),ntohs(tcp->check),ntohs(tcp->urg_prt));
+ lprintf(1,"SPORT(%d) DPORT(%d) SEQ(%u) ACKSEQ(%u) HEADLEN(%d) FIN(%d) SYN(%d) RST(%d) PSH(%d) WINDOW(%d) SUM(%04x) URGPRT(%d)\n",
+ ntohs(tcp->sport),ntohs(tcp->dport),ntohl(tcp->seq),ntohl(tcp->ack_seq),tcp->doff<<2,
+ tcp->fin,tcp->syn,tcp->rst,tcp->psh,ntohs(tcp->window),ntohs(tcp->check),ntohs(tcp->urg_prt));
+ return(0);
+}
+
+int udp_show(struct udp *udp)
+{
+ if(udp==NULL)
+ return(0);
+ BIH_DEBUG("bih: SPORT(%d) DPORT(%d) LEN(%d) SUM(%04x)\n",
+ ntohs(udp->sport),ntohs(udp->dport),ntohs(udp->len),ntohs(udp->check));
+ lprintf(1,"SPORT(%d) DPORT(%d) LEN(%d) SUM(%04x)\n",
+ ntohs(udp->sport),ntohs(udp->dport),ntohs(udp->len),ntohs(udp->check));
+ return(0);
+}
+
+int skb_show(struct sk_buff *skb)
+{
+ struct ipv6hdr *ipv6;
+ struct tcp *tcp;
+ struct udp *udp;
+ if(skb==NULL)
+ return(0);
+ ipv6 = (struct ipv6hdr *)ipv6_hdr(skb);
+ tcp=(struct tcp *)(ipv6+1);
+ udp=(struct udp *)(ipv6+1);
+ ipv6_show(ipv6);
+ tcp_show(tcp);
+ return(0);
+}
+
+void array_show(unsigned char *packp,int packlen,char hdflag,char base)
+{
+ int i;
+ if(hdflag)
+ lprintf(7,"==================== ARRAY[%d] ====================\n",packlen);
+ for(i=0;i<packlen;i++)
+ {
+ switch(base)
+ {
+ case 16:
+ if(i&&!(i%16))
+ lprintf(7,"\n");
+ lprintf(7,"%02x ",packp[i]);
+ break;
+ case 10:
+ if(i&&!(i%16))
+ lprintf(7,"\n");
+ lprintf(7,"%03d ",packp[i]);
+ break;
+ case 2:
+ {
+ unsigned char n,mask=0x80;
+ if(i&&!(i%4))
+ lprintf(7,"\n");
+ for(n=0;n<8;n++)
+ {
+ if(n&&!(n%4))
+ lprintf(7,",");
+ if(packp[i]&mask)
+ lprintf(7,"1");
+ else
+ lprintf(7,"0");
+ mask>>=1;
+ }
+ lprintf(7," ");
+ break;
+ }
+ default:
+ lprintf(7,"%c",packp[i]);
+ break;
+ }
+ }
+ if(base==16)
+ lprintf(7,"\n");
+}
+
+
+static int ip4_ip6(struct net_device *dev,char *src, int len, char *dst, int include_flag)/*v4 address be translated*/
+{
+ struct in6_addr addr,dstaddr;
+ struct iphdr *ih4 = (struct iphdr *) src;
+ struct icmphdr *icmp_hdr;
+ struct udphdr *udp_hdr;
+ struct tcphdr *tcp_hdr;
+
+ struct ipv6hdr *ih6 = (struct ipv6hdr *) dst;
+ struct frag_hdr *ih6_frag = (struct frag_hdr *)(dst+sizeof(struct ipv6hdr));
+ struct icmp6hdr *icmp6_hdr;
+
+ int hdr_len = (int)(ih4->ihl * 4);
+ int icmp_len;
+ int plen;
+
+ unsigned int csum;
+ int fl_csum = 0;
+ int icmperr = 1;
+ int fr_flag = 0;
+ __u16 new_tot_len;
+ __u8 new_nexthdr;
+ __u16 icmp_ptr = 0;
+ int ret;
+ struct map_node *mapnode;
+
+ BIH_DEBUG("bih: ip4_ip6 start\n");
+ if(ipv4_is_loopback(ih4->daddr)||ipv4_is_multicast(ih4->daddr)||
+ ipv4_is_lbcast(ih4->daddr)||ipv4_is_zeronet(ih4->daddr)||
+ ih4->daddr==ih4->saddr)
+ {
+ BIH_DEBUG("bih: ip4_ip6 ipv4 is not right addr\n");
+ return(-1);
+ }
+
+ if(ih4->protocol==IPPROTO_UDP)
+ {
+ udp_hdr = (struct udphdr *)(src+hdr_len);
+ if(ntohs(udp_hdr->dest)==53)
+ {
+ BIH_DEBUG("bih: ip4_ip6 pkt type is dns\n");
+ return(-1);
+ }
+ }
+
+ ret=ipv6_get_addr(dev,&addr);
+ if(ret!=0)
+ {
+ BIH_DEBUG("bih: ip4_ip6 get ipv6 addr failed\n");
+ return(-1);
+ }
+ mapnode=map_search(ih4->daddr);
+ if(mapnode)
+ memcpy(&dstaddr,&mapnode->in6addr,sizeof(struct in6_addr));
+
+ else
+ {
+ BIH_DEBUG("bih: ip4_ip6 no correct map searched\n");
+ return(-1);
+ }
+#ifdef __BIHDEBUG__
+{
+ struct ip *ip=(struct ip *)ih4;
+ BIH_DEBUG("bih: ---------- %s ----------\n",mapnode?"466":"464");
+ lprintf(0,"---------- %s ----------\n",mapnode?"466":"464");
+ ip_show(ip);
+}
+#endif
+
+ if (ntohs(ih4->frag_off) == IP_DF || include_flag ) {
+ new_tot_len = ntohs(ih4->tot_len);
+
+ if (ih4->protocol == IPPROTO_ICMP)
+ new_nexthdr = NEXTHDR_ICMP;
+ else
+ new_nexthdr = ih4->protocol;
+ }
+ else {
+ /* need to add Fragment Header */
+ fr_flag = 1;
+ /* total length = total length from IPv4 packet +
+ length of Fragment Header */
+ new_tot_len = ntohs(ih4->tot_len) + sizeof(struct frag_hdr);
+ /* IPv6 Header NextHeader = NEXTHDR_FRAGMENT */
+ new_nexthdr = NEXTHDR_FRAGMENT;
+ /* Fragment Header NextHeader copy from IPv4 packet */
+ if (ih4->protocol == IPPROTO_ICMP)
+ ih6_frag->nexthdr = NEXTHDR_ICMP;
+ else
+ ih6_frag->nexthdr = ih4->protocol;
+
+ /* copy frag offset from IPv4 packet */
+ ih6_frag->frag_off = htons((ntohs(ih4->frag_off) & IP_OFFSET) << 3);
+ /* copy MF flag from IPv4 packet */
+ ih6_frag->frag_off = htons((ntohs(ih6_frag->frag_off) |
+ ((ntohs(ih4->frag_off) & IP_MF) >> 13)));
+ /* copy Identification field from IPv4 packet */
+ ih6_frag->identification = htonl(ntohs(ih4->id));
+ /* reserved field initialized to zero */
+ ih6_frag->reserved = 0;
+ }
+
+ ih6->version = 6;
+
+ if (tos_ignore_flag) {
+ ih6->priority = 0;
+ ih6->flow_lbl[0] = 0;
+ } else {
+ ih6->priority = (ih4->tos & 0xf0) >> 4;
+ ih6->flow_lbl[0] = (ih4->tos & 0x0f) << 4;
+ }
+ ih6->flow_lbl[1] = 0;
+ ih6->flow_lbl[2] = 0;
+
+ /* Hop Limit = IPv4 TTL */
+ ih6->hop_limit = ih4->ttl;
+
+ memcpy(ih6->saddr.s6_addr,addr.s6_addr,16);
+ memcpy(ih6->daddr.s6_addr,dstaddr.s6_addr,16);
+
+ plen = new_tot_len - hdr_len; /* Payload length = IPv4 total len - IPv4 header len */
+ ih6->payload_len = htons(plen);
+ ih6->nexthdr = new_nexthdr; /* Next Header */
+
+ switch (ih4->protocol) {
+ case IPPROTO_ICMP:
+ if ( (ntohs(ih4->frag_off) & IP_OFFSET) != 0 || (ntohs(ih4->frag_off) & IP_MF) != 0 ) {
+ BIH_DEBUG("bih: ip4_ip6(): don't translate ICMPv4 fragments - packet dropped.\n");
+ lprintf(0,"ip4_ip6(): don't translate ICMPv4 fragments - packet dropped.\n");
+ return -1;
+ }
+
+ icmp_hdr = (struct icmphdr *) (src+hdr_len); /* point to ICMPv4 header */
+ csum = 0;
+ icmp_len = ntohs(ih4->tot_len) - hdr_len; /* ICMPv4 packet length */
+ icmp6_hdr = (struct icmp6hdr *)(dst+sizeof(struct ipv6hdr)
+ +fr_flag*sizeof(struct frag_hdr)); /* point to ICMPv6 header */
+
+ if (include_flag) {
+ BIH_DEBUG("bih: ip4_ip6(): It's included ICMPv4 in ICMPv4 Error message - packet dropped.\n");
+ lprintf(0,"ip4_ip6(): It's included ICMPv4 in ICMPv4 Error message - packet dropped.\n");
+ return -1;
+ }
+
+ /* Check ICMPv4 Type field */
+ switch (icmp_hdr->type) {
+ /* ICMP Error messages */
+ /* Destination Unreachable (Type 3) */
+ case ICMP_DEST_UNREACH:
+ icmp6_hdr->icmp6_type = ICMPV6_DEST_UNREACH; /* to Type 1 */
+ icmp6_hdr->icmp6_unused = 0;
+ switch (icmp_hdr->code)
+ {
+ case ICMP_NET_UNREACH: /* Code 0 */
+ case ICMP_HOST_UNREACH: /* Code 1 */
+ case ICMP_SR_FAILED: /* Code 5 */
+ case ICMP_NET_UNKNOWN: /* Code 6 */
+ case ICMP_HOST_UNKNOWN: /* Code 7 */
+ case ICMP_HOST_ISOLATED: /* Code 8 */
+ case ICMP_NET_UNR_TOS: /* Code 11 */
+ case ICMP_HOST_UNR_TOS: /* Code 12 */
+ icmp6_hdr->icmp6_code = ICMPV6_NOROUTE; /* to Code 0 */
+ break;
+ case ICMP_PROT_UNREACH: /* Code 2 */
+ icmp6_hdr->icmp6_type = ICMPV6_PARAMPROB; /* to Type 4 */
+ icmp6_hdr->icmp6_code = ICMPV6_UNK_NEXTHDR; /* to Code 1 */
+ /* Set pointer filed to 6, it's octet offset IPv6 Next Header field */
+ icmp6_hdr->icmp6_pointer = htonl(6);
+ break;
+ case ICMP_PORT_UNREACH: /* Code 3 */
+ icmp6_hdr->icmp6_code = ICMPV6_PORT_UNREACH; /* to Code 4 */
+ break;
+ case ICMP_FRAG_NEEDED: /* Code 4 */
+ icmp6_hdr->icmp6_type = ICMPV6_PKT_TOOBIG; /* to Type 2 */
+ icmp6_hdr->icmp6_code = 0;
+ /* Correct MTU */
+ if (icmp_hdr->un.frag.mtu == 0)
+ icmp6_hdr->icmp6_mtu = htonl(576);
+ else
+ icmp6_hdr->icmp6_mtu = htonl(ntohs(icmp_hdr->un.frag.mtu)+IP4_IP6_HDR_DIFF);
+
+ break;
+ case ICMP_NET_ANO: /* Code 9 */
+ case ICMP_HOST_ANO: /* Code 10 */
+ icmp6_hdr->icmp6_code = ICMPV6_ADM_PROHIBITED; /* to Code 1 */
+ break;
+ default: /* discard any other Code */
+ BIH_DEBUG("bih: ip4_ip6(): Unknown ICMPv4 Type %d Code %d - packet dropped.\n",
+ ICMP_DEST_UNREACH, icmp_hdr->code);
+ lprintf(0,"ip4_ip6(): Unknown ICMPv4 Type %d Code %d - packet dropped.\n",
+ ICMP_DEST_UNREACH, icmp_hdr->code);
+ return -1;
+ }
+ break;
+ /* Time Exceeded (Type 11) */
+ case ICMP_TIME_EXCEEDED:
+ icmp6_hdr->icmp6_type = ICMPV6_TIME_EXCEED;
+ icmp6_hdr->icmp6_code = icmp_hdr->code;
+ break;
+ /* Parameter Problem (Type 12) */
+ case ICMP_PARAMETERPROB:
+ icmp6_hdr->icmp6_type = ICMPV6_PARAMPROB;
+ icmp6_hdr->icmp6_code = icmp_hdr->code;
+
+ icmp_ptr = ntohs(icmp_hdr->un.echo.id) >> 8;
+ switch (icmp_ptr) {
+ case 0:
+ icmp6_hdr->icmp6_pointer = 0;
+ break;
+ case 2:
+ icmp6_hdr->icmp6_pointer = __constant_htonl(4);
+ break;
+ case 8:
+ icmp6_hdr->icmp6_pointer = __constant_htonl(7);
+ break;
+ case 9:
+ icmp6_hdr->icmp6_pointer = __constant_htonl(6);
+ break;
+ case 12:
+ icmp6_hdr->icmp6_pointer = __constant_htonl(8);
+ break;
+ case 16:
+ icmp6_hdr->icmp6_pointer = __constant_htonl(24);
+ break;
+ default:
+ icmp6_hdr->icmp6_pointer = 0xffffffff;
+ break;
+ }
+ break;
+ case ICMP_ECHO:
+ icmperr = 0;
+ icmp6_hdr->icmp6_type = ICMPV6_ECHO_REQUEST;
+ icmp6_hdr->icmp6_code = 0;
+ memcpy(((char *)icmp6_hdr)+4, ((char *)icmp_hdr)+4, len - hdr_len - 4);
+ break;
+
+ case ICMP_ECHOREPLY:
+ icmperr = 0;
+ icmp6_hdr->icmp6_type = ICMPV6_ECHO_REPLY;
+ icmp6_hdr->icmp6_code = 0;
+ memcpy(((char *)icmp6_hdr)+4, ((char *)icmp_hdr)+4, len - hdr_len - 4);
+ break;
+
+ default:
+ BIH_DEBUG("bih: ip4_ip6(): Unknown ICMPv4 packet Type %x - packet dropped.\n", icmp_hdr->type);
+ lprintf(0,"ip4_ip6(): Unknown ICMPv4 packet Type %x - packet dropped.\n", icmp_hdr->type);
+ return -1;
+ }
+
+ if (icmperr) {
+ if (ip4_ip6(dev,src+hdr_len+sizeof(struct icmphdr), len - hdr_len - sizeof(struct icmphdr),
+ dst+sizeof(struct ipv6hdr)+fr_flag*sizeof(struct frag_hdr)
+ +sizeof(struct icmp6hdr), 1) == -1) {
+ BIH_DEBUG("bih: ip4_ip6(): Uncorrect translation of ICMPv4 Error message - packet dropped.\n");
+ lprintf(0,"ip4_ip6(): Uncorrect translation of ICMPv4 Error message - packet dropped.\n");
+ return -1;
+ }
+ icmp_len += 20;
+ plen += 20;
+ ih6->payload_len = htons(plen);
+ }
+
+ icmp6_hdr->icmp6_cksum = 0;
+ csum = 0;
+
+ csum = csum_partial((u_char *)icmp6_hdr, icmp_len, csum);
+ icmp6_hdr->icmp6_cksum = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, icmp_len,
+ IPPROTO_ICMPV6, csum);
+ break;
+
+ case IPPROTO_TCP:
+ memcpy(dst+sizeof(struct ipv6hdr)+fr_flag*sizeof(struct frag_hdr),
+ src+hdr_len, len - hdr_len);
+ tcp_hdr = (struct tcphdr *)(dst+sizeof(struct ipv6hdr)+ fr_flag*sizeof(struct frag_hdr));
+ if(ntohs(ih4->frag_off) == IP_DF||ih4->frag_off==0)
+ {
+ tcp_hdr->check = 0;
+ csum = 0;
+ csum = csum_partial((unsigned char *)tcp_hdr, plen - fr_flag*sizeof(struct frag_hdr), csum);
+ tcp_hdr->check = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, plen - fr_flag*sizeof(struct frag_hdr), IPPROTO_TCP, csum);
+ }
+ else if((ntohs(ih4->frag_off)&IP_OFFSET)==0&&(ntohs(ih4->frag_off)&IP_MF)!= 0)
+ tcp_hdr->check = 0;
+#ifdef __BIHDEBUG__
+{
+ struct tcp *tcp=(struct tcp *)tcp_hdr;
+ ipv6_show(ih6);
+ tcp_show(tcp);
+}
+#endif
+ break;
+
+ case IPPROTO_UDP:
+ udp_hdr = (struct udphdr *)(src+hdr_len);
+ if ((ntohs(ih4->frag_off) & IP_OFFSET) == 0) {
+ if ((ntohs(ih4->frag_off) & IP_MF) != 0) {
+ /* It's a first fragment */
+ if (udp_hdr->check == 0) {
+ BIH_DEBUG("bih: transalte: First fragment of UDP with zero checksum - packet droped\n");
+ BIH_DEBUG("bih: transalte: addr: %x src port: %d dst port: %d\n",
+ htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
+ lprintf(0,"transalte: First fragment of UDP with zero checksum - packet droped\n");
+ lprintf(0,"transalte: addr: %x src port: %d dst port: %d\n",
+ htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
+ return -1;
+ }
+ }
+ else if (udp_hdr->check == 0)
+ fl_csum = 1;
+ }
+
+ udp_hdr = (struct udphdr *)(dst+sizeof(struct ipv6hdr)
+ + fr_flag*sizeof(struct frag_hdr));
+ memcpy((char *)udp_hdr, src+hdr_len, len - hdr_len);
+
+ fl_csum=1;
+ if (fl_csum && (!include_flag)) {
+ if(ntohs(ih4->frag_off) == IP_DF||ih4->frag_off==0)
+ {
+ udp_hdr->check = 0;
+ csum = 0;
+ csum = csum_partial((unsigned char *)udp_hdr, plen - fr_flag*sizeof(struct frag_hdr), csum);
+ udp_hdr->check = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, plen -
+ fr_flag*sizeof(struct frag_hdr), IPPROTO_UDP, csum);
+ }
+ else if((ntohs(ih4->frag_off)&IP_OFFSET)==0&&(ntohs(ih4->frag_off)&IP_MF)!= 0)
+ udp_hdr->check = 0;
+#ifdef __BIHDEBUG__
+{
+ struct udp *udp=(struct udp *)udp_hdr;
+ ipv6_show(ih6);
+ udp_show(udp);
+ //array_show((unsigned char *)udp_hdr,len-hdr_len,1,16);
+}
+#endif
+ }
+ break;
+
+ /* Discard packets with any other protocol */
+ default:
+ BIH_DEBUG("bih: ip4_ip6(): Unknown upper protocol - packet dropped.\n");
+ lprintf(0,"ip4_ip6(): Unknown upper protocol - packet dropped.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int ip6_ip4(struct net_device *dev,char *src, int len, char *dst, int include_flag)/*v6 address be translated*/
+{
+ unsigned int srcaddr,dstaddr;
+ struct in6_addr addr6;
+ struct ipv6hdr *ip6_hdr=(struct ipv6hdr *)src;
+ struct iphdr *ip_hdr=(struct iphdr *)dst;
+ int opts_len = 0;
+ int icmperr = 1;
+ int ntot_len = 0;
+ int real_len;
+ int len_delta;
+ int ip6_payload_len;
+ int inc_opts_len = 0;
+ __u8 next_hdr;
+ int ret;
+ int addr_type;
+ struct map_node *mapnode;
+ struct udphdr *udp_hdr;
+ unsigned char proto=0;
+
+ BIH_DEBUG("bih: ip6_ip4 start\n");
+#if 0
+ //if it is the RA packet, let it go // test
+ //we dont care the linklocal addr translate
+ ret=ipv6_get_laddr(dev,&addr6);
+ if(ret!=0)
+ {
+ BIH_DEBUG("bih: ip4_ip6 get ipv6 laddr failed\n");
+ return(-1);
+ }
+ //if pkt dest ip is link local addr
+ if(memcmp(&ip6_hdr->daddr,&addr6,sizeof(struct in6_addr))!=0)
+ {
+ BIH_DEBUG("bih: ip4_ip6 the dest addr is the linklocal addr\n");
+ if(NEXTHDR_ICMP == ip6_hdr->nexthdr)
+ {
+ BIH_DEBUG("bih: ip4_ip6 the pkt is the icmpv6 pkt\n");
+ return -2;
+ }
+ }
+#endif
+ addr_type=ipv6_addr_type(&ip6_hdr->daddr);
+ ipv6_show(ip6_hdr);
+ if (addr_type&IPV6_ADDR_MULTICAST||
+ addr_type&IPV6_ADDR_LOOPBACK||
+ addr_type&IPV6_ADDR_LINKLOCAL||
+ addr_type&IPV6_ADDR_SITELOCAL)
+ {
+ BIH_DEBUG("bih: ip6_ip4 addr_type=%di return\n",addr_type);
+ return(-1);
+ }
+ addr_type=ipv6_addr_type(&ip6_hdr->saddr);
+ if(addr_type&IPV6_ADDR_LINKLOCAL||
+ addr_type&IPV6_ADDR_SITELOCAL)
+ {
+ BIH_DEBUG("bih: ip6_ip4 addr_type=%d exit\n",addr_type);
+ return(-1);
+ }
+
+ udp_hdr=(struct udphdr *)getipv6uppkg(src,&proto,NULL);
+ if(proto==NEXTHDR_UDP&&ntohs(udp_hdr->source)==53)
+ {
+ BIH_DEBUG("bih: ip6_ip4 dns pkt exit\n");
+ return(-1);
+ }
+ ret=ipv6_get_addr(dev,&addr6);
+ if(ret!=0)
+ {
+ BIH_DEBUG("bih: ip6_ip4 dns pkt exit\n");
+ return(-1);
+ }
+ ret=ipv4_get_addr(dev,&dstaddr);
+ if(ret!=0)
+ {
+ BIH_DEBUG("bih: ip6_ip4 get addr failed\n");
+ return(-1);
+ }
+ if(memcmp(&ip6_hdr->daddr,&addr6,sizeof(struct in6_addr))!=0)
+ {
+
+#ifdef __BIHDEBUG__
+ char dstbuf[64],locbuf[64];
+ inet_ntop6((unsigned char *)&ip6_hdr->daddr.s6_addr, dstbuf, sizeof(dstbuf)-1);
+ inet_ntop6((unsigned char *)&addr6.s6_addr, locbuf, sizeof(locbuf)-1);
+ lprintf(0,"Pkg dst(%s) will be forward\n",dstbuf,locbuf);
+ BIH_DEBUG("bih: Pkg dst(%s) will be forward\n",dstbuf,locbuf);
+#endif
+
+ BIH_DEBUG("bih: ip6_ip4 pkt will be forward\n");
+ return -1;
+ }
+
+ mapnode=map_find(ip6_hdr->saddr);
+ if(mapnode)
+ srcaddr=mapnode->id;
+
+ else
+ {
+ srcaddr=pool_addr_assign(&ip6_hdr->saddr);
+ if(srcaddr==0)
+ {
+ BIH_DEBUG(0,"pool_addr_assign error\n");
+ lprintf(0,"pool_addr_assign error\n");
+ return(-1);
+ }
+ mapnode=(struct map_node *)1;
+ }
+
+#ifdef __BIHDEBUG__
+ BIH_DEBUG("bih: ---------- %s ----------\n",mapnode?"466":"464");
+ lprintf(0,"---------- %s ----------\n",mapnode?"466":"464");
+ ipv6_show(ip6_hdr);
+#endif
+ if ( (len_delta = len - sizeof(struct ipv6hdr)) >= 0)
+ {
+ real_len = sizeof(struct iphdr);
+
+ ip_hdr->frag_off = 0;
+ ip_hdr->id = 0;
+
+ next_hdr = ip6_hdr->nexthdr;
+
+ if (next_hdr == NEXTHDR_HOP) {
+ if ( (len_delta - sizeof(struct ipv6_opt_hdr)) >= 0)
+ {
+ struct ipv6_opt_hdr *ip6h =
+ (struct ipv6_opt_hdr *)(src+sizeof(struct ipv6hdr) + opts_len);
+ if ( (len_delta -= ip6h->hdrlen*8 + 8) >= 0)
+ {
+ opts_len += ip6h->hdrlen*8 + 8;
+ next_hdr = ip6h->nexthdr;
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): hop_by_hop header error, packet droped\n");
+ lprintf(0,"ip6_ip4(): hop_by_hop header error, packet droped\n");
+ return -1;
+ }
+ }
+ }
+
+ if (len_delta > 0)
+ {
+ while(next_hdr != NEXTHDR_ICMP && next_hdr != NEXTHDR_TCP
+ && next_hdr != NEXTHDR_UDP)
+ {
+ /* Destination options header */
+ if (next_hdr == NEXTHDR_DEST)
+ {
+ if ( (len_delta - sizeof(struct ipv6_opt_hdr)) >= 0)
+ {
+ struct ipv6_opt_hdr *ip6d =
+ (struct ipv6_opt_hdr *)(src + sizeof(struct ipv6hdr) + opts_len);
+ if ( (len_delta -= ip6d->hdrlen*8 + 8) >= 0)
+ {
+ opts_len += ip6d->hdrlen*8 + 8;
+ next_hdr = ip6d->nexthdr;
+ }
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): destination header error, packet droped");
+ lprintf(0,"ip6_ip4(): destination header error, packet droped");
+ return -1;
+ }
+ }
+ else if (next_hdr == NEXTHDR_ROUTING)
+ {
+ if ( (len_delta - sizeof(struct ipv6_rt_hdr)) >= 0)
+ {
+ struct ipv6_rt_hdr *ip6rt =
+ (struct ipv6_rt_hdr *)(src+sizeof(struct ipv6hdr) + opts_len);
+ if (ip6rt->segments_left != 0) {
+ BIH_DEBUG("bih: ip6_ip4(): routing header type != 0\n");
+ lprintf(0,"ip6_ip4(): routing header type != 0\n");
+ return -1;
+ }
+ if ( (len_delta -= ip6rt->hdrlen*8 + 8) >= 0)
+ {
+ opts_len += ip6rt->hdrlen*8 + 8;
+ next_hdr = ip6rt->nexthdr;
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): routing header error, packet droped");
+ lprintf(0,"ip6_ip4(): routing header error, packet droped");
+ return -1;
+ }
+ }
+ }
+ else if (next_hdr == NEXTHDR_FRAGMENT)
+ {
+ if ( (len_delta -= sizeof(struct frag_hdr)) >= 0)
+ {
+ struct frag_hdr *ip6f =
+ (struct frag_hdr *)(src+sizeof(struct ipv6hdr)+opts_len);
+
+ opts_len += sizeof(struct frag_hdr); /* Frag Header Length = 8 */
+ ip_hdr->id = htons(ntohl(ip6f->identification)); /* ID field */
+ ip_hdr->frag_off = htons((ntohs(ip6f->frag_off) & IP6F_OFF_MASK) >> 3);
+ /* fragment offset */
+ ip_hdr->frag_off = htons(ntohs(ip_hdr->frag_off) |
+ ((ntohs(ip6f->frag_off) & IP6F_MORE_FRAG) << 13));
+ /* more fragments flag */
+ next_hdr = ip6f->nexthdr;
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): fragment header error, packet droped");
+ lprintf(0,"ip6_ip4(): fragment header error, packet droped");
+ return -1;
+ }
+ }
+ else if (next_hdr == NEXTHDR_NONE)
+ {
+ break;
+ }
+ else if (next_hdr == NEXTHDR_ESP || next_hdr == NEXTHDR_AUTH)
+ {
+ BIH_DEBUG("bih: ip6_ip4(): cannot translate AUTH or ESP extention header, packet dropped\n");
+ lprintf(0,"ip6_ip4(): cannot translate AUTH or ESP extention header, packet dropped\n");
+ return -1;
+ }
+ else if (next_hdr == NEXTHDR_IPV6)
+ {
+ BIH_DEBUG("bih: ip6_ip4(): cannot translate IPv6-IPv6 packet, packet dropped\n");
+ lprintf(0,"ip6_ip4(): cannot translate IPv6-IPv6 packet, packet dropped\n");
+ return -1;
+ }
+ else if (next_hdr == 0)
+ {
+ BIH_DEBUG("bih: ip6_ip4(): NEXTHDR in extention header = 0, packet dropped\n");
+ lprintf(0,"ip6_ip4(): NEXTHDR in extention header = 0, packet dropped\n");
+ return -1;
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): cannot translate extention header = %d, packet dropped\n", next_hdr);
+ lprintf(0,"ip6_ip4(): cannot translate extention header = %d, packet dropped\n", next_hdr);
+ return -1;
+ }
+ }
+ }
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): error packet len, packet dropped.\n");
+ lprintf(0,"ip6_ip4(): error packet len, packet dropped.\n");
+ return -1;
+ }
+
+ ip_hdr->version = IPVERSION;
+ ip_hdr->ihl = 5;
+
+ if (tos_ignore_flag)
+ ip_hdr->tos = 0;
+ else {
+ ip_hdr->tos = ip6_hdr->priority << 4;
+ ip_hdr->tos = ip_hdr->tos | (ip6_hdr->flow_lbl[0] >> 4);
+ }
+
+ ip6_payload_len = ntohs(ip6_hdr->payload_len);
+
+ if (ip6_payload_len == 0)
+ ntot_len = 0;
+ else
+ ntot_len = ip6_payload_len + IP4_IP6_HDR_DIFF - opts_len;
+
+ ip_hdr->tot_len = htons(ntot_len);
+ ip_hdr->ttl = ip6_hdr->hop_limit;
+ ip_hdr->protocol = next_hdr;
+
+ ip_hdr->saddr = srcaddr;
+ ip_hdr->daddr = dstaddr;
+
+ ip_hdr->check = 0;
+ ip_hdr->check = ip_fast_csum((unsigned char *)ip_hdr, ip_hdr->ihl);
+
+ if (len_delta > 0)
+ {
+ if (next_hdr == NEXTHDR_ICMP)
+ {
+ struct icmp6hdr *icmp6_hdr;
+ struct icmphdr *icmp_hdr;
+
+ if ((len_delta -= sizeof(struct icmp6hdr)) >= 0)
+ {
+ icmp6_hdr = (struct icmp6hdr *)(src + sizeof(struct ipv6hdr) + opts_len);
+ icmp_hdr = (struct icmphdr *)(dst + sizeof(struct iphdr));
+
+ real_len += len_delta + sizeof(struct icmphdr);
+
+ ip_hdr->protocol = IPPROTO_ICMP;
+
+ if (include_flag) {
+ if (icmp6_hdr->icmp6_type != ICMPV6_ECHO_REQUEST)
+ {
+ BIH_DEBUG("bih: ip6_ip4(): included ICMPv6 in ICMPv6 Error message, packet dropped\n");
+ lprintf(0,"ip6_ip4(): included ICMPv6 in ICMPv6 Error message, packet dropped\n");
+ return -1;
+ }
+ }
+
+ switch (icmp6_hdr->icmp6_type)
+ {
+ case ICMPV6_DEST_UNREACH: /* Type 1 */
+ icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
+ icmp_hdr->un.echo.id = 0;
+ icmp_hdr->un.echo.sequence = 0;
+ switch (icmp6_hdr->icmp6_code)
+ {
+ case ICMPV6_NOROUTE: /* Code 0 */
+ case ICMPV6_NOT_NEIGHBOUR: /* Code 2 */
+ case ICMPV6_ADDR_UNREACH: /* Code 3 */
+ icmp_hdr->code = ICMP_HOST_UNREACH; /* To Code 1 */
+ break;
+ case ICMPV6_ADM_PROHIBITED: /* Code 1 */
+ icmp_hdr->code = ICMP_HOST_ANO; /* To Code 10 */
+ break;
+ case ICMPV6_PORT_UNREACH: /* Code 4 */
+ icmp_hdr->code = ICMP_PORT_UNREACH; /* To Code 3 */
+
+ break;
+ default: /* discard any other codes */
+ BIH_DEBUG("bih: ip6_ip4(): Unknown ICMPv6 Type %d Code %d - packet dropped.\n",
+ ICMPV6_DEST_UNREACH, icmp6_hdr->icmp6_code);
+ lprintf(0,"ip6_ip4(): Unknown ICMPv6 Type %d Code %d - packet dropped.\n",
+ ICMPV6_DEST_UNREACH, icmp6_hdr->icmp6_code);
+ return -1;
+ }
+ break;
+ case ICMPV6_PKT_TOOBIG: /* Type 2 */
+ icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
+ icmp_hdr->code = ICMP_FRAG_NEEDED; /* to Code 4 */
+ icmp_hdr->un.frag.mtu = (__u16) icmp6_hdr->icmp6_mtu;
+ break;
+ case ICMPV6_TIME_EXCEED:
+ icmp_hdr->type = ICMP_TIME_EXCEEDED; /* to Type 11 */
+ icmp_hdr->code = icmp6_hdr->icmp6_code; /* Code unchanged */
+ break;
+ case ICMPV6_PARAMPROB:
+ switch (icmp6_hdr->icmp6_code) {
+ case ICMPV6_UNK_NEXTHDR: /* Code 1 */
+ icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
+ icmp_hdr->code = ICMP_PROT_UNREACH; /* to Code 2 */
+ break;
+ default: /* if Code != 1 */
+ icmp_hdr->type = ICMP_PARAMETERPROB; /* to Type 12 */
+ icmp_hdr->code = 0; /* to Code 0 */
+ switch (ntohl(icmp6_hdr->icmp6_pointer))
+ {
+ case 0: /* IPv6 Version -> IPv4 Version */
+ icmp_hdr->un.echo.id = 0;
+ break;
+ case 4: /* IPv6 PayloadLength -> IPv4 Total Length */
+ icmp_hdr->un.echo.id = 0x0002; /* 2 */
+ break;
+ case 6: /* IPv6 Next Header-> IPv4 Protocol */
+ icmp_hdr->un.echo.id = 0x0009; /* 9 */
+ break;
+ case 7: /* IPv6 Hop Limit -> IPv4 TTL */
+ icmp_hdr->un.echo.id = 0x0008; /* 8 */
+ break;
+ case 8: /* IPv6 Src addr -> IPv4 Src addr */
+ icmp_hdr->un.echo.id = 0x000c; /* 12 */
+ break;
+ case 24: /* IPv6 Dst addr -> IPv4 Dst addr*/
+ icmp_hdr->un.echo.id = 0x0010; /* 16 */
+ break;
+ default: /* set all ones in other cases */
+ icmp_hdr->un.echo.id = 0xff;
+ break;
+ }
+ break;
+ }
+ break;
+
+ case ICMPV6_ECHO_REQUEST:
+ icmperr = 0; /* not error ICMP message */
+ icmp_hdr->type = ICMP_ECHO; /* to Type 8 */
+ icmp_hdr->code = 0; /* to Code 0 */
+ icmp_hdr->un.echo.id = icmp6_hdr->icmp6_identifier;
+ icmp_hdr->un.echo.sequence = icmp6_hdr->icmp6_sequence;
+ if (len_delta > 0)
+ memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
+ ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
+ break;
+ case ICMPV6_ECHO_REPLY:
+ icmperr = 0; /* not error ICMP message */
+ icmp_hdr->type = ICMP_ECHOREPLY; /* to Type 0 */
+ icmp_hdr->code = 0; /* to Code 0 */
+ icmp_hdr->un.echo.id = icmp6_hdr->icmp6_identifier;
+ icmp_hdr->un.echo.sequence = icmp6_hdr->icmp6_sequence;
+ if (len_delta > 0)
+ memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
+ ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
+ break;
+ default:
+ BIH_DEBUG("bih: ip6_ip4(): unknown ICMPv6 Type %d, packet dropped.\n", icmp6_hdr->icmp6_type);
+ lprintf(0,"ip6_ip4(): unknown ICMPv6 Type %d, packet dropped.\n", icmp6_hdr->icmp6_type);
+ return -1;
+ }
+
+ if (icmperr)
+ {
+ if (len_delta >= sizeof(struct ipv6hdr))
+ {
+ if((inc_opts_len = ip6_ip4(dev,(char *)icmp6_hdr + sizeof(struct icmp6hdr), len_delta,
+ (char *)icmp_hdr + sizeof(struct icmphdr), 1)) == -1) {
+ BIH_DEBUG("bih: ip6_ip4(): incorrect translation of ICMPv6 Error message, packet dropped\n");
+ lprintf(0,"ip6_ip4(): incorrect translation of ICMPv6 Error message, packet dropped\n");
+ return -1;
+ }
+ if (ntot_len != 0)
+ ip_hdr->tot_len = htons(ntot_len - inc_opts_len - IP4_IP6_HDR_DIFF);
+ real_len = real_len - inc_opts_len - IP4_IP6_HDR_DIFF;
+ }
+ else if (len_delta > 0)
+ {
+ memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
+ ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
+ }
+ }
+
+ ip_hdr->check = 0;
+ ip_hdr->check = ip_fast_csum((unsigned char *)ip_hdr, ip_hdr->ihl);
+
+ if (ntot_len != 0)
+ {
+ icmp_hdr->checksum = 0;
+ icmp_hdr->checksum = ip_compute_csum((unsigned char *)icmp_hdr, ntohs(ip_hdr->tot_len)
+ - sizeof(struct iphdr));
+ }
+ }
+ else
+ {
+ BIH_DEBUG("bih: ip6_ip4(): error length ICMP packet, packet dropped.\n");
+ lprintf(0,"ip6_ip4(): error length ICMP packet, packet dropped.\n");
+ return -1;
+ }
+
+ }
+ else {
+ unsigned int csum;
+ struct udphdr *udp_hdr;
+ struct tcphdr *tcp_hdr;
+ real_len += len_delta;
+ memcpy(dst+sizeof(struct iphdr), src + sizeof(struct ipv6hdr) + opts_len, len_delta);
+ if (next_hdr == NEXTHDR_TCP)
+ {
+ tcp_hdr = (struct tcphdr *)(dst+sizeof(struct iphdr));
+ if(ntohs(ip_hdr->frag_off) == IP_DF||ip_hdr->frag_off==0)
+ {
+ tcp_hdr->check = 0;
+ csum = 0;
+ csum = csum_partial((unsigned char *)tcp_hdr, len_delta, csum);
+ tcp_hdr->check = csum_tcpudp_magic(ip_hdr->saddr, ip_hdr->daddr, len_delta, IPPROTO_TCP, csum);
+ }
+ else if((ntohs(ip_hdr->frag_off)&IP_OFFSET)==0&&(ntohs(ip_hdr->frag_off)&IP_MF)!= 0)
+ tcp_hdr->check = 0;
+#ifdef __BIHDEBUG__
+{
+ struct tcp *tcp=(struct tcp *)tcp_hdr;
+ struct ip *ip=(struct ip *)ip_hdr;
+ ip_show(ip);
+ tcp_show(tcp);
+}
+#endif
+ }
+ else if (next_hdr == NEXTHDR_UDP)
+ {
+ udp_hdr = (struct udphdr *)(dst+sizeof(struct iphdr));
+ if(ntohs(ip_hdr->frag_off) == IP_DF||ip_hdr->frag_off==0)
+ {
+ udp_hdr->check = 0;
+ csum = 0;
+ csum = csum_partial((unsigned char *)udp_hdr, len_delta, csum);
+ udp_hdr->check = csum_tcpudp_magic(ip_hdr->saddr, ip_hdr->daddr, len_delta, IPPROTO_UDP, csum);
+ }
+ else if((ntohs(ip_hdr->frag_off)&IP_OFFSET)==0&&(ntohs(ip_hdr->frag_off)&IP_MF)!= 0)
+ udp_hdr->check = 0;
+#ifdef __BIHDEBUG__
+{
+ struct udp *udp=(struct udp *)udp_hdr;
+ struct ip *ip=(struct ip *)ip_hdr;
+ ip_show(ip);
+ udp_show(udp);
+ //array_show(dst+sizeof(struct iphdr), len_delta,1,16);
+}
+#endif
+ }
+ }
+ }
+ if (include_flag)
+ return opts_len;
+ else
+ return real_len;
+}
+
+static int ip4_fragment(struct sk_buff *skb, int len, int hdr_len, struct net_device *dev)
+{
+ struct sk_buff *skb2 = NULL; /* pointer to new struct sk_buff for transleded packet */
+ char buff[FRAG_BUFF_SIZE+hdr_len]; /* buffer to form new fragment packet */
+ char *cur_ptr = skb->data+hdr_len; /* pointter to current packet data with len = frag_len */
+ struct iphdr *ih4 = (struct iphdr *) skb->data;
+ struct iphdr *new_ih4 = (struct iphdr *) buff; /* point to new IPv4 hdr */
+ struct ethhdr *new_eth_h; /* point to ether hdr, need to set hard header data in fragment */
+ int data_len = len - hdr_len; /* origin packet data len */
+ int rest_len = data_len; /* rest data to fragment */
+ int frag_len = 0; /* current fragment len */
+ int last_frag = 0; /* last fragment flag, if = 1, it's last fragment */
+ int flag_last_mf = 0;
+ int ret;
+ __u16 new_id = 0; /* to generate identification field */
+ __u16 frag_offset = 0; /* fragment offset */
+ unsigned int csum;
+ unsigned short udp_len;
+
+ BIH_DEBUG("bih: ip4_fragment start\n");
+ if ((ntohs(ih4->frag_off) & IP_MF) == 0 )
+ /* it's a case we'll clear MF flag in our last packet */
+ flag_last_mf = 1;
+
+ if (ih4->protocol == IPPROTO_UDP) {
+ if ( (ntohs(ih4->frag_off) & IP_OFFSET) == 0) {
+ struct udphdr *udp_hdr = (struct udphdr *)((char *)ih4 + hdr_len);
+ if (!flag_last_mf) {
+ if (udp_hdr->check == 0) {
+ /* it's a first fragment with ZERO checksum and we drop packet */
+ printk("translate: First fragment of UDP with zero checksum - packet droped\n");
+ printk("translate: addr: %x src port: %d dst port: %d\n",
+ htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
+ return -1;
+ }
+ }
+ else if (udp_hdr->check == 0) {
+ /* Calculate UDP checksum only if it's not fragment */
+ udp_len = ntohs(udp_hdr->len);
+ csum = 0;
+ csum = csum_partial((unsigned char *)udp_hdr, udp_len, csum);
+ udp_hdr->check = csum_tcpudp_magic(ih4->saddr, ih4->daddr, udp_len, IPPROTO_UDP, csum);
+ }
+ }
+ }
+ frag_offset = ntohs(ih4->frag_off) & IP_OFFSET;
+ new_id = ih4->id;
+ while(1) {
+ if (rest_len <= FRAG_BUFF_SIZE) {
+ /* it's last fragmen */
+ frag_len = rest_len; /* rest data */
+ last_frag = 1;
+ }
+ else
+ frag_len = FRAG_BUFF_SIZE;
+ /* copy IP header to buffer */
+ memcpy(buff, skb->data, hdr_len);
+ /* copy data to buffer with len = frag_len */
+ memcpy(buff + hdr_len, cur_ptr, frag_len);
+ /* set id field in new IPv4 header*/
+ new_ih4->id = new_id;
+ /* is it last fragmet */
+ if(last_frag && flag_last_mf)
+ /* clear MF flag */
+ new_ih4->frag_off = htons(frag_offset & (~IP_MF));
+ else
+ /* set MF flag */
+ new_ih4->frag_off = htons(frag_offset | IP_MF);
+ /* change packet total length */
+ new_ih4->tot_len = htons(frag_len+hdr_len);
+ /* rebuild the header checksum (IP needs it) */
+ new_ih4->check = 0;
+ new_ih4->check = ip_fast_csum((unsigned char *)new_ih4,new_ih4->ihl);
+ /* Allocate new sk_buff to compose translated packet */
+ skb2 = dev_alloc_skb(frag_len+hdr_len+dev->hard_header_len+IP4_IP6_HDR_DIFF+IP6_FRAGMENT_SIZE);
+ if (!skb2) {
+ printk(KERN_DEBUG "%s: alloc_skb failure - packet dropped.\n", dev->name);
+ dev_kfree_skb(skb2);
+ return -1;
+ }
+ skb_put(skb2, frag_len+hdr_len+dev->hard_header_len+IP4_IP6_HDR_DIFF+IP6_FRAGMENT_SIZE);
+ new_eth_h = (struct ethhdr *)skb2->data;
+ new_eth_h->h_proto = htons(ETH_P_IPV6);
+ skb_reset_mac_header(skb2);
+ skb_pull(skb2, dev->hard_header_len);
+ skb_reset_network_header(skb2);
+ skb2->protocol = htons(ETH_P_IPV6);
+ /* call translation function */
+ if ( ip4_ip6(dev,buff, frag_len+hdr_len, skb2->data, 0) == -1) {
+// lprintf(0,"ip4_ip6 error\n");
+ dev_kfree_skb(skb2);
+ return -1;
+ }
+ /*
+ * Set needed fields in new sk_buff
+ */
+ skb2->dev = dev;
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ skb2->pkt_type = PACKET_HOST;
+
+ /* send packet to upper layer */
+// ret=ipv6_rcv(skb2,dev,NULL,NULL);
+ ret=netif_rx(skb2);
+ if(ret!=0)
+ {
+ BIH_DEBUG("bih: ipv6_rcv error\n");
+ lprintf(0,"ipv6_rcv error\n");
+ dev_kfree_skb(skb2);
+ return -1;
+ }
+ /* exit if it was last fragment */
+ if (last_frag)
+ break;
+
+ /* correct current data pointer */
+ cur_ptr += frag_len;
+ /* rest data len */
+ rest_len -= frag_len;
+ /* current fragment offset */
+ frag_offset = (frag_offset*8 + frag_len)/8;
+ }
+ return 0;
+}
+
+int bih_xmit(struct sk_buff *skb,struct net_device *dev)
+{
+ struct sk_buff *skb2 = NULL, *skb3=NULL;
+ int ret,new_packet_len,len,skb_delta = 0;
+ static char *new_packet_buff;
+ struct ethhdr *eth_h;
+ struct in6_addr addr;
+
+ BIH_DEBUG("bih: bih_xmit start\n");
+ if (skb == NULL || dev==NULL)
+ {
+ return -1;
+ }
+/*
+ if(skb->dev==bihdev||BIHMODE!=1)
+ return(-1);
+*/
+ BIH_DEBUG("bih: bih_xmit get ipv6 addr start\n");
+ ret=ipv6_get_addr(dev,&addr);
+ if(ret!=0)
+ {
+#if 0 //test
+ BIH_DEBUG("bih: bih_xmit get ipv6 addr failed\n");
+ if(0 == ipv6_get_laddr(dev, &addr))
+ {
+ BIH_DEBUG("bih: bih_xmit get ipv6 linklocal addr success\n");
+ ret=netif_rx(skb);
+ if(ret!=0)
+ BIH_DEBUG("bih: bih_xmitip_rcv|ip6_rcv error(ret=%d)\n",ret);
+ else
+ kfree_skb(skb);
+ return(ret);
+ }
+#endif
+ BIH_DEBUG("bih: bih_xmit get ipv6 linklocal addr failed\n");
+ return(-1);
+ }
+ BIH_DEBUG("bih: bih_xmit get ipv6 addr end\n");
+
+ if(new_packet_buff==NULL)
+ {
+ new_packet_buff=kmalloc(2048,GFP_KERNEL);
+ if(new_packet_buff==NULL)
+ {
+ BIH_DEBUG("bih: kmalloc error\n");
+ lprintf(0,"kmalloc error\n");
+ return(-1);
+ }
+ }
+
+ dev->trans_start = jiffies;
+ if (ntohs(skb->protocol) == ETH_P_IP)
+ {
+ int hdr_len;
+ int data_len;
+ struct iphdr *ih4;
+ struct icmphdr *icmp_hdr;
+
+ BIH_DEBUG("bih: bih_xmit ip4\n");
+ ih4 = (struct iphdr *)skb->data; /* point to incoming packet's IPv4 header */
+ if (skb->len != ntohs(ih4->tot_len)) {
+ lprintf(0,"skb error\n");
+ BIH_DEBUG("bih: bih_xmit skb error");
+ return -1;
+ }
+ len = skb->len;
+ hdr_len = (int)(ih4->ihl * 4);
+ data_len = len - hdr_len;
+
+// if ( (ntohs(ih4->frag_off) & IP_DF) == 0 )
+ {
+ if ( data_len > FRAG_BUFF_SIZE )
+// if ( data_len > 1440 )
+ {
+ if(skb_is_nonlinear(skb))
+ {
+ skb3=skb_copy(skb, GFP_ATOMIC);
+ if(skb3)
+ {
+ skb3->sk=skb->sk;
+ }
+ }
+ else
+ skb3=skb;
+ len = skb3->len;
+ ret=ip4_fragment(skb3, len, hdr_len, dev);
+ if(skb3!=skb)
+ dev_kfree_skb(skb3);
+ if(ret==0)
+ dev_kfree_skb(skb);
+ BIH_DEBUG("bih: bih_xmit data_len=%d is bigger than FRAG_BUFF_SIZE(%d)", data_len, FRAG_BUFF_SIZE);
+ return ret;
+ }
+ }
+ if ( ntohs(ih4->frag_off) == IP_DF )
+ skb_delta = IP4_IP6_HDR_DIFF;
+ else
+ skb_delta = IP4_IP6_HDR_DIFF + IP6_FRAGMENT_SIZE;
+ if ( ih4->protocol == IPPROTO_ICMP) {
+ icmp_hdr = (struct icmphdr *) (skb->data+hdr_len);
+ if ( icmp_hdr->type != ICMP_ECHO && icmp_hdr->type != ICMP_ECHOREPLY) {
+ skb_delta += IP4_IP6_HDR_DIFF;
+ }
+ }
+ skb2 = dev_alloc_skb(len+dev->hard_header_len+skb_delta);
+ if (!skb2) {
+ lprintf(0,"dev_alloc_skb error\n");
+ BIH_DEBUG("bih: bih_xmit dev_alloc_skb failed\n");
+ return -1;
+ }
+ skb_put(skb2, len+dev->hard_header_len+skb_delta);
+ eth_h = (struct ethhdr *)skb2->data;
+ eth_h->h_proto = htons(ETH_P_IPV6);
+ skb_reset_mac_header(skb2);
+ skb_pull(skb2,dev->hard_header_len);
+// skb2->h.raw = skb2->nh.raw = skb2->data;
+ skb_reset_network_header(skb2);
+ skb2->protocol = htons(ETH_P_IPV6);
+
+ if(skb_is_nonlinear(skb))
+ {
+ skb3=skb_copy(skb, GFP_ATOMIC);
+ if(skb3)
+ {
+ skb3->sk=skb->sk;
+ }
+ }
+ else
+ skb3=skb;
+ if (ip4_ip6(dev,skb3->data, len, skb2->data, 0) == -1 ) {
+ if(skb3!=skb)
+ dev_kfree_skb(skb3);
+ dev_kfree_skb(skb2);
+ BIH_DEBUG("bih: bih_xmit ip4 to ip6 failed\n");
+ return -1;
+ }
+ if(skb3!=skb)
+ dev_kfree_skb(skb3);
+ skb2->dev = bihdev;
+ }
+ else if (ntohs(skb->protocol) == ETH_P_IPV6)
+ {
+ BIH_DEBUG("bih: bih_xmit ip6\n");
+ len = skb->len;
+ if(skb_is_nonlinear(skb))
+ {
+ skb3=skb_copy(skb, GFP_ATOMIC);
+ if(skb3)
+ {
+ skb3->sk=skb->sk;
+ }
+ }
+ else
+ skb3=skb;
+ new_packet_len = ip6_ip4(dev,skb3->data, len, new_packet_buff, 0);
+ if(new_packet_len==-1)
+ {
+ if(skb3!=skb)
+ dev_kfree_skb(skb3);
+ BIH_DEBUG("bih: bih_xmit ip6 to ip4 failed\n");
+ return(-1);
+ }
+#if 0
+ else if(new_packet_len=-2) //add
+ {
+ ret = netif_rx(skb3);
+ if(ret!=0)
+ BIH_DEBUG("bih: ip_rcv|ip6_rcv icmpv6 error(ret=%d)\n",ret);
+ else
+ kfree_skb(skb);
+ return(ret);
+ }
+#endif
+ if(skb3!=skb)
+ dev_kfree_skb(skb3);
+ skb2 = dev_alloc_skb(new_packet_len + dev->hard_header_len);
+ if (!skb2)
+ {
+ BIH_DEBUG("bih: dev_alloc_skb error\n");
+ lprintf(0,"dev_alloc_skb error\n");
+ return(-1);
+ }
+ skb_put(skb2, new_packet_len + dev->hard_header_len);
+ eth_h = (struct ethhdr *)skb2->data;
+ eth_h->h_proto = htons(ETH_P_IP);
+ skb_reset_mac_header(skb2);
+ skb_pull(skb2, dev->hard_header_len);
+ memcpy(skb2->data, new_packet_buff, new_packet_len);
+// skb2->h.raw = skb2->nh.raw = skb2->data;
+ skb_reset_network_header(skb2);
+ skb_reset_transport_header(skb2);
+ skb2->mac_len = skb2->network_header - skb2->mac_header;
+ skb2->protocol = htons(ETH_P_IP);
+ skb2->dev=skb->dev;
+ }
+ else {
+ BIH_DEBUG("bih: bih_xmit skb->protocol=%d exception\n",ntohs(skb->protocol));
+ return(-1);
+ }
+
+ skb2->pkt_type = PACKET_HOST;
+ skb2->dev = dev;
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ if (skb->sk)
+ skb_set_owner_w(skb2, skb->sk);
+
+ BIH_DEBUG("bih: send data to netif_rx\n");
+ ret=netif_rx(skb2);
+/*
+ if (ntohs(skb2->protocol) == ETH_P_IP)
+ ret=ip_rcv(skb2,dev,NULL,NULL);
+ else
+ ret=ipv6_rcv(skb2,dev,NULL,NULL);
+*/
+ if(ret!=0)
+ printk("bih: ip_rcv|ip6_rcv error(ret=%d)\n",ret);
+ else
+ kfree_skb(skb);
+ return(ret);
+}
diff --git a/drivers/net/bih/translate.h b/drivers/net/bih/translate.h
new file mode 100644
index 00000000..93840462
--- /dev/null
+++ b/drivers/net/bih/translate.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ *
+ */
+#ifndef _FANYI_H
+#define _FANYI_H
+#define FANYI_ETH 0
+
+#define BUFF_SIZE 4096
+#define FRAG_BUFF_SIZE 1232
+//#define FRAG_BUFF_SIZE 1400
+
+
+#define TRANSLATED_PREFIX 0x0000ffff
+#define MAPPED_PREFIX 0x0000ffff
+
+#define IP4_IP6_HDR_DIFF 20
+#define IP6_FRAGMENT_SIZE 8
+
+#define IP6F_OFF_MASK 0xfff8
+#define IP6F_RESERVED_MASK 0x0006
+#define IP6F_MORE_FRAG 0x0001
+
+struct ip6_opthdr
+{
+ unsigned char nxt;
+ unsigned char len;
+};
+
+struct ip6_hdr
+{
+ union
+ {
+ struct ip6_hdrctl
+ {
+ uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
+ 20 bits flow-ID */
+ uint16_t ip6_un1_plen; /* payload length */
+ uint8_t ip6_un1_nxt; /* next header */
+ uint8_t ip6_un1_hlim; /* hop limit */
+ } ip6_un1;
+ uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
+ } ip6_ctlun;
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+};
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+struct ipv6 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned char priority:4,version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned char version:4,priority:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ unsigned char flow_lbl[3];
+ unsigned short payload_len;
+ unsigned char nexthdr;
+ unsigned char hop_limit;
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+};
+
+struct ip
+{
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned int ip_hl:4; /*header length*/
+ unsigned int ip_v:4; /*version*/
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned int ip_v:4; /*version*/
+ unsigned int ip_hl:4; /*header length*/
+#endif
+ unsigned char ip_tos; /*type of service*/
+ unsigned short ip_len; /*total length*/
+ unsigned short ip_id; /*identification*/
+ unsigned short ip_off; /*fragment offset field*/
+#define IP_RF 0x8000 /*reserved fragment flag*/
+#define IP_DF 0x4000 /*dont fragment flag*/
+#define IP_MF 0x2000 /*more fragments flag*/
+#define IP_OFFMASK 0x1fff /*mask for fragmenting bits*/
+ unsigned char ip_ttl; /*time to live*/
+ unsigned char ip_p; /*protocol*/
+ unsigned short ip_sum; /*checksum*/
+ unsigned int ip_src,ip_dst;/*source and dest address*/
+}__attribute__((packed));
+
+struct tcp
+{
+ unsigned short sport; /*源端口*/
+ unsigned short dport; /*目的端口*/
+ unsigned int seq; /*标识TCP数据包的序列号*/
+ unsigned int ack_seq; /*确认序列号,表示接受方下一次接受的数据序列号*/
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned short res1:4;
+ unsigned short doff:4; /*TCP数据包首部长度,以4字节为单位,
+ 一般的时候为5*/
+ unsigned short fin:1; /*如果设置为1的时候,表示请求关闭连接*/
+ unsigned short syn:1; /*如果设置为1的时候,表示请求建立连接*/
+ unsigned short rst:1; /*如果设置为1的时候,表示请求重新连接*/
+ unsigned short psh:1; /*如果设置为1,那么接收方收到数据后,
+ 立即交给上一层程序*/
+ unsigned short ack:1; /*如果确认号正确则为1*/
+ unsigned short urg:1; /*如果设置紧急数据指针,则该位为1*/
+ unsigned short res2:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned short doff:4;
+ unsigned short res1:4;
+ unsigned short res2:2;
+ unsigned short urg:1;
+ unsigned short ack:1;
+ unsigned short psh:1;
+ unsigned short rst:1;
+ unsigned short syn:1;
+ unsigned short fin:1;
+#endif
+ unsigned short window; /*告诉接收者可以接收的大小*/
+ unsigned short check; /*TCP数据报校验*/
+ unsigned short urg_prt; /*如果urg=1,那么指出紧急数据
+ 对于历史数据开始的序列号的偏移值*/
+}__attribute__((packed));
+
+struct udp
+{
+ unsigned short sport;
+ unsigned short dport;
+ unsigned short len;
+ unsigned short check;
+}__attribute__((packed));
+
+#define lprintf(level,format,...) \
+do \
+{ \
+ if(level==0) \
+ printk("%s(%d)%s: "format,__FILE__,__LINE__,(char *)__FUNCTION__,##__VA_ARGS__ ); \
+ else \
+ printk((format),##__VA_ARGS__ ); \
+} \
+while(0)
+
+#define PKG_PUT_SHORT(val, cp) \
+do \
+{ \
+ unsigned short Xv; \
+ Xv = (unsigned short)(val); \
+ *(cp)++ = (unsigned char)(Xv >> 8); \
+ *(cp)++ = (unsigned char)Xv; \
+} \
+while(0)
+
+#endif
diff --git a/drivers/net/bih/voslist.c b/drivers/net/bih/voslist.c
new file mode 100644
index 00000000..7281c4fe
--- /dev/null
+++ b/drivers/net/bih/voslist.c
@@ -0,0 +1,835 @@
+/*
+ * 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>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+#include "voslist.h"
+int inet_pton4(char *src,unsigned char *dst);
+int inet_pton6(char *src,unsigned char *dst);
+char *inet_ntop4(unsigned char *src, char *dst, size_t size);
+char *inet_ntop6(unsigned char *src, char *dst, size_t size);
+unsigned int sk_inet_addr(char* ip_str);
+char *buff2String(char *buff,int bufflen);
+int msg_field2(char *linebuf,int linelen,int num,char **field,int *flen,char gech);
+void *vrealloc(void *ptr,int newsize,int oldsize,char freeflag);
+int listnode_tj(struct listnode *head);
+void *listnode_pop(struct listnode **head);
+int listnode_free(struct listnode *node,void (*func)(void *));
+int listnode_clear(struct listnode **head,void (*func)(void *));
+void listnode_show(struct listnode *head);
+struct listnode *listnode_find(struct listnode *head,unsigned int key);
+struct listnode *listnode_search(struct listnode *head,void *data,int len,int (*func)(void *,void *,int));
+struct listnode *listnode_match(struct listnode *head,void *data,int len,int (*func)(void *,void *,int));
+int listnode_insert(struct listnode **head,struct listnode *node);
+struct listnode *listnode_uninsert(struct listnode **head,struct listnode *node);
+struct listnode *listnode_uninsert2(struct listnode **head,unsigned int key);
+struct listnode *listnode_add(struct listnode **head,unsigned int key,void *data,int datalen);
+int listnode_del(struct listnode **head,unsigned int key,void (*func)(void *));
+struct listnode *listnode_tail(struct listnode **head,void *data,int datalen);
+int listnode_join(struct listnode **head,struct listnode **list);
+
+int inet_pton4(char *src,unsigned char *dst) /*The "dotted decimal" -> "integer"*/
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[4], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, 4);
+ return (1);
+}
+
+int inet_pton6(char *src,unsigned char *dst) /*The "dotted hex" -> "integer"*/
+{
+ static char xdigits_l[] = "0123456789abcdef",xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[16], *tp, *endp, *colonp;
+ char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', 16);
+ endp = tp + 16;
+ colonp = NULL;
+
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + 2 > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + 4) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += 4;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + 2 > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, 16);
+ return (1);
+}
+
+char *inet_ntop4(unsigned char *src, char *dst, size_t size) /*The "integer" -> "dotted decimal"*/
+{
+ static const char *fmt = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+ if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size)
+ {
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+char *inet_ntop6(unsigned char *src, char *dst, size_t size) /*The "integer" -> "dotted hex"*/
+{
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[16 / 2];
+ int i;
+
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < 16; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len=0;
+ cur.base = -1;
+ cur.len=0;
+ for (i = 0; i < (16 / 2); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ tp = tmp;
+ for (i = 0; i < (16 / 2); i++) {
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ if (i != 0)
+ *tp++ = ':';
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp,
+ sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ if (best.base != -1 && (best.base + best.len) ==
+ (16 / 2))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ if ((size_t)(tp - tmp) > size) {
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+unsigned int sk_inet_addr(char* ip_str) /*Interval of a point into a in_addr address*/
+{
+ unsigned int ip = 0;
+ unsigned char *p=(unsigned char *)&ip;
+ unsigned int a1, a2, a3, a4;
+
+ if(ip_str==NULL||!strcasecmp(ip_str,"ANY")||!strcmp(ip_str,"0"))
+ {
+ ip=((unsigned long int) 0x00000000);
+ return(ip);
+ }
+ sscanf(ip_str, "%d.%d.%d.%d", &a1, &a2, &a3, &a4);
+ *p=a1;
+ *(p+1)=a2;
+ *(p+2)=a3;
+ *(p+3)=a4;
+ return ip;
+}
+
+char *buff2String(char *buff,int bufflen)
+{
+ static char *tmpbuf;
+ int len;
+ if(buff==NULL)
+ return(NULL);
+ if(tmpbuf)
+ vfree(tmpbuf);
+ if(bufflen<=0)
+ len=strlen(buff);
+ else
+ len=bufflen;
+ tmpbuf=(char *)vmalloc(len+1);
+ if(tmpbuf==NULL)
+ return(NULL);
+ tmpbuf[len]=0;
+ memcpy(tmpbuf,buff,len);
+ return(tmpbuf);
+}
+
+int msg_field2(char *linebuf,int linelen,int num,char **field,int *flen,char gech)
+{
+ char *lineend,*fieldstart=linebuf,*fieldend,numflag;
+ int fieldlen,i,yhnum,xyhnum,khnum;
+
+ if(linebuf==NULL||linelen<=0||(num>=0&&field==NULL))
+ return(-1);
+ if(gech=='\t')
+ gech=' ';
+ lineend=linebuf+linelen;
+ for(i=0;i<linelen;i++)
+ if(*(linebuf+i)=='\t')
+ *(linebuf+i)=' ';
+ while(*fieldstart==gech)
+ fieldstart++;
+ if(*fieldstart==0)
+ {
+ if(num<0)
+ {
+ return(0);
+ }
+ else
+ {
+ *field=NULL;
+ if(flen)
+ *flen=0;
+ return(-1);
+ }
+ }
+ if(num<0)
+ {
+ numflag=1;
+ num=1000;
+ }
+ else
+ numflag=0;
+ while(num>0)
+ {
+// fieldend=strchr(fieldstart,gech);
+ fieldend=memchr(fieldstart,gech,lineend-fieldstart);
+ if(fieldend==NULL)
+ {
+ if(numflag)
+ {
+ return(1000-num+1);
+ }
+ else
+ {
+ *field=NULL;
+ if(flen)
+ *flen=0;
+ return(-1);
+ }
+ }
+ for(i=1,yhnum=0,xyhnum=0,khnum=0;i<fieldend-fieldstart;i++)
+ {
+ if(fieldstart[i]=='"')
+ {
+ if(fieldstart[i-1]!='\\')
+ yhnum++;
+ else
+ if(!(yhnum%2))
+ xyhnum++;
+ }
+ else if(fieldstart[i]=='(')
+ khnum++;
+ else if(fieldstart[i]==')')
+ khnum--;
+ }
+ if(fieldstart[0]=='"')
+ yhnum++;
+ else if(fieldstart[0]=='(')
+ khnum++;
+ else if(fieldstart[0]==')')
+ khnum--;
+ while((yhnum%2)||(xyhnum%2)||(khnum))
+ {
+ while(*++fieldend==gech);
+// fieldend=strchr(fieldend,gech);
+ fieldend=memchr(fieldend,gech,lineend-fieldend);
+ if(fieldend==NULL)
+ {
+ if(numflag)
+ {
+ return(1000-num+1);
+ }
+ else
+ {
+ *field=NULL;
+ if(flen)
+ *flen=0;
+ return(-1);
+ }
+ }
+ for(i=1,yhnum=0,xyhnum=0,khnum=0;i<fieldend-fieldstart;i++)
+ {
+ if(fieldstart[i]=='"')
+ {
+ if(fieldstart[i-1]!='\\')
+ yhnum++;
+ else
+ if(!(yhnum%2))
+ xyhnum++;
+ }
+ else if(fieldstart[i]=='(')
+ khnum++;
+ else if(fieldstart[i]==')')
+ khnum--;
+ }
+ if(fieldstart[0]=='"')
+ yhnum++;
+ else if(fieldstart[0]=='(')
+ khnum++;
+ else if(fieldstart[0]==')')
+ khnum--;
+ }
+ while(*++fieldend==gech&&fieldend<lineend);
+ fieldstart=fieldend;
+ if(fieldstart>=lineend)
+ {
+ if(numflag)
+ return(1000-num+1);
+ else
+ {
+ *field=NULL;
+ if(flen)
+ *flen=0;
+ return(-1);
+ }
+ }
+ num--;
+ }
+// fieldend=strchr(fieldstart,gech);
+ fieldend=memchr(fieldstart,gech,lineend-fieldstart);
+ if(fieldend!=NULL)
+ {
+ for(i=1,yhnum=0,xyhnum=0,khnum=0;i<fieldend-fieldstart;i++)
+ {
+ if(fieldstart[i]=='"')
+ {
+ if(fieldstart[i-1]!='\\')
+ yhnum++;
+ else
+ if(!(yhnum%2))
+ xyhnum++;
+ }
+ else if(fieldstart[i]=='(')
+ khnum++;
+ else if(fieldstart[i]==')')
+ khnum--;
+ }
+ if(fieldstart[0]=='"')
+ yhnum++;
+ else if(fieldstart[0]=='(')
+ khnum++;
+ else if(fieldstart[0]==')')
+ khnum--;
+ while((yhnum%2)||(xyhnum%2)||(khnum))
+ {
+ while(*++fieldend==gech);
+// fieldend=strchr(fieldend,gech);
+ fieldend=memchr(fieldend,gech,lineend-fieldend);
+ if(fieldend==NULL)
+ {
+ fieldend=&fieldstart[strlen(fieldstart)];
+ break;
+ }
+ for(i=1,yhnum=0,xyhnum=0,khnum=0;i<fieldend-fieldstart;i++)
+ {
+ if(fieldstart[i]=='"')
+ {
+ if(fieldstart[i-1]!='\\')
+ yhnum++;
+ else
+ if(!(yhnum%2))
+ xyhnum++;
+ }
+ else if(fieldstart[i]=='(')
+ khnum++;
+ else if(fieldstart[i]==')')
+ khnum--;
+ }
+ if(fieldstart[0]=='"')
+ yhnum++;
+ else if(fieldstart[0]=='(')
+ khnum++;
+ else if(fieldstart[0]==')')
+ khnum--;
+ }
+ }
+ else
+ fieldend=&fieldstart[strlen(fieldstart)];
+ if(fieldend>linebuf+linelen)
+ fieldend=linebuf+linelen;
+ fieldlen=fieldend-fieldstart;
+ if(!fieldlen)
+ {
+ *field=NULL;
+ if(flen)
+ *flen=0;
+ return(-1);
+ }
+ if(flen)
+ {
+ *field=fieldstart;
+ *flen=fieldlen;
+ return(0);
+ }
+ else
+ {
+ char *retbuf;
+ retbuf=vmalloc(fieldlen+1);
+ if(retbuf)
+ {
+ memcpy(retbuf,fieldstart,fieldlen);
+ retbuf[fieldlen]=0;
+ *field=retbuf;
+ return(0);
+ }
+ else
+ return(-1);
+ }
+}
+
+void *vrealloc(void *ptr,int newsize,int oldsize,char freeflag)
+{
+ void *p=vmalloc(newsize);
+ if(ptr&&p)
+ {
+ memcpy(p, ptr,((oldsize < newsize) ? oldsize : newsize));
+ }
+ if(ptr&&freeflag)
+ vfree(ptr);
+ return p;
+}
+
+int listnode_tj(struct listnode *head)
+{
+ int num;
+ for(num=0;head;head=head->next,num++);
+ return(num);
+}
+
+void *listnode_pop(struct listnode **head)
+{
+ struct listnode *node;
+ void *data;
+ node=*head;
+ if(node==NULL)
+ return(NULL);
+ *head=node->next;
+ if(*head)
+ (*head)->prev=NULL;
+ data=node->data;
+ vfree(node);
+ return(data);
+}
+
+int listnode_free(struct listnode *node,void (*func)(void *))
+{
+ if(node==NULL)
+ return(0);
+ if(node->data&&func)
+ {
+ func(node->data);
+ }
+ vfree(node);
+ return(0);
+}
+
+int listnode_clear(struct listnode **head,void (*func)(void *))
+{
+ struct listnode *node;
+ if(head==NULL)
+ return(-1);
+ if(*head==(void *)-1)
+ {
+ *head=NULL;
+ return(0);
+ }
+ for(node=*head;node;node=*head)
+ {
+ *head=node->next;
+ listnode_free(node,func);
+ }
+ return(0);
+}
+
+void listnode_show(struct listnode *head)
+{
+ lprintf(5,"LIST(%d):",listnode_tj(head));
+ while(head)
+ {
+ lprintf(5," %u",head->key);
+ head=head->next;
+ }
+ lprintf(5,"\n");
+ return;
+}
+
+struct listnode *listnode_find(struct listnode *head,unsigned int key)
+{
+ struct listnode *trace=head;
+ if(head==NULL||head==(void *)-1)
+ return(NULL);
+ while(trace)
+ {
+ if(trace->key==key)
+ return(trace);
+ else if(trace->key>key)
+ return(NULL);
+ trace=trace->next;
+ }
+ return(NULL);
+}
+
+struct listnode *listnode_search(struct listnode *head,void *data,int len,int (*func)(void *,void *,int))
+{
+ struct listnode *trace=head;
+ if(head==NULL||head==(void *)-1)
+ return(NULL);
+ while(trace)
+ {
+ if(func==NULL)
+ {
+ if(trace->data==data)
+ return(trace);
+ else
+ trace=trace->next;
+ }
+ else
+ {
+ if(trace->datalen==len&&func(trace->data,data,len)==0)
+ return(trace);
+ else
+ trace=trace->next;
+ }
+ }
+ return(NULL);
+}
+
+struct listnode *listnode_match(struct listnode *head,void *data,int len,int (*func)(void *,void *,int))
+{
+ struct listnode *trace=head;
+ if(head==NULL||head==(void *)-1)
+ return(NULL);
+ while(trace)
+ {
+ if(func==NULL)
+ {
+ if(trace->data==data)
+ return(trace);
+ else
+ trace=trace->next;
+ }
+ else
+ {
+ if(trace->datalen>=len&&func(trace->data,data,len)==0)
+ return(trace);
+ else
+ trace=trace->next;
+ }
+ }
+ return(NULL);
+}
+
+int listnode_insert(struct listnode **head,struct listnode *node)
+{
+ struct listnode *trace=*head,*ptrace=NULL;
+ if(node==NULL)
+ {
+ lprintf(0,"argument error\n");
+ return(-1);
+ }
+ if(trace==(void *)-1)
+ trace=NULL;
+ while(trace)
+ {
+ if(trace->key==node->key)
+ {
+ return(-1);
+ }
+ else if(trace->key<node->key)
+ {
+ ptrace=trace;
+ trace=trace->next;
+ }
+ else
+ {
+ node->next=trace;
+ trace->prev=node;
+ break;
+ }
+ }
+ if(ptrace)
+ {
+ ptrace->next=node;
+ node->prev=ptrace;
+ }
+ else
+ {
+ node->prev=NULL;
+ *head=node;
+ }
+ return(0);
+}
+
+struct listnode *listnode_uninsert(struct listnode **head,struct listnode *node)
+{
+ if(head==NULL||node==NULL)
+ return(NULL);
+ if(node->prev)
+ node->prev->next=node->next;
+ else
+ *head=node->next;
+ if(node->next)
+ node->next->prev=node->prev;
+ return(node);
+}
+
+struct listnode *listnode_uninsert2(struct listnode **head,unsigned int key)
+{
+ struct listnode *node;
+ if(head==NULL)
+ return(NULL);
+ node=listnode_find(*head,key);
+ if(node==NULL)
+ return(NULL);
+ return(listnode_uninsert(head,node));
+}
+
+struct listnode *listnode_add(struct listnode **head,unsigned int key,void *data,int datalen)
+{
+ struct listnode *node;
+
+ node=listnode_find(*head,key);
+ if(node)
+ {
+ if(node->data)
+ return((struct listnode *)-1);
+ else
+ {
+ node->data=data;
+ node->datalen=datalen;
+ node->datasp=0;
+ return(node);
+ }
+ }
+ node=(struct listnode *)vmalloc(sizeof(struct listnode));
+ if(node==NULL)
+ {
+ lprintf(0,"vmalloc error\n");
+ return(NULL);
+ }
+ memset(node,0,sizeof(struct listnode));
+ node->key=key;
+ node->data=data;
+ node->datalen=datalen;
+ node->datasp=0;
+ if(!listnode_insert(head,node))
+ return(node);
+ else
+ {
+ vfree(node);
+ return(NULL);
+ }
+}
+
+int listnode_del(struct listnode **head,unsigned int key,void (*func)(void *))
+{
+ struct listnode *node;
+ node=listnode_find(*head,key);
+ if(node==NULL)
+ return(-1);
+ listnode_uninsert(head,node);
+ listnode_free(node,func);
+ return(0);
+}
+
+struct listnode *listnode_tail(struct listnode **head,void *data,int datalen)
+{
+ struct listnode *node;
+ static int num=0;
+
+ node=(struct listnode *)vmalloc(sizeof(struct listnode));
+ if(node==NULL)
+ {
+ lprintf(0,"vmalloc error\n");
+ return(NULL);
+ }
+ memset(node,0,sizeof(struct listnode));
+ node->key=num++;
+ node->data=data;
+ node->datalen=datalen;
+ node->datasp=0;
+ if(!listnode_insert(head,node))
+ return(node);
+ else
+ {
+ vfree(node);
+ return(NULL);
+ }
+}
+
+int listnode_join(struct listnode **head,struct listnode **list)
+{
+ struct listnode *newlist=NULL,*lhead,*node;
+ if(head==NULL||list==NULL)
+ {
+ return(-1);
+ }
+ if(*head==NULL)
+ {
+ *head=*list;
+ return(0);
+ }
+ if(*list==NULL)
+ return(0);
+ lhead=*list;
+ while(lhead)
+ {
+ node=lhead;
+ lhead=lhead->next;
+ if(listnode_insert(head,node)!=0)
+ listnode_insert(&newlist,node);
+ }
+ *list=newlist;
+ return(0);
+}
+
+#if 0
+int main(void)
+{
+ struct listnode *head=NULL;
+ int i;
+
+ for(i=0;i<32;i++)
+ listnode_add(&head,randshu(0,100),NULL);
+ listnode_show(head);
+}
+#endif
+
diff --git a/drivers/net/bih/voslist.h b/drivers/net/bih/voslist.h
new file mode 100644
index 00000000..45e5584d
--- /dev/null
+++ b/drivers/net/bih/voslist.h
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ */
+#ifndef _VOSLIST_H
+#define _VOSLIST_H
+enum _listnode_status
+{
+ LISTNODE_STATUS_ENABLE,
+ LISTNODE_STATUS_DISABLE
+};
+
+struct listnode
+{
+ struct listnode *next;
+ struct listnode *prev;
+ unsigned int key;
+ char status;
+ void *data;
+ int datalen;
+ unsigned int datasp;
+};
+
+#define SHOW2BUF_DEF \
+ static char buff[1000],*p = NULL; \
+ int ret,len,size; \
+
+#define SHOW2BUF_INIT() \
+do \
+{ \
+ ret=0; \
+ if(p&&p!=buff) \
+ vfree(p); \
+ size=sizeof(buff)-1; \
+ len=0; \
+ buff[0]=0; \
+ p=buff; \
+} \
+while(0)
+
+#define SHOW2BUF_RET return(p)
+
+#define SHOW2BUF(format,...) \
+do \
+{ \
+ ret=snprintf(p+len,size-len,format,##__VA_ARGS__); \
+ if (ret < 0 || ret >= (size-len)) \
+ { \
+ while (1) \
+ { \
+ p=vrealloc(p,2*size+1,size,p!=buff); \
+ if(!p) \
+ { \
+ lprintf(0,"vrealloc error\n"); \
+ break; \
+ } \
+ size*=2; \
+ ret=snprintf(p+len,size-len,format,##__VA_ARGS__); \
+ if (ret > -1 && ret < (size-len)) \
+ break; \
+ } \
+ } \
+ len+=ret; \
+ if(p) \
+ *(p+len)=0; \
+} \
+while(0)
+
+#define lprintf(level,format,...) \
+do \
+{ \
+ if(level==0) \
+ printk("%s(%d)%s: "format,__FILE__,__LINE__,(char *)__FUNCTION__,##__VA_ARGS__ ); \
+ else \
+ printk((format),##__VA_ARGS__ ); \
+} \
+while(0)
+#define vmalloc(size) kmalloc((size),GFP_KERNEL)
+#define vfree kfree
+
+#define PKG_GET_STRING(val, cp) \
+do \
+{ \
+ while(*(cp)) \
+ *(val)++=*(cp)++; \
+ *(val)++=0; \
+} \
+while(0)
+
+#define PKG_GET_BYTE(val, cp) ((val) = *(cp)++)
+
+#define PKG_GET_SHORT(val, cp) \
+do \
+{ \
+ unsigned short Xv; \
+ Xv = (*(cp)++) << 8; \
+ Xv |= *(cp)++; \
+ (val) = Xv; \
+} \
+while(0)
+
+#define PKG_GET_NETSHORT(val, cp) \
+do \
+{ \
+ unsigned char *Xvp; \
+ unsigned short Xv; \
+ Xvp = (unsigned char *) &Xv; \
+ *Xvp++ = *(cp)++; \
+ *Xvp++ = *(cp)++; \
+ (val) = Xv; \
+} \
+while(0)
+
+#define PKG_GET_LONG(val, cp) \
+do \
+{ \
+ unsigned long Xv; \
+ Xv = (*(cp)++) << 24; \
+ Xv |= (*(cp)++) << 16; \
+ Xv |= (*(cp)++) << 8; \
+ Xv |= *(cp)++; \
+ (val) = Xv; \
+} \
+while(0)
+
+#define PKG_GET_NETLONG(val, cp) \
+do \
+{ \
+ unsigned char *Xvp; \
+ unsigned long Xv; \
+ Xvp = (unsigned char *) &Xv; \
+ *Xvp++ = *(cp)++; \
+ *Xvp++ = *(cp)++; \
+ *Xvp++ = *(cp)++; \
+ *Xvp++ = *(cp)++; \
+ (val) = Xv; \
+} \
+while(0)
+
+#define PKG_PUT_BUF(val, len, cp) \
+do \
+{ \
+ memcpy((cp),(val),(len)); \
+ (cp)+=(len); \
+} \
+while(0)
+
+#define PKG_PUT_STRING(val, cp) \
+do \
+{ \
+ while(*(val)) \
+ *(cp)++=*(val)++; \
+ *(cp)++=0; \
+} \
+while(0)
+
+#define PKG_PUT_BYTE(val, cp) (*(cp)++ = (unsigned char)(val))
+
+#define PKG_PUT_SHORT(val, cp) \
+do \
+{ \
+ unsigned short Xv; \
+ Xv = (unsigned short)(val); \
+ *(cp)++ = (unsigned char)(Xv >> 8); \
+ *(cp)++ = (unsigned char)Xv; \
+} \
+while(0)
+
+#define PKG_PUT_NETSHORT(val, cp) \
+do \
+{ \
+ unsigned char *Xvp; \
+ unsigned short Xv = (unsigned short)(val); \
+ Xvp = (unsigned char *)&Xv; \
+ *(cp)++ = *Xvp++; \
+ *(cp)++ = *Xvp++; \
+} \
+while(0)
+
+#define PKG_PUT_LONG(val, cp) \
+do \
+{ \
+ unsigned long Xv; \
+ Xv = (unsigned long)(val); \
+ *(cp)++ = (unsigned char)(Xv >> 24); \
+ *(cp)++ = (unsigned char)(Xv >> 16); \
+ *(cp)++ = (unsigned char)(Xv >> 8); \
+ *(cp)++ = (unsigned char)Xv; \
+} \
+while(0)
+
+#define PKG_PUT_NETLONG(val, cp) \
+do \
+{ \
+ unsigned char *Xvp; \
+ unsigned long Xv = (unsigned long)(val); \
+ Xvp = (unsigned char *)&Xv; \
+ *(cp)++ = *Xvp++; \
+ *(cp)++ = *Xvp++; \
+ *(cp)++ = *Xvp++; \
+ *(cp)++ = *Xvp++; \
+} \
+while(0)
+
+int inet_pton4(char *src,unsigned char *dst);
+int inet_pton6(char *src,unsigned char *dst);
+char *inet_ntop4(unsigned char *src, char *dst, size_t size);
+char *inet_ntop6(unsigned char *src, char *dst, size_t size);
+unsigned int sk_inet_addr(char* ip_str);
+char *buff2String(char *buff,int bufflen);
+int msg_field2(char *linebuf,int linelen,int num,char **field,int *flen,char gech);
+void *vrealloc(void *ptr,int newsize,int oldsize,char freeflag);
+int listnode_tj(struct listnode *head);
+void *listnode_pop(struct listnode **head);
+int listnode_free(struct listnode *node,void (*func)(void *));
+int listnode_clear(struct listnode **head,void (*func)(void *));
+void listnode_show(struct listnode *head);
+struct listnode *listnode_find(struct listnode *head,unsigned int key);
+struct listnode *listnode_search(struct listnode *head,void *data,int len,int (*func)(void *,void *,int));
+struct listnode *listnode_match(struct listnode *head,void *data,int len,int (*func)(void *,void *,int));
+int listnode_insert(struct listnode **head,struct listnode *node);
+struct listnode *listnode_uninsert(struct listnode **head,struct listnode *node);
+struct listnode *listnode_uninsert2(struct listnode **head,unsigned int key);
+struct listnode *listnode_add(struct listnode **head,unsigned int key,void *data,int datalen);
+int listnode_del(struct listnode **head,unsigned int key,void (*func)(void *));
+struct listnode *listnode_tail(struct listnode **head,void *data,int datalen);
+int listnode_join(struct listnode **head,struct listnode **list);
+
+#endif