diff options
Diffstat (limited to 'drivers/net/bih')
| -rw-r--r-- | drivers/net/bih/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/net/bih/Makefile | 3 | ||||
| -rw-r--r-- | drivers/net/bih/bih_module.c | 1068 | ||||
| -rw-r--r-- | drivers/net/bih/config.sh | 34 | ||||
| -rw-r--r-- | drivers/net/bih/map.c | 351 | ||||
| -rw-r--r-- | drivers/net/bih/map.h | 50 | ||||
| -rw-r--r-- | drivers/net/bih/pool.c | 283 | ||||
| -rw-r--r-- | drivers/net/bih/pool.h | 34 | ||||
| -rw-r--r-- | drivers/net/bih/translate.c | 1585 | ||||
| -rw-r--r-- | drivers/net/bih/translate.h | 176 | ||||
| -rw-r--r-- | drivers/net/bih/voslist.c | 835 | ||||
| -rw-r--r-- | drivers/net/bih/voslist.h | 249 |
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 |
