summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2003-07-27 02:32:07 -0700
committerDavid S. Miller <davem@kernel.bkbits.net>2003-07-27 02:32:07 -0700
commit596aac2cab7581d015f58ccf7fb97be5d06c06fa (patch)
tree8db22027240dca73d52903ba96b69b3e0688858c /net
parent872d1c7a5963bdbcc78cce3283db0fd52fafa39d (diff)
[IPSEC]: Use per-SA flag to control ECN propagation.
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ah4.c3
-rw-r--r--net/ipv4/esp4.c3
-rw-r--r--net/ipv4/ipcomp.c3
-rw-r--r--net/ipv4/xfrm4_input.c12
-rw-r--r--net/ipv6/ah6.c3
-rw-r--r--net/ipv6/esp6.c3
-rw-r--r--net/ipv6/ipcomp6.c3
-rw-r--r--net/ipv6/xfrm6_input.c11
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/xfrm/xfrm_user.c2
10 files changed, 47 insertions, 0 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 030bc3605b99..4641b35a273c 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -1,5 +1,6 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ah.h>
@@ -123,6 +124,8 @@ static int ah_output(struct sk_buff *skb)
top_iph->tos = iph->tos;
top_iph->ttl = iph->ttl;
if (x->props.mode) {
+ if (x->props.flags & XFRM_STATE_NOECN)
+ IP_ECN_clear(top_iph);
top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET);
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
} else {
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 93289a96545a..af293a7bc687 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -1,5 +1,6 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/esp.h>
@@ -109,6 +110,8 @@ int esp_output(struct sk_buff *skb)
top_iph->ihl = 5;
top_iph->version = 4;
top_iph->tos = iph->tos; /* DS disclosed */
+ if (x->props.flags & XFRM_STATE_NOECN)
+ IP_ECN_clear(top_iph);
top_iph->tot_len = htons(skb->len + alen);
top_iph->frag_off = iph->frag_off&htons(IP_DF);
if (!(top_iph->frag_off))
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index f3356664be06..f968969d61d8 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -18,6 +18,7 @@
#include <asm/scatterlist.h>
#include <linux/crypto.h>
#include <linux/pfkeyv2.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
@@ -210,6 +211,8 @@ static int ipcomp_output(struct sk_buff *skb)
top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ip_comp_hdr));
memcpy(top_iph, &tmp_iph, iph->ihl * 4);
iph = top_iph;
+ if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN))
+ IP_ECN_clear(iph);
iph->tot_len = htons(skb->len);
iph->protocol = IPPROTO_COMP;
iph->check = 0;
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 4b9797600d74..9a10d736d62a 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -10,6 +10,7 @@
*/
#include <linux/slab.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
@@ -20,6 +21,15 @@ int xfrm4_rcv(struct sk_buff *skb)
return xfrm4_rcv_encap(skb, 0);
}
+static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
+{
+ struct iphdr *inner_iph = skb->nh.iph;
+
+ if (INET_ECN_is_ce(outer_iph->tos) &&
+ INET_ECN_is_not_ce(inner_iph->tos))
+ IP_ECN_set_ce(inner_iph);
+}
+
int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{
int err;
@@ -75,6 +85,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (iph->protocol != IPPROTO_IPIP)
goto drop;
skb->nh.raw = skb->data;
+ if (!(x->props.flags & XFRM_STATE_NOECN))
+ ipip_ecn_decapsulate(iph, skb);
iph = skb->nh.iph;
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
decaps = 1;
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 6696e519f134..07d92a2e48a3 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -26,6 +26,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ah.h>
@@ -220,6 +221,8 @@ int ah6_output(struct sk_buff *skb)
skb->nh.ipv6h->flow_lbl[0] = iph->flow_lbl[0];
skb->nh.ipv6h->flow_lbl[1] = iph->flow_lbl[1];
skb->nh.ipv6h->flow_lbl[2] = iph->flow_lbl[2];
+ if (x->props.flags & XFRM_STATE_NOECN)
+ IP6_ECN_clear(skb->nh.ipv6h);
} else {
memcpy(skb->nh.ipv6h, iph, hdr_len);
skb->nh.raw[nh_offset] = IPPROTO_AH;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index a9a384465160..e78cee3ed056 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -26,6 +26,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/esp.h>
@@ -121,6 +122,8 @@ int esp6_output(struct sk_buff *skb)
top_iph->flow_lbl[0] = iph->flow_lbl[0];
top_iph->flow_lbl[1] = iph->flow_lbl[1];
top_iph->flow_lbl[2] = iph->flow_lbl[2];
+ if (x->props.flags & XFRM_STATE_NOECN)
+ IP6_ECN_clear(top_iph);
top_iph->nexthdr = IPPROTO_ESP;
top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr));
top_iph->hop_limit = iph->hop_limit;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 307439f2a7c6..2101765131c9 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -32,6 +32,7 @@
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ipcomp.h>
@@ -201,6 +202,8 @@ static int ipcomp6_output(struct sk_buff *skb)
memcpy(top_iph, tmp_iph, hdr_len);
kfree(tmp_iph);
+ if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN))
+ IP6_ECN_clear(top_iph);
top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
skb->nh.raw = skb->data; /* top_iph */
ip6_find_1stfragopt(skb, &prevhdr);
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 7505f945fc8c..e38196564362 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -9,12 +9,21 @@
* IPv6 support
*/
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
static kmem_cache_t *secpath_cachep;
+static inline void ipip6_ecn_decapsulate(struct ipv6hdr *iph,
+ struct sk_buff *skb)
+{
+ if (INET_ECN_is_ce(ip6_get_dsfield(iph)) &&
+ INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h)))
+ IP6_ECN_set_ce(skb->nh.ipv6h);
+}
+
int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
{
struct sk_buff *skb = *pskb;
@@ -71,6 +80,8 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
if (nexthdr != IPPROTO_IPV6)
goto drop;
skb->nh.raw = skb->data;
+ if (!(x->props.flags & XFRM_STATE_NOECN))
+ ipip6_ecn_decapsulate(iph, skb);
iph = skb->nh.ipv6h;
decaps = 1;
break;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index f481a136dad4..ec9fe27e1e37 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -681,6 +681,8 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
}
sa->sadb_sa_flags = 0;
+ if (x->props.flags & XFRM_STATE_NOECN)
+ sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN;
/* hard time */
if (hsc & 2) {
@@ -957,6 +959,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
x->id.proto = proto;
x->id.spi = sa->sadb_sa_spi;
x->props.replay_window = sa->sadb_sa_replay;
+ if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN)
+ x->props.flags |= XFRM_STATE_NOECN;
lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1];
if (lifetime != NULL) {
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b2dd1296f7b6..f10711c7e0fb 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -201,6 +201,7 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *
x->props.reqid = p->reqid;
x->props.family = p->family;
x->props.saddr = p->saddr;
+ x->props.flags = p->flags;
}
static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
@@ -305,6 +306,7 @@ static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
p->replay_window = x->props.replay_window;
p->reqid = x->props.reqid;
p->family = x->props.family;
+ p->flags = x->props.flags;
p->seq = x->km.seq;
}