git-svn-id: http://svn.eurecom.fr/openair4G/trunk@6273 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
@@ -50,14 +50,22 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PARAM_ACTION = 1 << 0,
|
PARAM_LADDR = 1 << 0,
|
||||||
|
PARAM_LTUN = 1 << 1,
|
||||||
|
PARAM_RADDR = 1 << 2,
|
||||||
|
PARAM_RTUN = 1 << 3,
|
||||||
|
PARAM_ACTION = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void GTPURH_help(void)
|
static void GTPURH_help(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"GTPURH target options\n"
|
"GTPUAH target options\n"
|
||||||
" --action value Set action <value: remove>\n");
|
" --action value Set action <value: remove>\n"
|
||||||
|
" --own-ip value Set own IP address\n"
|
||||||
|
" --own-tun value Set own tunnel id <value: 1-2^31>\n"
|
||||||
|
" --peer-ip value Set peer IP address\n"
|
||||||
|
" --peer-tun value Set peer tunnel id <value: 1-2^31>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (IPTVERSION <= 135)
|
#if (IPTVERSION <= 135)
|
||||||
@@ -97,17 +105,63 @@ void gtpurh_param_act(unsigned int status, const char *p1, ...)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void parse_gtpurh_addr(const char *s, struct xt_gtpurh_target_info *info, int flag)
|
||||||
|
{
|
||||||
|
in_addr_t addr;
|
||||||
|
|
||||||
|
if ((addr = inet_addr(s)) == -1) {
|
||||||
|
switch (flag) {
|
||||||
|
case PARAM_LADDR:
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--own-ip", s);
|
||||||
|
break;
|
||||||
|
case PARAM_RADDR:
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--peer-ip", s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (flag) {
|
||||||
|
case PARAM_LADDR:
|
||||||
|
info->laddr = addr;
|
||||||
|
break;
|
||||||
|
case PARAM_RADDR:
|
||||||
|
info->raddr = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_gtpurh_tunid(char *s, struct xt_gtpurh_target_info *info, int flag)
|
||||||
|
{
|
||||||
|
unsigned int value;
|
||||||
|
|
||||||
|
if (!gtpurh_strtoui(s, &value, 0, UINT32_MAX)) {
|
||||||
|
switch (flag) {
|
||||||
|
case PARAM_LTUN:
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--own-tun", s);
|
||||||
|
break;
|
||||||
|
case PARAM_RTUN:
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--peer-tun", s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (flag) {
|
||||||
|
case PARAM_LTUN:
|
||||||
|
info->ltun = value;
|
||||||
|
break;
|
||||||
|
case PARAM_RTUN:
|
||||||
|
info->rtun = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void parse_gtpurh_action(char *s, struct xt_gtpurh_target_info *info, unsigned int *flags)
|
static void parse_gtpurh_action(char *s, struct xt_gtpurh_target_info *info, unsigned int *flags)
|
||||||
{
|
{
|
||||||
if (!strcmp(s, "remove"))
|
if (!strcmp(s, "remove")) {
|
||||||
{
|
|
||||||
info->action = PARAM_GTPURH_ACTION_REM;
|
info->action = PARAM_GTPURH_ACTION_REM;
|
||||||
*flags |= PARAM_GTPURH_ACTION_REM;
|
*flags |= PARAM_GTPURH_ACTION_REM;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--action", s);
|
gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--action", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,10 +182,30 @@ GTPURH_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '1':
|
case '1':
|
||||||
gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--action", *flags & PARAM_ACTION);
|
gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--own-ip", *flags & PARAM_LADDR);
|
||||||
parse_gtpurh_action(optarg, info, flags);
|
parse_gtpurh_addr(optarg, info, PARAM_LADDR);
|
||||||
*flags |= PARAM_ACTION;
|
*flags |= PARAM_LADDR;
|
||||||
return 1;
|
return 1;
|
||||||
|
case '2':
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--own-tun", *flags & PARAM_LTUN);
|
||||||
|
parse_gtpurh_tunid(optarg, info, PARAM_LTUN);
|
||||||
|
*flags |= PARAM_LTUN;
|
||||||
|
return 1;
|
||||||
|
case '3':
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--peer-ip", *flags & PARAM_RADDR);
|
||||||
|
parse_gtpurh_addr(optarg, info, PARAM_RADDR);
|
||||||
|
*flags |= PARAM_RADDR;
|
||||||
|
return 1;
|
||||||
|
case '4':
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--peer-tun", *flags & PARAM_RTUN);
|
||||||
|
parse_gtpurh_tunid(optarg, info, PARAM_RTUN);
|
||||||
|
*flags |= PARAM_RTUN;
|
||||||
|
return 1;
|
||||||
|
case '5':
|
||||||
|
gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--action", *flags & PARAM_ACTION);
|
||||||
|
parse_gtpurh_action(optarg, info, flags);
|
||||||
|
*flags |= PARAM_ACTION;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -143,10 +217,21 @@ static void GTPURH_check(unsigned int flags)
|
|||||||
{
|
{
|
||||||
gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify action");
|
gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify action");
|
||||||
}
|
}
|
||||||
|
if (!(flags & PARAM_LADDR))
|
||||||
if (flags & PARAM_GTPURH_ACTION_REM)
|
|
||||||
{
|
{
|
||||||
return;
|
gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify local addr");
|
||||||
|
}
|
||||||
|
if (!(flags & PARAM_LTUN))
|
||||||
|
{
|
||||||
|
gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify local tunnel id");
|
||||||
|
}
|
||||||
|
if (!(flags & PARAM_RADDR))
|
||||||
|
{
|
||||||
|
gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify remote addr");
|
||||||
|
}
|
||||||
|
if (!(flags & PARAM_RTUN))
|
||||||
|
{
|
||||||
|
gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify remote tunnel id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +276,12 @@ GTPURH_print(const void *ip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct option GTPURH_opts[] = {
|
static struct option GTPURH_opts[] = {
|
||||||
{ "action", 1, NULL, '1' },
|
{ "own-ip", 1, NULL, '1' },
|
||||||
{ .name = NULL }
|
{ "own-tun", 1, NULL, '2' },
|
||||||
|
{ "peer-ip", 1, NULL, '3' },
|
||||||
|
{ "peer-tun", 1, NULL, '4' },
|
||||||
|
{ "action", 1, NULL, '5' },
|
||||||
|
{ .name = NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
#if (IPTVERSION <= 135)
|
#if (IPTVERSION <= 135)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* GTPu klm for Linux/iptables
|
* GTPu klm for Linux/iptables
|
||||||
*
|
*
|
||||||
@@ -28,6 +27,9 @@
|
|||||||
#if 0
|
#if 0
|
||||||
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
|
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||||
|
# define WITH_IPV6 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//#define ROUTE_PACKET 1
|
//#define ROUTE_PACKET 1
|
||||||
@@ -39,220 +41,50 @@
|
|||||||
#error "Kernel version is not defined!!!! Exiting."
|
#error "Kernel version is not defined!!!! Exiting."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define NIPADDR(addr) \
|
||||||
|
(uint8_t)(addr & 0x000000FF), \
|
||||||
|
(uint8_t)((addr & 0x0000FF00) >> 8), \
|
||||||
|
(uint8_t)((addr & 0x00FF0000) >> 16), \
|
||||||
|
(uint8_t)((addr & 0xFF000000) >> 24)
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Pradip Biswas <pradip_biswas@polarisnetworks.net>");
|
MODULE_AUTHOR("Pradip Biswas <pradip_biswas@polarisnetworks.net>");
|
||||||
MODULE_DESCRIPTION("GTPu Data Path extension on netfilter");
|
MODULE_DESCRIPTION("GTPu Data Path extension on netfilter");
|
||||||
|
|
||||||
|
static char* _gtpurh_nf_inet_hook_2_string(int nf_inet_hookP);
|
||||||
/*
|
static inline bool _gtpurh_ip_is_fragment(const struct iphdr *iph_p);
|
||||||
* Statically sized hash table implementation
|
static void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP);
|
||||||
* (C) 2012 Sasha Levin <levinsasha928@gmail.com>
|
static unsigned int _gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_pP);
|
||||||
*/
|
#if defined(WITH_IPV6)
|
||||||
|
static unsigned int gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP);
|
||||||
#ifndef _LINUX_HASHTABLE_H
|
|
||||||
#define _LINUX_HASHTABLE_H
|
|
||||||
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/hash.h>
|
|
||||||
#include <linux/rculist.h>
|
|
||||||
|
|
||||||
#define DEFINE_HASHTABLE(name, bits) \
|
|
||||||
struct hlist_head name[1 << (bits)] = \
|
|
||||||
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
|
|
||||||
|
|
||||||
#define DECLARE_HASHTABLE(name, bits) \
|
|
||||||
struct hlist_head name[1 << (bits)]
|
|
||||||
|
|
||||||
#define HASH_SIZE(name) (ARRAY_SIZE(name))
|
|
||||||
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
|
|
||||||
|
|
||||||
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
|
|
||||||
#define hash_min(val, bits) \
|
|
||||||
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
|
|
||||||
|
|
||||||
static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sz; i++)
|
|
||||||
INIT_HLIST_HEAD(&ht[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_init - initialize a hash table
|
|
||||||
* @hashtable: hashtable to be initialized
|
|
||||||
*
|
|
||||||
* Calculates the size of the hashtable from the given parameter, otherwise
|
|
||||||
* same as hash_init_size.
|
|
||||||
*
|
|
||||||
* This has to be a macro since HASH_BITS() will not work on pointers since
|
|
||||||
* it calculates the size during preprocessing.
|
|
||||||
*/
|
|
||||||
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_add - add an object to a hashtable
|
|
||||||
* @hashtable: hashtable to add to
|
|
||||||
* @node: the &struct hlist_node of the object to be added
|
|
||||||
* @key: the key of the object to be added
|
|
||||||
*/
|
|
||||||
#define hash_add(hashtable, node, key) \
|
|
||||||
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_add_rcu - add an object to a rcu enabled hashtable
|
|
||||||
* @hashtable: hashtable to add to
|
|
||||||
* @node: the &struct hlist_node of the object to be added
|
|
||||||
* @key: the key of the object to be added
|
|
||||||
*/
|
|
||||||
#define hash_add_rcu(hashtable, node, key) \
|
|
||||||
hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_hashed - check whether an object is in any hashtable
|
|
||||||
* @node: the &struct hlist_node of the object to be checked
|
|
||||||
*/
|
|
||||||
static inline bool hash_hashed(struct hlist_node *node)
|
|
||||||
{
|
|
||||||
return !hlist_unhashed(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sz; i++)
|
|
||||||
if (!hlist_empty(&ht[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_empty - check whether a hashtable is empty
|
|
||||||
* @hashtable: hashtable to check
|
|
||||||
*
|
|
||||||
* This has to be a macro since HASH_BITS() will not work on pointers since
|
|
||||||
* it calculates the size during preprocessing.
|
|
||||||
*/
|
|
||||||
#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_del - remove an object from a hashtable
|
|
||||||
* @node: &struct hlist_node of the object to remove
|
|
||||||
*/
|
|
||||||
static inline void hash_del(struct hlist_node *node)
|
|
||||||
{
|
|
||||||
hlist_del_init(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_del_rcu - remove an object from a rcu enabled hashtable
|
|
||||||
* @node: &struct hlist_node of the object to remove
|
|
||||||
*/
|
|
||||||
static inline void hash_del_rcu(struct hlist_node *node)
|
|
||||||
{
|
|
||||||
hlist_del_init_rcu(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each - iterate over a hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @bkt: integer to use as bucket loop cursor
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
*/
|
|
||||||
#define hash_for_each(name, bkt, obj, pos, member) \
|
|
||||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
|
||||||
(bkt)++)\
|
|
||||||
hlist_for_each_entry(obj, pos, &name[bkt], member)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_rcu - iterate over a rcu enabled hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @bkt: integer to use as bucket loop cursor
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
*/
|
|
||||||
#define hash_for_each_rcu(name, bkt, obj, member) \
|
|
||||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
|
||||||
(bkt)++)\
|
|
||||||
hlist_for_each_entry_rcu(obj, &name[bkt], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_safe - iterate over a hashtable safe against removal of
|
|
||||||
* hash entry
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @bkt: integer to use as bucket loop cursor
|
|
||||||
* @tmp: a &struct used for temporary storage
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
*/
|
|
||||||
#define hash_for_each_safe(name, bkt, tmp, obj, member) \
|
|
||||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
|
||||||
(bkt)++)\
|
|
||||||
hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible - iterate over all possible objects hashing to the
|
|
||||||
* same bucket
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @tpos: the type * to use as a loop cursor.
|
|
||||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible(name, tpos, pos, member, key) \
|
|
||||||
hlist_for_each_entry(tpos, pos, &name[hash_min(key, HASH_BITS(name))], member)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible_rcu - iterate over all possible objects hashing to the
|
|
||||||
* same bucket in an rcu enabled hashtable
|
|
||||||
* in a rcu enabled hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible_rcu(name, obj, member, key) \
|
|
||||||
hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\
|
|
||||||
member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing
|
|
||||||
* to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*
|
|
||||||
* This is the same as hash_for_each_possible_rcu() except that it does
|
|
||||||
* not do any RCU debugging or tracing.
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \
|
|
||||||
hlist_for_each_entry_rcu_notrace(obj, \
|
|
||||||
&name[hash_min(key, HASH_BITS(name))], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible_safe - iterate over all possible objects hashing to the
|
|
||||||
* same bucket safe against removals
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @tmp: a &struct used for temporary storage
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible_safe(name, obj, tmp, member, key) \
|
|
||||||
hlist_for_each_entry_safe(obj, tmp,\
|
|
||||||
&name[hash_min(key, HASH_BITS(name))], member)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
static unsigned int gtpurh_tg4(struct sk_buff *skb_pP, const struct xt_action_param *par_pP);
|
||||||
|
|
||||||
|
static struct xt_target gtpurh_tg_reg[] __read_mostly = {
|
||||||
|
{
|
||||||
|
.name = "GTPURH",
|
||||||
|
.revision = 0,
|
||||||
|
.family = NFPROTO_IPV4,
|
||||||
|
.hooks = (1 << NF_INET_PRE_ROUTING) |
|
||||||
|
(1 << NF_INET_LOCAL_OUT),
|
||||||
|
.proto = IPPROTO_UDP,
|
||||||
|
.table = "raw",
|
||||||
|
.target = gtpurh_tg4,
|
||||||
|
.targetsize = sizeof(struct xt_gtpurh_target_info),
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
#if defined(WITH_IPV6)
|
||||||
|
{
|
||||||
|
.name = "GTPURH",
|
||||||
|
.revision = 0,
|
||||||
|
.family = NFPROTO_IPV6,
|
||||||
|
.proto = IPPROTO_UDP,
|
||||||
|
.table = "raw",
|
||||||
|
.target = gtpurh_tg6,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
struct gtpuhdr
|
struct gtpuhdr
|
||||||
{
|
{
|
||||||
@@ -276,28 +108,26 @@ struct gtpuhdr
|
|||||||
static char _gtpurh_print_buffer[GTPURH_2_PRINT_BUFFER_LEN];
|
static char _gtpurh_print_buffer[GTPURH_2_PRINT_BUFFER_LEN];
|
||||||
|
|
||||||
|
|
||||||
/*typedef struct ip_fragment_entry_s {
|
//-----------------------------------------------------------------------------
|
||||||
struct sk_buff *skb_p;
|
static char*
|
||||||
//struct timeval first_ts; // TO DO WITH IP_FRAG_TIME
|
_gtpurh_nf_inet_hook_2_string(int nf_inet_hookP) {
|
||||||
int flags; //ip header field
|
//-----------------------------------------------------------------------------
|
||||||
int offset; //ip header field
|
switch (nf_inet_hookP) {
|
||||||
int end;
|
case NF_INET_PRE_ROUTING: return "NF_INET_PRE_ROUTING";break;
|
||||||
struct hlist_node node;
|
case NF_INET_LOCAL_IN: return "NF_INET_LOCAL_IN";break;
|
||||||
}ip_fragment_entry_t;
|
case NF_INET_FORWARD: return "NF_INET_FORWARD";break;
|
||||||
|
case NF_INET_LOCAL_OUT: return "NF_INET_LOCAL_OUT";break;
|
||||||
|
case NF_INET_POST_ROUTING: return "NF_INET_POST_ROUTING";break;
|
||||||
|
default: return "NF_INET_UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct ip_reassembly_entry_s {
|
//-----------------------------------------------------------------------------
|
||||||
}ip_reassembly_entry_t;
|
static inline bool
|
||||||
*/
|
_gtpurh_ip_is_fragment(const struct iphdr *iph_p) {
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
static inline bool _gtpurh_ip_is_fragment(const struct iphdr *iph_p)
|
|
||||||
{
|
|
||||||
return (iph_p->frag_off & htons(IP_MF | IP_OFFSET)) != 0;
|
return (iph_p->frag_off & htons(IP_MF | IP_OFFSET)) != 0;
|
||||||
}
|
}
|
||||||
#define MAX_IP_FRAGMENTS 16
|
|
||||||
|
|
||||||
#define GTPURH_HASHTABLE_BITS 7
|
|
||||||
|
|
||||||
DEFINE_HASHTABLE(ip_fragments, GTPURH_HASHTABLE_BITS);
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP)
|
void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP)
|
||||||
@@ -356,7 +186,9 @@ void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP)
|
|||||||
|
|
||||||
|
|
||||||
#if defined(ROUTE_PACKET)
|
#if defined(ROUTE_PACKET)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_target_info *info_pP)
|
static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_target_info *info_pP)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct rtable *rt = NULL;
|
struct rtable *rt = NULL;
|
||||||
@@ -408,7 +240,7 @@ static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_
|
|||||||
skb_dst_set(skb_pP, &rt->dst);
|
skb_dst_set(skb_pP, &rt->dst);
|
||||||
skb_pP->dev = skb_dst(skb_pP)->dev;
|
skb_pP->dev = skb_dst(skb_pP)->dev;
|
||||||
|
|
||||||
/* Send the GTPu message out */
|
// Send the GTPu message out
|
||||||
ip_local_out(skb_pP);
|
ip_local_out(skb_pP);
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
@@ -418,140 +250,12 @@ static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*
|
|
||||||
static void
|
|
||||||
_gtpurh_delete_collection_ip_fragments(void)
|
|
||||||
{
|
|
||||||
int bucket_loop_cursor = 0;
|
|
||||||
struct ip_fragment_entry_s *ip_fragment_p = NULL;
|
|
||||||
struct hlist_node *pos_p = NULL;
|
|
||||||
|
|
||||||
hash_for_each(ip_fragments, bucket_loop_cursor, ip_fragment_p, pos_p, node) {
|
|
||||||
pr_info("GTPURH: %s struct ip_fragment_entry_s* %p, struct hlist_node* %p\n",
|
|
||||||
__FUNCTION__,
|
|
||||||
ip_fragment_p,
|
|
||||||
pos_p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
_gtpurh_target_reassembly(struct sk_buff *orig_skb_pP, const struct xt_gtpurh_target_info *tgi_pP)
|
|
||||||
{
|
|
||||||
struct iphdr *iph_p = ip_hdr(orig_skb_pP);
|
|
||||||
struct sk_buff *skb_p = NULL;
|
|
||||||
struct sk_buff *new_skb_p = NULL;
|
|
||||||
uint16_t key = 0;
|
|
||||||
int flags, offset, last_frag_offset;
|
|
||||||
int ihl, end;
|
|
||||||
struct ip_fragment_entry_s *ip_fragment_p = NULL;
|
|
||||||
struct hlist_node *pos_p = NULL;
|
|
||||||
int all_segments_availables = 1;
|
|
||||||
|
|
||||||
if ((orig_skb_pP) && (tgi_pP)) {
|
|
||||||
offset = ntohs(iph_p->frag_off);
|
|
||||||
flags = offset & ~IP_OFFSET;
|
|
||||||
offset &= IP_OFFSET; // offset is in 8-byte chunks
|
|
||||||
offset <<= 3;
|
|
||||||
ihl = ip_hdrlen(orig_skb_pP);
|
|
||||||
end = offset + orig_skb_pP->len - ihl;
|
|
||||||
|
|
||||||
key = iph_p->id;
|
|
||||||
|
|
||||||
pr_info("---------------GTPURH: Dump fragment:------------------------------------------------\n");
|
|
||||||
_gtpurh_print_hex_octets((unsigned char*)iph_p, orig_skb_pP->len);
|
|
||||||
// Is this the final fragment?
|
|
||||||
if ((flags & IP_MF) == 0) {
|
|
||||||
pr_info("GTPURH: try reassembly last segment id %u len %u offset %u end %u\n",
|
|
||||||
key,orig_skb_pP->len, offset, end);
|
|
||||||
// may be the last segment received
|
|
||||||
// normally iterator gives elements from head to tail, but elements
|
|
||||||
// have been inserted at the head, so iterator should retrieve fragments
|
|
||||||
// in reverse order.
|
|
||||||
last_frag_offset = offset;
|
|
||||||
hash_for_each_possible(ip_fragments, ip_fragment_p, pos_p, node, key) {
|
|
||||||
pr_info("GTPURH: try reassembly segment id %u len %u offset %u end %u\n",
|
|
||||||
key,ip_fragment_p->skb_p->len, ip_fragment_p->offset, ip_fragment_p->end);
|
|
||||||
if (ip_fragment_p->end == offset) {
|
|
||||||
offset = ip_fragment_p->offset;
|
|
||||||
} else {
|
|
||||||
pr_info("GTPURH: try reassembly segment id %u failed\n",
|
|
||||||
key);
|
|
||||||
all_segments_availables = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (all_segments_availables) {
|
|
||||||
// not optimal, but optimize later
|
|
||||||
new_skb_p = skb_copy_expand(orig_skb_pP,
|
|
||||||
last_frag_offset + skb_headroom(orig_skb_pP),
|
|
||||||
skb_tailroom(orig_skb_pP),
|
|
||||||
GFP_ATOMIC);
|
|
||||||
if (new_skb_p != NULL)
|
|
||||||
{
|
|
||||||
hash_for_each_possible(ip_fragments, ip_fragment_p, pos_p, node, key) {
|
|
||||||
skb_p = ip_fragment_p->skb_p;
|
|
||||||
skb_pull(new_skb_p, ihl);
|
|
||||||
|
|
||||||
pr_info("GTPURH: reassembly segment id %u len %u offset %u end %u\n",
|
|
||||||
key, skb_p->len, ip_fragment_p->offset, ip_fragment_p->end);
|
|
||||||
|
|
||||||
iph_p = (struct iphdr*)skb_push(new_skb_p, skb_p->len);
|
|
||||||
ihl = ip_hdrlen(skb_p);
|
|
||||||
memcpy(iph_p, skb_network_header(skb_p), skb_p->len);
|
|
||||||
}
|
|
||||||
skb_set_network_header(new_skb_p, 0);
|
|
||||||
if (_gtpurh_route_packet(new_skb_p, tgi_pP) != GTPURH_SUCCESS)
|
|
||||||
{
|
|
||||||
kfree_skb(new_skb_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
pr_info("GTPURH: Failed in skb_p allocation (%u bytes)\n",
|
|
||||||
last_frag_offset + skb_headroom(orig_skb_pP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (1) {
|
|
||||||
hash_for_each_possible(ip_fragments, ip_fragment_p, pos_p, node, key) {
|
|
||||||
kfree_skb(ip_fragment_p->skb_p);
|
|
||||||
hash_del(pos_p);
|
|
||||||
kfree(ip_fragment_p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pr_info("GTPURH: but in buffer not last segment id %u len %u offset %u end %u\n",
|
|
||||||
key,orig_skb_pP->len, offset, end);
|
|
||||||
// not the last fragment received
|
|
||||||
// assuming no out of order
|
|
||||||
ip_fragment_p = kmalloc(sizeof(struct ip_fragment_entry_s), GFP_KERNEL);
|
|
||||||
|
|
||||||
if (NULL != ip_fragment_p) {
|
|
||||||
ip_fragment_p->skb_p = skb_copy(orig_skb_pP, GFP_ATOMIC); // may use skb_clone(), TODO
|
|
||||||
ip_fragment_p->flags = flags;
|
|
||||||
ip_fragment_p->offset = offset;
|
|
||||||
ip_fragment_p->end = end;
|
|
||||||
pr_info("GTPURH: adding in hashtable key %04x ip_fragment %p skbuff %p\n",
|
|
||||||
key, ip_fragment_p, ip_fragment_p->skb_p);
|
|
||||||
|
|
||||||
INIT_HLIST_NODE(&ip_fragment_p->node);
|
|
||||||
hash_add(ip_fragments, &ip_fragment_p->node, key);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
pr_info("GTPURH: ERROR could not allocate memory for buffering IP fragment\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pr_info("%s(skb_p=%p,tgi_pP=%p) parameter skb_p or tgi_pP is NULL\n",
|
|
||||||
__FUNCTION__, orig_skb_pP, tgi_pP);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
static unsigned int
|
static unsigned int
|
||||||
_gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_pP)
|
_gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_pP) {
|
||||||
{
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct iphdr *iph_p = ip_hdr(orig_skb_pP);
|
struct iphdr *iph_p = ip_hdr(orig_skb_pP);
|
||||||
struct iphdr *iph2_p = NULL;
|
struct iphdr *iph2_p = NULL;
|
||||||
struct udphdr *udph_p = NULL;
|
struct udphdr *udph_p = NULL;
|
||||||
@@ -560,7 +264,6 @@ _gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_p
|
|||||||
#if defined(NEW_SKB)
|
#if defined(NEW_SKB)
|
||||||
struct sk_buff *new_skb_p = NULL;
|
struct sk_buff *new_skb_p = NULL;
|
||||||
struct iphdr *new_ip_p = NULL;
|
struct iphdr *new_ip_p = NULL;
|
||||||
unsigned int addr_type = 0;
|
|
||||||
#endif
|
#endif
|
||||||
uint16_t gtp_payload_size = 0;
|
uint16_t gtp_payload_size = 0;
|
||||||
|
|
||||||
@@ -730,57 +433,78 @@ _gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_p
|
|||||||
skb_p->priority = rt_tos2priority(iph2_p->tos);
|
skb_p->priority = rt_tos2priority(iph2_p->tos);
|
||||||
skb_p->pkt_type = PACKET_OTHERHOST;
|
skb_p->pkt_type = PACKET_OTHERHOST;
|
||||||
skb_dst_drop(skb_p);
|
skb_dst_drop(skb_p);
|
||||||
skb_dst_set(skb_p, &rt->dst);
|
skb_dst_set(skb_p, dst_clone(&rt->dst));
|
||||||
skb_p->dev = skb_dst(skb_p)->dev;
|
skb_p->dev = skb_dst(skb_p)->dev;
|
||||||
}
|
|
||||||
#if defined(NEW_SKB)
|
#if defined(NEW_SKB)
|
||||||
new_skb_p = alloc_skb(LL_MAX_HEADER + ntohs(iph2_p->tot_len), GFP_ATOMIC);
|
new_skb_p = alloc_skb(LL_MAX_HEADER + ntohs(iph2_p->tot_len), GFP_ATOMIC);
|
||||||
if (new_skb_p == NULL) {
|
if (new_skb_p == NULL) {
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
skb_reserve(new_skb_p, LL_MAX_HEADER);
|
skb_reserve(new_skb_p, LL_MAX_HEADER);
|
||||||
new_skb_p->protocol = skb_p->protocol;
|
new_skb_p->protocol = skb_p->protocol;
|
||||||
|
|
||||||
skb_reset_network_header(new_skb_p);
|
skb_reset_network_header(new_skb_p);
|
||||||
new_ip_p = (void *)skb_put(new_skb_p, iph2_p->ihl << 2);
|
new_ip_p = (void *)skb_put(new_skb_p, iph2_p->ihl << 2);
|
||||||
skb_reset_transport_header(new_skb_p);
|
skb_reset_transport_header(new_skb_p);
|
||||||
skb_put(new_skb_p, ntohs(iph2_p->tot_len) - (iph2_p->ihl << 2));
|
skb_put(new_skb_p, ntohs(iph2_p->tot_len) - (iph2_p->ihl << 2));
|
||||||
memcpy(new_ip_p, iph2_p, ntohs(iph2_p->tot_len));
|
memcpy(new_ip_p, iph2_p, ntohs(iph2_p->tot_len));
|
||||||
|
|
||||||
new_skb_p->mark = ntohl(gtpuh_p->tunid);
|
new_skb_p->mark = ntohl(gtpuh_p->tunid);
|
||||||
//new_skb_p->mark = skb_p->mark;
|
//new_skb_p->mark = skb_p->mark;
|
||||||
|
|
||||||
/* ip_route_me_harder expects skb->dst to be set */
|
/* ip_route_me_harder expects skb->dst to be set */
|
||||||
skb_dst_set(new_skb_p, dst_clone(skb_dst(skb_p)));
|
skb_dst_set(new_skb_p, dst_clone(skb_dst(skb_p)));
|
||||||
|
|
||||||
if (ip_route_me_harder(new_skb_p, RTN_UNSPEC) < 0)
|
/*if (ip_route_me_harder(new_skb_p, RTN_UNSPEC) < 0) {
|
||||||
goto free_new_skb;
|
pr_info("GTPURH: cannot route harder dest 0x%x\n", daddr);
|
||||||
|
goto free_skb;
|
||||||
|
}*/
|
||||||
|
|
||||||
new_ip_p->ttl = ip4_dst_hoplimit(skb_dst(new_skb_p));
|
new_ip_p->ttl = new_ip_p->ttl -1; // ip4_dst_hoplimit(skb_dst(new_skb_p));
|
||||||
new_skb_p->ip_summed = CHECKSUM_NONE;
|
new_skb_p->ip_summed = CHECKSUM_NONE;
|
||||||
|
|
||||||
/* "Never happens" (?) */
|
if (new_skb_p->len > dst_mtu(skb_dst(new_skb_p))) {
|
||||||
if (new_skb_p->len > dst_mtu(skb_dst(new_skb_p)))
|
pr_info("GTPURH: bad length\n");
|
||||||
goto free_new_skb;
|
goto free_skb;
|
||||||
|
}
|
||||||
|
|
||||||
nf_ct_attach(new_skb_p, skb_p);
|
nf_ct_attach(new_skb_p, skb_p);
|
||||||
ip_local_out(new_skb_p);
|
pr_info("GTPURH: ip_local_out %s/%s dev %s src %u.%u.%u.%u dst %u.%u.%u.%u \n",
|
||||||
return NF_DROP;
|
_gtpurh_nf_inet_hook_2_string(par_pP->hooknum),
|
||||||
|
gtpurh_tg_reg[0].table,
|
||||||
|
(new_skb_p->dev == NULL) ? "NULL" : new_skb_p->dev->name,
|
||||||
|
NIPADDR(new_ip_p->saddr),
|
||||||
|
NIPADDR(new_ip_p->daddr));
|
||||||
|
ip_local_out(new_skb_p);
|
||||||
|
return NF_DROP;
|
||||||
|
free_skb:
|
||||||
|
pr_info("GTPURH: Dropped skb ip_local_out %s/%s\n",
|
||||||
|
_gtpurh_nf_inet_hook_2_string(par_pP->hooknum),
|
||||||
|
gtpurh_tg_reg[0].table);
|
||||||
|
kfree_skb(new_skb_p);
|
||||||
|
return NF_DROP;
|
||||||
|
|
||||||
free_new_skb:
|
|
||||||
kfree_skb(new_skb_p);
|
|
||||||
return NF_DROP;
|
|
||||||
#else
|
#else
|
||||||
return NF_ACCEPT;
|
|
||||||
|
return NF_ACCEPT;
|
||||||
|
free_skb:
|
||||||
|
pr_info("GTPURH: Dropped skb\n");
|
||||||
|
kfree_skb(skb_p);
|
||||||
|
return NF_DROP;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(WITH_IPV6)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
static unsigned int
|
static unsigned int
|
||||||
gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP)
|
gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
const struct xt_gtpurh_target_info *tgi_p = par_pP->targinfo;
|
const struct xt_gtpurh_target_info *tgi_p = par_pP->targinfo;
|
||||||
int result = NF_DROP;
|
int result = NF_DROP;
|
||||||
@@ -794,60 +518,70 @@ gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP)
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
static unsigned int
|
static unsigned int
|
||||||
gtpurh_tg4(struct sk_buff *skb_pP, const struct xt_action_param *par_pP)
|
gtpurh_tg4(struct sk_buff *skb_pP, const struct xt_action_param *par_pP)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
|
const struct iphdr *iph_p = ip_hdr(skb_pP);
|
||||||
|
const struct rtable *rt_p = skb_rtable(skb_pP);
|
||||||
const struct xt_gtpurh_target_info *tgi_p = par_pP->targinfo;
|
const struct xt_gtpurh_target_info *tgi_p = par_pP->targinfo;
|
||||||
int result = NF_ACCEPT;
|
|
||||||
|
|
||||||
if (tgi_p == NULL) {
|
if (tgi_p == NULL) {
|
||||||
return result;
|
return NF_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tgi_p->raddr != iph_p->saddr) || (tgi_p->laddr != iph_p->daddr)) {
|
||||||
|
pr_info("GTPURH: Not processed because of not matching saddr %d.%d.%d.%d raddr %d.%d.%d.%d laddr %d.%d.%d.%d daddr %d.%d.%d.%d\n",
|
||||||
|
NIPADDR(tgi_p->raddr),
|
||||||
|
NIPADDR(iph_p->saddr),
|
||||||
|
NIPADDR(tgi_p->laddr),
|
||||||
|
NIPADDR(iph_p->daddr));
|
||||||
|
return NF_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip_hdrlen(skb_pP) != sizeof(struct iphdr)) {
|
||||||
|
pr_info("GTPURH: Dropped because IP options\n");
|
||||||
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop fragments
|
||||||
|
if (iph_p->frag_off & htons(IP_OFFSET)) {
|
||||||
|
pr_info("GTPURH: Dropped because is fragment\n");
|
||||||
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tgi_p->action == PARAM_GTPURH_ACTION_REM) {
|
if (tgi_p->action == PARAM_GTPURH_ACTION_REM) {
|
||||||
result = _gtpurh_tg4_rem(skb_pP, par_pP);
|
return _gtpurh_tg4_rem(skb_pP, par_pP);
|
||||||
}
|
}
|
||||||
return result;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xt_target gtpurh_tg_reg[] __read_mostly = {
|
|
||||||
{
|
|
||||||
.name = "GTPURH",
|
|
||||||
.revision = 0,
|
|
||||||
.family = NFPROTO_IPV6,
|
|
||||||
.proto = IPPROTO_UDP,
|
|
||||||
.table = "raw",
|
|
||||||
.target = gtpurh_tg6,
|
|
||||||
.me = THIS_MODULE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "GTPURH",
|
|
||||||
.revision = 0,
|
|
||||||
.family = NFPROTO_IPV4,
|
|
||||||
.hooks = (1 << NF_INET_PRE_ROUTING) |
|
|
||||||
(1 << NF_INET_LOCAL_OUT),
|
|
||||||
.proto = IPPROTO_UDP,
|
|
||||||
.table = "raw",
|
|
||||||
.target = gtpurh_tg4,
|
|
||||||
.targetsize = sizeof(struct xt_gtpurh_target_info),
|
|
||||||
.me = THIS_MODULE,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init gtpurh_tg_init(void)
|
//-----------------------------------------------------------------------------
|
||||||
{
|
static int
|
||||||
|
__init gtpurh_tg_init(void) {
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
pr_info("GTPURH: Initializing module (KVersion: %d)\n", KVERSION);
|
pr_info("GTPURH: Initializing module (KVersion: %d)\n", KVERSION);
|
||||||
pr_info("GTPURH: Copyright Polaris Networks 2010-2011\n");
|
pr_info("GTPURH: Copyright Polaris Networks 2010-2011\n");
|
||||||
pr_info("GTPURH: Modified by EURECOM Lionel GAUTHIER 2014\n");
|
pr_info("GTPURH: Modified by EURECOM Lionel GAUTHIER 2014\n");
|
||||||
//hash_init(ip_fragments);
|
#if defined(WITH_IPV6)
|
||||||
|
pr_info("GTPURH: IPv4/IPv6 enabled\n");
|
||||||
|
#else
|
||||||
|
pr_info("GTPURH: IPv4 only enabled\n");
|
||||||
|
#endif
|
||||||
return xt_register_targets(gtpurh_tg_reg, ARRAY_SIZE(gtpurh_tg_reg));
|
return xt_register_targets(gtpurh_tg_reg, ARRAY_SIZE(gtpurh_tg_reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit gtpurh_tg_exit(void)
|
//-----------------------------------------------------------------------------
|
||||||
{
|
static void
|
||||||
|
__exit gtpurh_tg_exit(void) {
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
xt_unregister_targets(gtpurh_tg_reg, ARRAY_SIZE(gtpurh_tg_reg));
|
xt_unregister_targets(gtpurh_tg_reg, ARRAY_SIZE(gtpurh_tg_reg));
|
||||||
//_gtpurh_delete_collection_ip_fragments();
|
|
||||||
pr_info("GTPURH: Unloading module\n");
|
pr_info("GTPURH: Unloading module\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user