Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
openairinterface5G
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Worker.N
openairinterface5G
Commits
5b720e47
Commit
5b720e47
authored
10 years ago
by
gauthier
Browse files
Options
Downloads
Patches
Plain Diff
git-svn-id:
http://svn.eurecom.fr/openair4G/trunk@6276
818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent
11b1db9f
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
openair-cn/GTPV1-U/GTPUAH/xt_GTPUAH.c
+247
-304
247 additions, 304 deletions
openair-cn/GTPV1-U/GTPUAH/xt_GTPUAH.c
with
247 additions
and
304 deletions
openair-cn/GTPV1-U/GTPUAH/xt_GTPUAH.c
+
247
−
304
View file @
5b720e47
/*
* GTPu klm for Linux/iptables
*
...
...
@@ -23,21 +22,60 @@
#include
<net/udp.h>
#include
<net/inet_sock.h>
#include
<net/route.h>
#include
<net/addrconf.h>
#include
<net/ip6_checksum.h>
#include
<net/ip6_route.h>
#include
<net/ipv6.h>
#include
<linux/netfilter/x_tables.h>
#include
<linux/netfilter_ipv4/ip_tables.h>
#if 0
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
#ifdef CONFIG_BRIDGE_NETFILTER
# include <linux/netfilter_bridge.h>
#endif
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
# define WITH_IPV6 1
#endif
#include
"xt_GTPUAH.h"
#if !(defined KVERSION)
#error "Kernel version is not defined!!!! Exiting."
#endif
//-----------------------------------------------------------------------------
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Pradip Biswas <pradip_biswas@polarisnetworks.net>"
);
MODULE_DESCRIPTION
(
"GTPu Data Path extension on netfilter"
);
//-----------------------------------------------------------------------------
static
char
*
_gtpuah_nf_inet_hook_2_string
(
int
nf_inet_hookP
);
static
void
_gtpuah_tg4_add
(
struct
sk_buff
*
old_skb_pP
,
const
struct
xt_action_param
*
par_pP
);
static
unsigned
int
gtpuah_tg4
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_action_param
*
par_pP
);
static
unsigned
int
gtpuah_tg6
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_action_param
*
par_pP
);
static
int
__init
gtpuah_tg_init
(
void
);
static
void
__exit
gtpuah_tg_exit
(
void
);
//-----------------------------------------------------------------------------
static
struct
xt_target
gtpuah_tg_reg
[]
__read_mostly
=
{
{
.
name
=
"GTPUAH"
,
.
revision
=
0
,
.
family
=
NFPROTO_IPV4
,
.
hooks
=
(
1
<<
NF_INET_POST_ROUTING
)
|
(
1
<<
NF_INET_LOCAL_IN
)
,
.
table
=
"mangle"
,
.
target
=
gtpuah_tg4
,
.
targetsize
=
sizeof
(
struct
xt_gtpuah_target_info
),
.
me
=
THIS_MODULE
,
},
#ifdef WITH_IPV6
{
.
name
=
"GTPUAH"
,
.
revision
=
0
,
.
family
=
NFPROTO_IPV6
,
.
hooks
=
(
1
<<
NF_INET_POST_ROUTING
)
|
(
1
<<
NF_INET_LOCAL_IN
)
,
.
table
=
"mangle"
,
.
target
=
gtpuah_tg6
,
.
targetsize
=
sizeof
(
struct
xt_gtpuah_target_info
),
.
me
=
THIS_MODULE
,
},
#endif
};
struct
gtpuhdr
{
...
...
@@ -46,7 +84,7 @@ struct gtpuhdr
u_int16_t
length
;
u_int32_t
tunid
;
};
//-----------------------------------------------------------------------------
#define MTU 1564
#define GTPU_HDR_PNBIT 1
#define GTPU_HDR_SBIT 1 << 1
...
...
@@ -55,347 +93,252 @@ struct gtpuhdr
#define GTPU_FAILURE 1
#define GTPU_SUCCESS !GTPU_FAILURE
#define GTPU_PORT 2152
#define IP_MORE_FRAGMENTS 0x2000
static
bool
_gtpuah_route_packet
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_gtpuah_target_info
*
info_pP
,
char
*
in_dev_pP
)
{
int
err
=
0
;
struct
rtable
*
rt
=
NULL
;
struct
iphdr
*
iph
=
ip_hdr
(
skb_pP
);
int
daddr
=
iph
->
daddr
;
struct
flowi
fl
=
{
.
u
=
{
.
ip4
=
{
.
daddr
=
daddr
,
.
flowi4_tos
=
RT_TOS
(
iph
->
tos
),
.
flowi4_scope
=
RT_SCOPE_UNIVERSE
,
}
}
};
#if 1
int
flags
,
offset
;
offset
=
ntohs
(
iph
->
frag_off
);
flags
=
offset
&
~
IP_OFFSET
;
offset
&=
IP_OFFSET
;
/* offset is in 8-byte chunks */
offset
<<=
3
;
pr_info
(
"GTPUAH(%d): Routing %s packet: %d.%d.%d.%d --> %d.%d.%d.%d Proto: %d, Len: %05u, Id %04X, Offset %u, Flags %04X, Mark: %u
\n
"
,
info_pP
->
action
,
(
ip_is_fragment
(
iph
)
==
0
)
?
""
:
"fragmented"
,
iph
->
saddr
&
0xFF
,
(
iph
->
saddr
&
0x0000FF00
)
>>
8
,
(
iph
->
saddr
&
0x00FF0000
)
>>
16
,
iph
->
saddr
>>
24
,
iph
->
daddr
&
0xFF
,
(
iph
->
daddr
&
0x0000FF00
)
>>
8
,
(
iph
->
daddr
&
0x00FF0000
)
>>
16
,
iph
->
daddr
>>
24
,
iph
->
protocol
,
ntohs
(
iph
->
tot_len
),
ntohs
(
iph
->
id
),
offset
,
flags
,
skb_pP
->
mark
);
#endif
if
(
in_dev_pP
)
{
if
(
strcasecmp
(
in_dev_pP
,
"lo"
)
==
0
)
{
struct
inet_sock
*
inet
=
inet_sk
(
skb_pP
->
sk
);
ip_queue_xmit
(
&
inet
->
sk
,
skb_pP
,
&
fl
);
}
else
{
rt
=
ip_route_output_key
(
&
init_net
,
&
fl
.
u
.
ip4
);
if
(
err
!=
0
)
{
pr_info
(
"GTPU: Failed to route packet to dst 0x%x. Error: (%d)"
,
fl
.
u
.
ip4
.
daddr
,
err
);
return
GTPU_FAILURE
;
}
#if 1
if
(
rt
->
dst
.
dev
)
{
pr_info
(
"GTPU: dst dev name %s
\n
"
,
rt
->
dst
.
dev
->
name
);
}
else
{
pr_info
(
"GTPU: dst dev NULL
\n
"
);
}
#endif
//if (info_pP->action == PARAM_GTPUAH_ACTION_ADD) //LG was commented
{
skb_dst_drop
(
skb_pP
);
skb_dst_set
(
skb_pP
,
&
rt
->
dst
);
skb_pP
->
dev
=
skb_dst
(
skb_pP
)
->
dev
;
}
skb_pP
->
protocol
=
htons
(
ETH_P_IP
);
/* Send the GTPu message out...gggH */
err
=
dst_output
(
skb_pP
);
}
}
if
(
err
==
0
)
{
return
GTPU_SUCCESS
;
}
else
{
return
GTPU_FAILURE
;
#define NIPADDR(addr) \
(
uint8_t
)(
addr
&
0x000000FF
),
\
(
uint8_t
)((
addr
&
0x0000FF00
)
>>
8
),
\
(
uint8_t
)((
addr
&
0x00FF0000
)
>>
16
),
\
(
uint8_t
)((
addr
&
0xFF000000
)
>>
24
)
//-----------------------------------------------------------------------------
static
char
*
_gtpuah_nf_inet_hook_2_string
(
int
nf_inet_hookP
)
{
//-----------------------------------------------------------------------------
switch
(
nf_inet_hookP
)
{
case
NF_INET_PRE_ROUTING
:
return
"NF_INET_PRE_ROUTING"
;
break
;
case
NF_INET_LOCAL_IN
:
return
"NF_INET_LOCAL_IN"
;
break
;
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"
;
}
}
static
unsigned
int
_gtpuah_t
arget
_add
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_
gtpuah_target_info
*
tgi_pP
,
char
*
in_dev
_pP
)
{
struct
iphdr
*
iph
=
ip_hdr
(
skb_pP
)
;
struct
iphdr
*
iph2
=
NULL
;
struct
ud
phdr
*
udph
=
NULL
;
struct
gtpuhdr
*
gtpuh
=
NULL
;
struct
sk_buff
*
new_skb
=
NULL
;
struct
sk_buff
*
new_skb
2
=
NULL
;
uint16_t
headroom_reqd
=
sizeof
(
struct
iphdr
)
+
sizeof
(
struct
udphdr
)
+
sizeof
(
struct
gtpuhdr
);
//-----------------------------------------------------------------------------
static
void
_gtpuah_t
g4
_add
(
struct
sk_buff
*
old_
skb_pP
,
const
struct
xt_
action_param
*
par
_pP
)
{
//-----------------------------------------------------------------------------
struct
rtable
*
rt
=
NULL
;
struct
iphdr
*
old_iph_p
=
ip_hdr
(
old_skb_pP
)
;
struct
i
phdr
*
new_iph_p
=
NULL
;
struct
udphdr
*
udph_p
=
NULL
;
struct
gtpuhdr
*
gtpuh_p
=
NULL
;
struct
sk_buff
*
new_skb
_p
=
NULL
;
uint16_t
headroom_reqd
=
LL_MAX_HEADER
+
sizeof
(
struct
iphdr
)
+
sizeof
(
struct
udphdr
)
+
sizeof
(
struct
gtpuhdr
);
uint16_t
orig_iplen
=
0
,
udp_len
=
0
,
ip_len
=
0
;
int16_t
remaining_bytes_to_send
=
0
,
remaining_payload_to_send
=
0
,
payload_to_send
=
0
,
bytes_to_remove
=
0
,
bytes_to_send
=
0
;
int
flags
=
0
,
offset
=
0
,
offset2
=
0
;
if
(
skb_pP
->
mark
==
0
)
{
pr_info
(
"GTPUAH: _gtpuah_target_add force info_pP mark %u to skb_pP mark %u"
,
skb_pP
->
mark
,
tgi_pP
->
rtun
);
skb_pP
->
mark
=
tgi_pP
->
rtun
;
int
flags
=
0
,
offset
=
0
;
unsigned
int
addr_type
=
RTN_UNSPEC
;
if
(
old_skb_pP
->
mark
==
0
)
{
pr_info
(
"GTPUAH: _gtpuah_target_add force info_pP mark %u to skb_pP mark %u"
,
old_skb_pP
->
mark
,
((
const
struct
xt_gtpuah_target_info
*
)(
par_pP
->
targinfo
))
->
rtun
);
old_skb_pP
->
mark
=
((
const
struct
xt_gtpuah_target_info
*
)(
par_pP
->
targinfo
))
->
rtun
;
}
/* Keep the length of the source IP packet */
orig_iplen
=
ntohs
(
iph
->
tot_len
);
offset
=
ntohs
(
iph
->
frag_off
);
orig_iplen
=
ntohs
(
old_
iph
_p
->
tot_len
);
offset
=
ntohs
(
old_
iph
_p
->
frag_off
);
flags
=
offset
&
~
IP_OFFSET
;
/* Create a new copy of the original skb...can't avoid :-( */
if
((
(
orig_iplen
+
headroom_reqd
)
<=
MTU
)
||
(
flags
&
IP_DF
))
{
if
((
orig_iplen
+
headroom_reqd
)
<=
MTU
)
{
#if 1
if
(
flags
&
IP_DF
)
{
pr_info
(
"GTPUAH: DONT FRAGMENT id %04X"
,
ntohs
(
iph
->
id
));
}
#endif
new_skb
=
skb_copy_expand
(
skb_pP
,
headroom_reqd
+
skb_headroom
(
skb_pP
),
skb_tailroom
(
skb_pP
),
GFP_ATOMIC
);
if
(
new_skb
==
NULL
)
{
return
NF_ACCEPT
;
new_skb_p
=
skb_copy_expand
(
old_skb_pP
,
headroom_reqd
+
skb_headroom
(
old_skb_pP
),
skb_tailroom
(
old_skb_pP
),
GFP_ATOMIC
);
if
(
new_skb_p
==
NULL
)
{
pr_info
(
"GTPUAH: skb_copy_expand returned NULL"
);
return
;
}
nf_reset
(
new_skb_p
);
//skb_nfmark(new_skb_p) = 0;
skb_init_secmark
(
new_skb_p
);
skb_shinfo
(
new_skb_p
)
->
gso_size
=
0
;
skb_shinfo
(
new_skb_p
)
->
gso_segs
=
0
;
skb_shinfo
(
new_skb_p
)
->
gso_type
=
0
;
/* Add GTPu header */
gtpuh
=
(
struct
gtpuhdr
*
)
skb_push
(
new_skb
,
sizeof
(
struct
gtpuhdr
));
gtpuh
->
flags
=
0x30
;
/* v1 and Protocol-type=GTP */
gtpuh
->
msgtype
=
0xff
;
/* T-PDU */
gtpuh
->
length
=
htons
(
orig_iplen
);
gtpuh
->
tunid
=
htonl
(
skb_pP
->
mark
);
gtpuh
_p
=
(
struct
gtpuhdr
*
)
skb_push
(
new_skb
_p
,
sizeof
(
struct
gtpuhdr
));
gtpuh
_p
->
flags
=
0x30
;
/* v1 and Protocol-type=GTP */
gtpuh
_p
->
msgtype
=
0xff
;
/* T-PDU */
gtpuh
_p
->
length
=
htons
(
orig_iplen
);
gtpuh
_p
->
tunid
=
htonl
(
old_
skb_pP
->
mark
);
/* Add UDP header */
udp_len
=
sizeof
(
struct
udphdr
)
+
sizeof
(
struct
gtpuhdr
)
+
orig_iplen
;
udph
=
(
struct
udphdr
*
)
skb_push
(
new_skb
,
sizeof
(
struct
udphdr
));
udph
->
source
=
htons
(
GTPU_PORT
);
udph
->
dest
=
htons
(
GTPU_PORT
);
udph
->
len
=
htons
(
udp_len
);
udph
->
check
=
0
;
udph
->
check
=
csum_tcpudp_magic
(
tgi_pP
->
laddr
,
tgi_pP
->
raddr
,
udp_len
,
IPPROTO_UDP
,
csum_partial
((
char
*
)
udph
,
udp_len
,
0
));
skb_set_transport_header
(
new_skb
,
0
);
udp_len
=
sizeof
(
struct
udphdr
)
+
sizeof
(
struct
gtpuhdr
)
+
orig_iplen
;
udph
_p
=
(
struct
udphdr
*
)
skb_push
(
new_skb
_p
,
sizeof
(
struct
udphdr
));
udph
_p
->
source
=
htons
(
GTPU_PORT
);
udph
_p
->
dest
=
htons
(
GTPU_PORT
);
udph
_p
->
len
=
htons
(
udp_len
);
udph
_p
->
check
=
0
;
udph
_p
->
check
=
csum_tcpudp_magic
(
((
const
struct
xt_gtpuah_target_info
*
)(
par_pP
->
targinfo
))
->
laddr
,
((
const
struct
xt_gtpuah_target_info
*
)(
par_pP
->
targinfo
))
->
raddr
,
udp_len
,
IPPROTO_UDP
,
csum_partial
((
char
*
)
udph
_p
,
udp_len
,
0
));
skb_set_transport_header
(
new_skb
_p
,
0
);
/* Add IP header */
ip_len
=
sizeof
(
struct
iphdr
)
+
sizeof
(
struct
udphdr
)
+
sizeof
(
struct
gtpuhdr
)
+
orig_iplen
;
iph
=
(
struct
iphdr
*
)
skb_push
(
new_skb
,
sizeof
(
struct
iphdr
));
iph
->
ihl
=
5
;
iph
->
version
=
4
;
iph
->
tos
=
0
;
iph
->
tot_len
=
htons
(
ip_len
);
iph
->
id
=
(
uint16_t
)(((
uint64_t
)
new_skb
)
>>
8
);
iph
->
frag_off
=
0
;
iph
->
ttl
=
64
;
iph
->
protocol
=
IPPROTO_UDP
;
iph
->
saddr
=
(
tgi_pP
->
laddr
);
iph
->
daddr
=
(
tgi_pP
->
raddr
);
iph
->
check
=
0
;
iph
->
check
=
ip_fast_csum
((
unsigned
char
*
)
iph
,
iph
->
ihl
);
skb_set_network_header
(
new_skb
,
0
);
/* Route the packet */
if
(
_gtpuah_route_packet
(
new_skb
,
tgi_pP
,
in_dev_pP
)
==
GTPU_SUCCESS
)
{
/* Succeeded. Drop the original packet */
return
NF_DROP
;
}
else
{
kfree_skb
(
new_skb
);
return
NF_ACCEPT
;
/* What should we do here ??? ACCEPT seems to be the best option */
}
}
else
{
new_skb
=
skb_copy_expand
(
skb_pP
,
headroom_reqd
+
skb_headroom
(
skb_pP
),
0
,
GFP_ATOMIC
);
if
(
new_skb
==
NULL
)
{
return
NF_ACCEPT
;
}
// must segment if added headers (IP, UDP, GTP) + original data + original headers > MTU
pr_info
(
"GTPUAH: Fragmentation Id %04X payload size %u (IP Head inc), total ip packet size %u"
,
htons
((
uint16_t
)(((
uint64_t
)
new_skb
)
>>
8
)),
MTU
-
headroom_reqd
,
MTU
);
gtpuh
=
(
struct
gtpuhdr
*
)
skb_push
(
new_skb
,
sizeof
(
struct
gtpuhdr
));
gtpuh
->
flags
=
0x30
;
/* v1 and Protocol-type=GTP */
gtpuh
->
msgtype
=
0xff
;
/* T-PDU */
gtpuh
->
length
=
htons
(
orig_iplen
);
gtpuh
->
tunid
=
htonl
(
skb_pP
->
mark
);
/* Add UDP header */
udp_len
=
sizeof
(
struct
udphdr
)
+
sizeof
(
struct
gtpuhdr
)
+
orig_iplen
;
udph
=
(
struct
udphdr
*
)
skb_push
(
new_skb
,
sizeof
(
struct
udphdr
));
udph
->
source
=
htons
(
GTPU_PORT
);
udph
->
dest
=
htons
(
GTPU_PORT
);
udph
->
len
=
htons
(
udp_len
);
udph
->
check
=
0
;
udph
->
check
=
csum_tcpudp_magic
(
tgi_pP
->
laddr
,
tgi_pP
->
raddr
,
udp_len
,
IPPROTO_UDP
,
csum_partial
((
char
*
)
udph
,
udp_len
,
0
));
skb_set_transport_header
(
new_skb
,
0
);
/* Add IP header */
ip_len
=
MTU
;
iph
=
(
struct
iphdr
*
)
skb_push
(
new_skb
,
sizeof
(
struct
iphdr
));
iph
->
ihl
=
5
;
iph
->
version
=
4
;
iph
->
tos
=
0
;
iph
->
tot_len
=
htons
(
ip_len
);
iph
->
id
=
(
uint16_t
)(((
uint64_t
)
new_skb
)
>>
8
);
iph
->
frag_off
=
htons
(
IP_MORE_FRAGMENTS
);
iph
->
ttl
=
64
;
iph
->
protocol
=
IPPROTO_UDP
;
iph
->
saddr
=
(
tgi_pP
->
laddr
);
iph
->
daddr
=
(
tgi_pP
->
raddr
);
iph
->
check
=
0
;
iph
->
check
=
ip_fast_csum
((
unsigned
char
*
)
iph
,
iph
->
ihl
);
skb_set_network_header
(
new_skb
,
0
);
skb_trim
(
new_skb
,
MTU
-
headroom_reqd
);
/* Route the packet */
if
(
_gtpuah_route_packet
(
new_skb
,
tgi_pP
,
in_dev_pP
)
==
GTPU_SUCCESS
)
{
remaining_payload_to_send
=
orig_iplen
-
MTU
+
headroom_reqd
;
remaining_bytes_to_send
=
remaining_payload_to_send
+
sizeof
(
struct
iphdr
);
bytes_to_remove
=
MTU
-
headroom_reqd
;
offset2
=
MTU
-
headroom_reqd
-
sizeof
(
struct
iphdr
);
// the localhost generated traffic can have len > MTU
// but can cause problem at UE rx side
while
(
remaining_payload_to_send
>
0
)
{
if
((
remaining_payload_to_send
+
sizeof
(
struct
iphdr
))
>
MTU
)
{
bytes_to_send
=
MTU
;
payload_to_send
=
MTU
-
sizeof
(
struct
iphdr
);
new_iph_p
=
(
struct
iphdr
*
)
skb_push
(
new_skb_p
,
sizeof
(
struct
iphdr
));
new_iph_p
->
ihl
=
5
;
new_iph_p
->
version
=
4
;
new_iph_p
->
tos
=
0
;
new_iph_p
->
tot_len
=
htons
(
ip_len
);
new_iph_p
->
id
=
(
uint16_t
)(((
uint64_t
)
new_skb_p
)
>>
8
);
new_iph_p
->
frag_off
=
0
;
new_iph_p
->
ttl
=
64
;
new_iph_p
->
protocol
=
IPPROTO_UDP
;
new_iph_p
->
saddr
=
((
const
struct
xt_gtpuah_target_info
*
)(
par_pP
->
targinfo
))
->
laddr
;
new_iph_p
->
daddr
=
((
const
struct
xt_gtpuah_target_info
*
)(
par_pP
->
targinfo
))
->
raddr
;
new_iph_p
->
check
=
0
;
new_iph_p
->
check
=
ip_fast_csum
((
unsigned
char
*
)
new_iph_p
,
new_iph_p
->
ihl
);
skb_set_network_header
(
new_skb_p
,
0
);
new_skb_p
->
ip_summed
=
CHECKSUM_COMPLETE
;
new_skb_p
->
csum
=
new_iph_p
->
check
;
new_skb_p
->
mark
=
old_skb_pP
->
mark
;
switch
(
par_pP
->
hooknum
)
{
case
NF_INET_POST_ROUTING
:
{
struct
flowi
fl
=
{
.
u
=
{
.
ip4
=
{
.
daddr
=
new_iph_p
->
daddr
,
.
flowi4_tos
=
RT_TOS
(
new_iph_p
->
tos
),
.
flowi4_scope
=
RT_SCOPE_UNIVERSE
,
}
}
};
pr_info
(
"GTPUAH: PACKET -> NF_HOOK NF_INET_POST_ROUTING/%s encapsulated src: %u.%u.%u.%u dst: %u.%u.%u.%u"
,
gtpuah_tg_reg
[
0
].
table
,
NIPADDR
(
old_iph_p
->
saddr
),
NIPADDR
(
old_iph_p
->
daddr
));
new_skb_p
->
pkt_type
=
PACKET_OTHERHOST
;
// PACKET_OUTGOING
#ifdef CONFIG_BRIDGE_NETFILTER
if
(
new_skb_p
->
nf_bridge
!=
NULL
&&
new_skb_p
->
nf_bridge
->
mask
&
BRNF_BRIDGED
)
{
addr_type
=
RTN_LOCAL
;
new_skb_p
->
pkt_type
=
PACKET_HOST
;
}
#endif
rt
=
ip_route_output_key
(
&
init_net
,
&
fl
.
u
.
ip4
);
if
(
rt
==
NULL
)
{
pr_info
(
"GTPURH: Failed to route packet to dst 0x%x."
,
fl
.
u
.
ip4
.
daddr
);
goto
free_new_skb
;
}
new_skb_p
->
priority
=
rt_tos2priority
(
new_iph_p
->
tos
);
skb_dst_drop
(
new_skb_p
);
if
(
rt
->
dst
.
dev
)
{
pr_info
(
"GTPURH: dst dev name %s
\n
"
,
rt
->
dst
.
dev
->
name
);
skb_dst_set
(
new_skb_p
,
dst_clone
(
&
rt
->
dst
));
new_skb_p
->
dev
=
skb_dst
(
new_skb_p
)
->
dev
;
if
(
new_skb_p
->
len
>
dst_mtu
(
skb_dst
(
new_skb_p
)))
{
goto
free_new_skb
;
}
nf_ct_attach
(
new_skb_p
,
old_skb_pP
);
ip_local_out
(
new_skb_p
);
}
else
{
bytes_to_send
=
remaining_payload_to_send
+
sizeof
(
struct
iphdr
);
payload_to_send
=
remaining_payload_to_send
;
pr_info
(
"GTPURH: rt->dst.dev == NULL
\n
"
);
goto
free_new_skb
;
}
pr_info
(
"GTPUAH: Fragmentation Id %04X payload size %u, total ip packet size %u"
,
htons
((
uint16_t
)(((
uint64_t
)
new_skb
)
>>
8
)),
payload_to_send
,
bytes_to_send
);
// Not optimal, TO OPTIMIZE copies
new_skb2
=
skb_copy
(
skb_pP
,
GFP_ATOMIC
);
skb_pull
(
new_skb2
,
bytes_to_remove
);
/* Add IP header */
iph2
=
(
struct
iphdr
*
)
skb_push
(
new_skb2
,
sizeof
(
struct
iphdr
));
iph2
->
ihl
=
5
;
iph2
->
version
=
4
;
iph2
->
tos
=
0
;
iph2
->
tot_len
=
htons
(
bytes_to_send
);
iph2
->
id
=
(
uint16_t
)(((
uint64_t
)
new_skb
)
>>
8
);
iph2
->
frag_off
=
htons
(
offset2
/
8
);
iph2
->
ttl
=
64
;
iph2
->
protocol
=
IPPROTO_UDP
;
iph2
->
saddr
=
(
tgi_pP
->
laddr
);
iph2
->
daddr
=
(
tgi_pP
->
raddr
);
iph2
->
check
=
0
;
iph2
->
check
=
ip_fast_csum
((
unsigned
char
*
)
iph2
,
iph2
->
ihl
);
skb_set_network_header
(
new_skb2
,
0
);
skb_trim
(
new_skb2
,
MTU
);
_gtpuah_route_packet
(
new_skb2
,
tgi_pP
,
in_dev_pP
);
remaining_payload_to_send
=
remaining_payload_to_send
-
payload_to_send
;
bytes_to_remove
=
bytes_to_remove
+
payload_to_send
;
offset2
=
offset2
+
payload_to_send
;
}
return
NF_DROP
;
}
else
{
kfree_skb
(
new_skb
);
return
NF_ACCEPT
;
/* What should we do here ??? ACCEPT seems to be the best option */
break
;
case
NF_INET_LOCAL_IN
:
addr_type
=
RTN_LOCAL
;
pr_info
(
"GTPUAH: PACKET -> NF_HOOK NF_INET_LOCAL_IN/%s src: %u.%u.%u.%u dst: %u.%u.%u.%u NOT PROCESSED"
,
gtpuah_tg_reg
[
0
].
table
,
NIPADDR
(
old_iph_p
->
saddr
),
NIPADDR
(
old_iph_p
->
daddr
));
//NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, new_skb_p, NULL,
// skb_dst(new_skb_p)->dev, ip_local_deliver_finish);
goto
free_new_skb
;
break
;
default:
pr_info
(
"GTPUAH: NF_HOOK %u not processed"
,
par_pP
->
hooknum
);
goto
free_new_skb
;
}
}
return
;
}
free_new_skb:
pr_info
(
"GTPUAH: PACKET DROPPED"
);
kfree_skb
(
new_skb_p
);
return
;
}
#ifdef WITH_IPV6
//-----------------------------------------------------------------------------
static
unsigned
int
gtpuah_tg6
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_action_param
*
par_pP
)
{
//-----------------------------------------------------------------------------
const
struct
xt_gtpuah_target_info
*
tgi_p
=
par_pP
->
targinfo
;
if
(
tgi_p
==
NULL
)
{
return
NF_ACCEPT
;
}
if
(
tgi_p
->
action
==
PARAM_GTPUAH_ACTION_ADD
)
{
return
NF_DROP
;
// TODO
}
return
NF_ACCEPT
;
}
#endif
//-----------------------------------------------------------------------------
static
unsigned
int
xt_gtpuah_target
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_action_param
*
par_pP
)
{
gtpuah_tg4
(
struct
sk_buff
*
skb_pP
,
const
struct
xt_action_param
*
par_pP
)
{
//-----------------------------------------------------------------------------
const
struct
iphdr
*
iph_p
=
ip_hdr
(
skb_pP
);
const
struct
xt_gtpuah_target_info
*
tgi_p
=
par_pP
->
targinfo
;
int
result
=
NF_ACCEPT
;
if
(
tgi_p
==
NULL
)
{
return
result
;
if
(
tgi_p
==
NULL
)
{
return
NF_ACCEPT
;
}
if
(
tgi_p
->
action
==
PARAM_GTPUAH_ACTION_ADD
)
{
result
=
_gtpuah_target_add
(
skb_pP
,
tgi_p
,
par_pP
->
in
->
name
);
if
(
tgi_p
->
action
==
PARAM_GTPUAH_ACTION_ADD
)
{
pr_info
(
"GTPUAH: PACKET -> NF_HOOK %s/%s src: %u.%u.%u.%u dst: %u.%u.%u.%u NOT PROCESSED"
,
_gtpuah_nf_inet_hook_2_string
(
par_pP
->
hooknum
),
NIPADDR
(
iph_p
->
saddr
),
NIPADDR
(
iph_p
->
daddr
));
//_gtpuah_tg4_add(skb_pP, par_pP);
return
NF_DROP
;
}
return
result
;
return
NF_ACCEPT
;
}
static
struct
xt_target
xt_gtpuah_reg
__read_mostly
=
{
.
name
=
"GTPUAH"
,
.
revision
=
0
,
.
family
=
AF_INET
,
.
hooks
=
(
1
<<
NF_INET_FORWARD
)
|
(
1
<<
NF_INET_POST_ROUTING
)
|
(
1
<<
NF_INET_LOCAL_OUT
),
.
table
=
"mangle"
,
.
target
=
xt_gtpuah_target
,
.
targetsize
=
sizeof
(
struct
xt_gtpuah_target_info
),
.
me
=
THIS_MODULE
,
};
//-----------------------------------------------------------------------------
static
int
__init
gtpuah_tg_init
(
void
)
{
//-----------------------------------------------------------------------------
static
int
__init
xt_gtpuah_init
(
void
)
{
pr_info
(
"GTPUAH: Initializing module (KVersion: %d)
\n
"
,
KVERSION
);
pr_info
(
"GTPUAH: Copyright Polaris Networks 2010-2011
\n
"
);
pr_info
(
"GTPUAH: Modified by EURECOM Lionel GAUTHIER 2014
\n
"
);
return
xt_register_target
(
&
xt_gtpuah_reg
);
#if defined(WITH_IPV6)
pr_info
(
"GTPURH: IPv4/IPv6 enabled
\n
"
);
#else
pr_info
(
"GTPURH: IPv4 only enabled
\n
"
);
#endif
return
xt_register_targets
(
gtpuah_tg_reg
,
ARRAY_SIZE
(
gtpuah_tg_reg
));
}
static
void
__exit
xt_
gtpuah_exit
(
void
)
static
void
__exit
gtpuah_
tg_
exit
(
void
)
{
xt_unregister_target
(
&
xt_gtpuah_reg
);
xt_unregister_targets
(
gtpuah_tg_reg
,
ARRAY_SIZE
(
gtpuah_tg_reg
));
#if defined(WITH_IPV6)
pr_info
(
"GTPURH: IPv4/IPv6 enabled
\n
"
);
#else
pr_info
(
"GTPURH: IPv4 only enabled
\n
"
);
#endif
pr_info
(
"GTPUAH: Unloading module
\n
"
);
}
module_init
(
xt_gtpuah_init
);
module_exit
(
xt_gtpuah_exit
);
module_init
(
gtpuah_tg_init
);
module_exit
(
gtpuah_tg_exit
);
MODULE_ALIAS
(
"ipt6_GTPUAH"
);
MODULE_ALIAS
(
"ipt_GTPUAH"
);
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment