diff options
author | Miika Komu <miika@iki.fi> | 2007-02-06 17:27:32 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-02-08 15:39:02 -0500 |
commit | 4337226228e1cfc1d70ee975789c6bd070fb597c (patch) | |
tree | a30fd4257c0c2796815dc9cc13b8a12f13f1f2bf | |
parent | c82f963efe823d3cacaf1f1b7f1a35cc9628b188 (diff) |
[IPSEC]: IPv4 over IPv6 IPsec tunnel
This is the patch to support IPv4 over IPv6 IPsec.
Signed-off-by: Miika Komu <miika@iki.fi>
Signed-off-by: Diego Beltrami <Diego.Beltrami@hiit.fi>
Signed-off-by: Kazunori Miyazawa <miyazawa@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 50 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 42 |
2 files changed, 65 insertions, 27 deletions
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index fb9f69c616f5..011136a95809 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -72,13 +72,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
72 | struct dst_entry *dst, *dst_prev; | 72 | struct dst_entry *dst, *dst_prev; |
73 | struct rtable *rt0 = (struct rtable*)(*dst_p); | 73 | struct rtable *rt0 = (struct rtable*)(*dst_p); |
74 | struct rtable *rt = rt0; | 74 | struct rtable *rt = rt0; |
75 | __be32 remote = fl->fl4_dst; | ||
76 | __be32 local = fl->fl4_src; | ||
77 | struct flowi fl_tunnel = { | 75 | struct flowi fl_tunnel = { |
78 | .nl_u = { | 76 | .nl_u = { |
79 | .ip4_u = { | 77 | .ip4_u = { |
80 | .saddr = local, | 78 | .saddr = fl->fl4_src, |
81 | .daddr = remote, | 79 | .daddr = fl->fl4_dst, |
82 | .tos = fl->fl4_tos | 80 | .tos = fl->fl4_tos |
83 | } | 81 | } |
84 | } | 82 | } |
@@ -94,7 +92,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
94 | for (i = 0; i < nx; i++) { | 92 | for (i = 0; i < nx; i++) { |
95 | struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); | 93 | struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); |
96 | struct xfrm_dst *xdst; | 94 | struct xfrm_dst *xdst; |
97 | int tunnel = 0; | ||
98 | 95 | ||
99 | if (unlikely(dst1 == NULL)) { | 96 | if (unlikely(dst1 == NULL)) { |
100 | err = -ENOBUFS; | 97 | err = -ENOBUFS; |
@@ -116,19 +113,28 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
116 | 113 | ||
117 | dst1->next = dst_prev; | 114 | dst1->next = dst_prev; |
118 | dst_prev = dst1; | 115 | dst_prev = dst1; |
119 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 116 | |
120 | remote = xfrm[i]->id.daddr.a4; | ||
121 | local = xfrm[i]->props.saddr.a4; | ||
122 | tunnel = 1; | ||
123 | } | ||
124 | header_len += xfrm[i]->props.header_len; | 117 | header_len += xfrm[i]->props.header_len; |
125 | trailer_len += xfrm[i]->props.trailer_len; | 118 | trailer_len += xfrm[i]->props.trailer_len; |
126 | 119 | ||
127 | if (tunnel) { | 120 | if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) { |
128 | fl_tunnel.fl4_src = local; | 121 | unsigned short encap_family = xfrm[i]->props.family; |
129 | fl_tunnel.fl4_dst = remote; | 122 | switch(encap_family) { |
123 | case AF_INET: | ||
124 | fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; | ||
125 | fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; | ||
126 | break; | ||
127 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
128 | case AF_INET6: | ||
129 | ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6); | ||
130 | ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6); | ||
131 | break; | ||
132 | #endif | ||
133 | default: | ||
134 | BUG_ON(1); | ||
135 | } | ||
130 | err = xfrm_dst_lookup((struct xfrm_dst **)&rt, | 136 | err = xfrm_dst_lookup((struct xfrm_dst **)&rt, |
131 | &fl_tunnel, AF_INET); | 137 | &fl_tunnel, encap_family); |
132 | if (err) | 138 | if (err) |
133 | goto error; | 139 | goto error; |
134 | } else | 140 | } else |
@@ -145,6 +151,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
145 | i = 0; | 151 | i = 0; |
146 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | 152 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { |
147 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | 153 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; |
154 | struct xfrm_state_afinfo *afinfo; | ||
148 | x->u.rt.fl = *fl; | 155 | x->u.rt.fl = *fl; |
149 | 156 | ||
150 | dst_prev->xfrm = xfrm[i++]; | 157 | dst_prev->xfrm = xfrm[i++]; |
@@ -162,8 +169,17 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
162 | /* Copy neighbout for reachability confirmation */ | 169 | /* Copy neighbout for reachability confirmation */ |
163 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); | 170 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); |
164 | dst_prev->input = rt->u.dst.input; | 171 | dst_prev->input = rt->u.dst.input; |
165 | dst_prev->output = xfrm4_output; | 172 | /* XXX: When IPv6 module can be unloaded, we should manage reference |
166 | if (rt->peer) | 173 | * to xfrm6_output in afinfo->output. Miyazawa |
174 | * */ | ||
175 | afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); | ||
176 | if (!afinfo) { | ||
177 | dst = *dst_p; | ||
178 | goto error; | ||
179 | } | ||
180 | dst_prev->output = afinfo->output; | ||
181 | xfrm_state_put_afinfo(afinfo); | ||
182 | if (dst_prev->xfrm->props.family == AF_INET && rt->peer) | ||
167 | atomic_inc(&rt->peer->refcnt); | 183 | atomic_inc(&rt->peer->refcnt); |
168 | x->u.rt.peer = rt->peer; | 184 | x->u.rt.peer = rt->peer; |
169 | /* Sheit... I remember I did this right. Apparently, | 185 | /* Sheit... I remember I did this right. Apparently, |
@@ -274,7 +290,7 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) | |||
274 | 290 | ||
275 | if (likely(xdst->u.rt.idev)) | 291 | if (likely(xdst->u.rt.idev)) |
276 | in_dev_put(xdst->u.rt.idev); | 292 | in_dev_put(xdst->u.rt.idev); |
277 | if (likely(xdst->u.rt.peer)) | 293 | if (dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer)) |
278 | inet_putpeer(xdst->u.rt.peer); | 294 | inet_putpeer(xdst->u.rt.peer); |
279 | xfrm_dst_destroy(xdst); | 295 | xfrm_dst_destroy(xdst); |
280 | } | 296 | } |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 5e7d8a7d6414..0bc866c0d83c 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -25,6 +25,12 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | |||
25 | IP6_ECN_set_ce(inner_iph); | 25 | IP6_ECN_set_ce(inner_iph); |
26 | } | 26 | } |
27 | 27 | ||
28 | static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb) | ||
29 | { | ||
30 | if (INET_ECN_is_ce(ipv6_get_dsfield(skb->nh.ipv6h))) | ||
31 | IP_ECN_set_ce(skb->h.ipiph); | ||
32 | } | ||
33 | |||
28 | /* Add encapsulation header. | 34 | /* Add encapsulation header. |
29 | * | 35 | * |
30 | * The top IP header will be constructed per RFC 2401. The following fields | 36 | * The top IP header will be constructed per RFC 2401. The following fields |
@@ -40,6 +46,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | |||
40 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | 46 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
41 | { | 47 | { |
42 | struct dst_entry *dst = skb->dst; | 48 | struct dst_entry *dst = skb->dst; |
49 | struct xfrm_dst *xdst = (struct xfrm_dst*)dst; | ||
43 | struct ipv6hdr *iph, *top_iph; | 50 | struct ipv6hdr *iph, *top_iph; |
44 | int dsfield; | 51 | int dsfield; |
45 | 52 | ||
@@ -52,16 +59,24 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
52 | skb->h.ipv6h = top_iph + 1; | 59 | skb->h.ipv6h = top_iph + 1; |
53 | 60 | ||
54 | top_iph->version = 6; | 61 | top_iph->version = 6; |
55 | top_iph->priority = iph->priority; | 62 | if (xdst->route->ops->family == AF_INET6) { |
56 | top_iph->flow_lbl[0] = iph->flow_lbl[0]; | 63 | top_iph->priority = iph->priority; |
57 | top_iph->flow_lbl[1] = iph->flow_lbl[1]; | 64 | top_iph->flow_lbl[0] = iph->flow_lbl[0]; |
58 | top_iph->flow_lbl[2] = iph->flow_lbl[2]; | 65 | top_iph->flow_lbl[1] = iph->flow_lbl[1]; |
66 | top_iph->flow_lbl[2] = iph->flow_lbl[2]; | ||
67 | top_iph->nexthdr = IPPROTO_IPV6; | ||
68 | } else { | ||
69 | top_iph->priority = 0; | ||
70 | top_iph->flow_lbl[0] = 0; | ||
71 | top_iph->flow_lbl[1] = 0; | ||
72 | top_iph->flow_lbl[2] = 0; | ||
73 | top_iph->nexthdr = IPPROTO_IPIP; | ||
74 | } | ||
59 | dsfield = ipv6_get_dsfield(top_iph); | 75 | dsfield = ipv6_get_dsfield(top_iph); |
60 | dsfield = INET_ECN_encapsulate(dsfield, dsfield); | 76 | dsfield = INET_ECN_encapsulate(dsfield, dsfield); |
61 | if (x->props.flags & XFRM_STATE_NOECN) | 77 | if (x->props.flags & XFRM_STATE_NOECN) |
62 | dsfield &= ~INET_ECN_MASK; | 78 | dsfield &= ~INET_ECN_MASK; |
63 | ipv6_change_dsfield(top_iph, 0, dsfield); | 79 | ipv6_change_dsfield(top_iph, 0, dsfield); |
64 | top_iph->nexthdr = IPPROTO_IPV6; | ||
65 | top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); | 80 | top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); |
66 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | 81 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); |
67 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | 82 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); |
@@ -72,7 +87,8 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
72 | { | 87 | { |
73 | int err = -EINVAL; | 88 | int err = -EINVAL; |
74 | 89 | ||
75 | if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6) | 90 | if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6 |
91 | && skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPIP) | ||
76 | goto out; | 92 | goto out; |
77 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 93 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
78 | goto out; | 94 | goto out; |
@@ -81,10 +97,16 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
81 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 97 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) |
82 | goto out; | 98 | goto out; |
83 | 99 | ||
84 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | 100 | if (skb->nh.raw[IP6CB(skb)->nhoff] == IPPROTO_IPV6) { |
85 | ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); | 101 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) |
86 | if (!(x->props.flags & XFRM_STATE_NOECN)) | 102 | ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); |
87 | ipip6_ecn_decapsulate(skb); | 103 | if (!(x->props.flags & XFRM_STATE_NOECN)) |
104 | ipip6_ecn_decapsulate(skb); | ||
105 | } else { | ||
106 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
107 | ip6ip_ecn_decapsulate(skb); | ||
108 | skb->protocol = htons(ETH_P_IP); | ||
109 | } | ||
88 | skb->mac.raw = memmove(skb->data - skb->mac_len, | 110 | skb->mac.raw = memmove(skb->data - skb->mac_len, |
89 | skb->mac.raw, skb->mac_len); | 111 | skb->mac.raw, skb->mac_len); |
90 | skb->nh.raw = skb->data; | 112 | skb->nh.raw = skb->data; |