aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorAnsis Atteka <aatteka@nicira.com>2013-09-18 15:29:53 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-13 14:51:07 -0700
commit2a6a2791b1e6ebd7ad29f137a309471f92d71c55 (patch)
tree613e5018ff9eeaae11184aac70cd682fa93f31f6 /include
parent20218d3d355cb32bdf1d737438958aa75f6ab21a (diff)
downloadkernel_samsung_smdk4412-2a6a2791b1e6ebd7ad29f137a309471f92d71c55.tar.gz
kernel_samsung_smdk4412-2a6a2791b1e6ebd7ad29f137a309471f92d71c55.tar.bz2
kernel_samsung_smdk4412-2a6a2791b1e6ebd7ad29f137a309471f92d71c55.zip
ip: generate unique IP identificator if local fragmentation is allowed
[ Upstream commit 703133de331a7a7df47f31fb9de51dc6f68a9de8 ] If local fragmentation is allowed, then ip_select_ident() and ip_select_ident_more() need to generate unique IDs to ensure correct defragmentation on the peer. For example, if IPsec (tunnel mode) has to encrypt large skbs that have local_df bit set, then all IP fragments that belonged to different ESP datagrams would have used the same identificator. If one of these IP fragments would get lost or reordered, then peer could possibly stitch together wrong IP fragments that did not belong to the same datagram. This would lead to a packet loss or data corruption. Signed-off-by: Ansis Atteka <aatteka@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/net/ip.h12
-rw-r--r--include/net/ipip.h2
2 files changed, 9 insertions, 5 deletions
diff --git a/include/net/ip.h b/include/net/ip.h
index 66dd4914920..2370f47e336 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -262,9 +262,11 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
-static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk)
+static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk)
{
- if (iph->frag_off & htons(IP_DF)) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) {
/* This is only to work around buggy Windows95/2000
* VJ compression implementations. If the ID field
* does not change, they drop every other packet in
@@ -276,9 +278,11 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str
__ip_select_ident(iph, dst, 0);
}
-static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more)
+static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk, int more)
{
- if (iph->frag_off & htons(IP_DF)) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) {
if (sk && inet_sk(sk)->inet_daddr) {
iph->id = htons(inet_sk(sk)->inet_id);
inet_sk(sk)->inet_id += 1 + more;
diff --git a/include/net/ipip.h b/include/net/ipip.h
index a32654d5273..4dccfe3bf73 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -50,7 +50,7 @@ struct ip_tunnel_prl_entry {
int pkt_len = skb->len - skb_transport_offset(skb); \
\
skb->ip_summed = CHECKSUM_NONE; \
- ip_select_ident(iph, &rt->dst, NULL); \
+ ip_select_ident(skb, &rt->dst, NULL); \
\
err = ip_local_out(skb); \
if (likely(net_xmit_eval(err) == 0)) { \