aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-11-14 00:41:28 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:46 -0500
commit227620e295090629fcb2c46ad3828222ab65438d (patch)
tree534162a74628fdfa7a8201cb776a45ca07510e5b /net/ipv4
parent36cf9acf93e8561d9faec24849e57688a81eb9c5 (diff)
[IPSEC]: Separate inner/outer mode processing on input
With inter-family transforms the inner mode differs from the outer mode. Attempting to handle both sides from the same function means that it needs to handle both IPv4 and IPv6 which creates duplication and confusion. This patch separates the two parts on the input path so that each function deals with one family only. In particular, the functions xfrm4_extract_inut/xfrm6_extract_inut moves the pertinent fields from the IPv4/IPv6 IP headers into a neutral format stored in skb->cb. This is then used by the inner mode input functions to modify the inner IP header. In this way the input function no longer has to know about the outer address family. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/xfrm4_input.c7
-rw-r--r--net/ipv4/xfrm4_mode_beet.c67
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c44
-rw-r--r--net/ipv4/xfrm4_state.c2
4 files changed, 57 insertions, 63 deletions
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 5e95c8a07efb..c0323d05ab69 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -16,6 +16,11 @@
16#include <net/ip.h> 16#include <net/ip.h>
17#include <net/xfrm.h> 17#include <net/xfrm.h>
18 18
19int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb)
20{
21 return xfrm4_extract_header(skb);
22}
23
19#ifdef CONFIG_NETFILTER 24#ifdef CONFIG_NETFILTER
20static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) 25static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
21{ 26{
@@ -91,7 +96,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
91 96
92 xfrm_vec[xfrm_nr++] = x; 97 xfrm_vec[xfrm_nr++] = x;
93 98
94 if (x->outer_mode->input(x, skb)) 99 if (x->inner_mode->input(x, skb))
95 goto drop; 100 goto drop;
96 101
97 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { 102 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index 94842adce144..e093a7b59e18 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -17,6 +17,21 @@
17#include <net/ip.h> 17#include <net/ip.h>
18#include <net/xfrm.h> 18#include <net/xfrm.h>
19 19
20static void xfrm4_beet_make_header(struct sk_buff *skb)
21{
22 struct iphdr *iph = ip_hdr(skb);
23
24 iph->ihl = 5;
25 iph->version = 4;
26
27 iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
28 iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
29
30 iph->id = XFRM_MODE_SKB_CB(skb)->id;
31 iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off;
32 iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl;
33}
34
20/* Add encapsulation header. 35/* Add encapsulation header.
21 * 36 *
22 * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. 37 * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
@@ -40,20 +55,12 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
40 offsetof(struct iphdr, protocol); 55 offsetof(struct iphdr, protocol);
41 skb->transport_header = skb->network_header + sizeof(*iph); 56 skb->transport_header = skb->network_header + sizeof(*iph);
42 57
58 xfrm4_beet_make_header(skb);
59
43 ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen); 60 ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen);
44 61
45 top_iph = ip_hdr(skb); 62 top_iph = ip_hdr(skb);
46 63
47 top_iph->ihl = 5;
48 top_iph->version = 4;
49
50 top_iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
51 top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
52
53 top_iph->id = XFRM_MODE_SKB_CB(skb)->id;
54 top_iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off;
55 top_iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl;
56
57 if (unlikely(optlen)) { 64 if (unlikely(optlen)) {
58 BUG_ON(optlen < 0); 65 BUG_ON(optlen < 0);
59 66
@@ -75,43 +82,46 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
75 82
76static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) 83static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
77{ 84{
78 struct iphdr *iph = ip_hdr(skb); 85 struct iphdr *iph;
79 int phlen = 0;
80 int optlen = 0; 86 int optlen = 0;
81 u8 ph_nexthdr = 0;
82 int err = -EINVAL; 87 int err = -EINVAL;
83 88
84 if (unlikely(iph->protocol == IPPROTO_BEETPH)) { 89 if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
85 struct ip_beet_phdr *ph; 90 struct ip_beet_phdr *ph;
91 int phlen;
86 92
87 if (!pskb_may_pull(skb, sizeof(*ph))) 93 if (!pskb_may_pull(skb, sizeof(*ph)))
88 goto out; 94 goto out;
89 ph = (struct ip_beet_phdr *)(ipip_hdr(skb) + 1); 95
96 ph = (struct ip_beet_phdr *)skb->data;
90 97
91 phlen = sizeof(*ph) + ph->padlen; 98 phlen = sizeof(*ph) + ph->padlen;
92 optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); 99 optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
93 if (optlen < 0 || optlen & 3 || optlen > 250) 100 if (optlen < 0 || optlen & 3 || optlen > 250)
94 goto out; 101 goto out;
95 102
96 if (!pskb_may_pull(skb, phlen + optlen)) 103 XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
97 goto out;
98 skb->len -= phlen + optlen;
99 104
100 ph_nexthdr = ph->nexthdr; 105 if (!pskb_may_pull(skb, phlen));
106 goto out;
107 __skb_pull(skb, phlen);
101 } 108 }
102 109
103 skb_set_network_header(skb, phlen - sizeof(*iph)); 110 skb_push(skb, sizeof(*iph));
104 memmove(skb_network_header(skb), iph, sizeof(*iph)); 111 skb_reset_network_header(skb);
105 skb_set_transport_header(skb, phlen + optlen); 112
106 skb->data = skb_transport_header(skb); 113 memmove(skb->data - skb->mac_len, skb_mac_header(skb),
114 skb->mac_len);
115 skb_set_mac_header(skb, -skb->mac_len);
116
117 xfrm4_beet_make_header(skb);
107 118
108 iph = ip_hdr(skb); 119 iph = ip_hdr(skb);
109 iph->ihl = (sizeof(*iph) + optlen) / 4; 120
110 iph->tot_len = htons(skb->len + iph->ihl * 4); 121 iph->ihl += optlen / 4;
122 iph->tot_len = htons(skb->len);
111 iph->daddr = x->sel.daddr.a4; 123 iph->daddr = x->sel.daddr.a4;
112 iph->saddr = x->sel.saddr.a4; 124 iph->saddr = x->sel.saddr.a4;
113 if (ph_nexthdr)
114 iph->protocol = ph_nexthdr;
115 iph->check = 0; 125 iph->check = 0;
116 iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); 126 iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
117 err = 0; 127 err = 0;
@@ -120,7 +130,8 @@ out:
120} 130}
121 131
122static struct xfrm_mode xfrm4_beet_mode = { 132static struct xfrm_mode xfrm4_beet_mode = {
123 .input = xfrm4_beet_input, 133 .input2 = xfrm4_beet_input,
134 .input = xfrm_prepare_input,
124 .output2 = xfrm4_beet_output, 135 .output2 = xfrm4_beet_output,
125 .output = xfrm4_prepare_output, 136 .output = xfrm4_prepare_output,
126 .owner = THIS_MODULE, 137 .owner = THIS_MODULE,
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index cc8bbb274e37..aa335dba8ffa 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -16,19 +16,12 @@
16 16
17static inline void ipip_ecn_decapsulate(struct sk_buff *skb) 17static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
18{ 18{
19 struct iphdr *outer_iph = ip_hdr(skb);
20 struct iphdr *inner_iph = ipip_hdr(skb); 19 struct iphdr *inner_iph = ipip_hdr(skb);
21 20
22 if (INET_ECN_is_ce(outer_iph->tos)) 21 if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
23 IP_ECN_set_ce(inner_iph); 22 IP_ECN_set_ce(inner_iph);
24} 23}
25 24
26static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
27{
28 if (INET_ECN_is_ce(iph->tos))
29 IP6_ECN_set_ce(ipv6_hdr(skb));
30}
31
32/* Add encapsulation header. 25/* Add encapsulation header.
33 * 26 *
34 * The top IP header will be constructed per RFC 2401. 27 * The top IP header will be constructed per RFC 2401.
@@ -72,20 +65,11 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
72 65
73static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 66static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
74{ 67{
75 struct iphdr *iph = ip_hdr(skb);
76 const unsigned char *old_mac; 68 const unsigned char *old_mac;
77 int err = -EINVAL; 69 int err = -EINVAL;
78 70
79 switch (iph->protocol){ 71 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
80 case IPPROTO_IPIP: 72 goto out;
81 break;
82#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
83 case IPPROTO_IPV6:
84 break;
85#endif
86 default:
87 goto out;
88 }
89 73
90 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 74 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
91 goto out; 75 goto out;
@@ -94,20 +78,11 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
94 (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) 78 (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
95 goto out; 79 goto out;
96 80
97 iph = ip_hdr(skb); 81 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
98 if (iph->protocol == IPPROTO_IPIP) { 82 ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb));
99 if (x->props.flags & XFRM_STATE_DECAP_DSCP) 83 if (!(x->props.flags & XFRM_STATE_NOECN))
100 ipv4_copy_dscp(ipv4_get_dsfield(iph), ipip_hdr(skb)); 84 ipip_ecn_decapsulate(skb);
101 if (!(x->props.flags & XFRM_STATE_NOECN)) 85
102 ipip_ecn_decapsulate(skb);
103 }
104#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
105 else {
106 if (!(x->props.flags & XFRM_STATE_NOECN))
107 ipip6_ecn_decapsulate(iph, skb);
108 skb->protocol = htons(ETH_P_IPV6);
109 }
110#endif
111 old_mac = skb_mac_header(skb); 86 old_mac = skb_mac_header(skb);
112 skb_set_mac_header(skb, -skb->mac_len); 87 skb_set_mac_header(skb, -skb->mac_len);
113 memmove(skb_mac_header(skb), old_mac, skb->mac_len); 88 memmove(skb_mac_header(skb), old_mac, skb->mac_len);
@@ -119,7 +94,8 @@ out:
119} 94}
120 95
121static struct xfrm_mode xfrm4_tunnel_mode = { 96static struct xfrm_mode xfrm4_tunnel_mode = {
122 .input = xfrm4_tunnel_input, 97 .input2 = xfrm4_tunnel_input,
98 .input = xfrm_prepare_input,
123 .output2 = xfrm4_tunnel_output, 99 .output2 = xfrm4_tunnel_output,
124 .output = xfrm4_prepare_output, 100 .output = xfrm4_prepare_output,
125 .owner = THIS_MODULE, 101 .owner = THIS_MODULE,
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index e6030e74ff65..85f04b7b237f 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -65,10 +65,12 @@ int xfrm4_extract_header(struct sk_buff *skb)
65static struct xfrm_state_afinfo xfrm4_state_afinfo = { 65static struct xfrm_state_afinfo xfrm4_state_afinfo = {
66 .family = AF_INET, 66 .family = AF_INET,
67 .proto = IPPROTO_IPIP, 67 .proto = IPPROTO_IPIP,
68 .eth_proto = htons(ETH_P_IP),
68 .owner = THIS_MODULE, 69 .owner = THIS_MODULE,
69 .init_flags = xfrm4_init_flags, 70 .init_flags = xfrm4_init_flags,
70 .init_tempsel = __xfrm4_init_tempsel, 71 .init_tempsel = __xfrm4_init_tempsel,
71 .output = xfrm4_output, 72 .output = xfrm4_output,
73 .extract_input = xfrm4_extract_input,
72 .extract_output = xfrm4_extract_output, 74 .extract_output = xfrm4_extract_output,
73}; 75};
74 76