diff options
| -rw-r--r-- | include/net/xfrm.h | 13 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_mode_beet.c | 63 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 49 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_mode_beet.c | 58 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 36 | ||||
| -rw-r--r-- | net/xfrm/xfrm_output.c | 212 |
6 files changed, 207 insertions, 224 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index bdda545cf740..4351444c10fc 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -423,19 +423,6 @@ int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned sh | |||
| 423 | int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family); | 423 | int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family); |
| 424 | 424 | ||
| 425 | struct xfrm_mode { | 425 | struct xfrm_mode { |
| 426 | /* | ||
| 427 | * Add encapsulation header. | ||
| 428 | * | ||
| 429 | * On exit, the transport header will be set to the start of the | ||
| 430 | * encapsulation header to be filled in by x->type->output and | ||
| 431 | * the mac header will be set to the nextheader (protocol for | ||
| 432 | * IPv4) field of the extension header directly preceding the | ||
| 433 | * encapsulation header, or in its absence, that of the top IP | ||
| 434 | * header. The value of the network header will always point | ||
| 435 | * to the top IP header while skb->data will point to the payload. | ||
| 436 | */ | ||
| 437 | int (*output2)(struct xfrm_state *x,struct sk_buff *skb); | ||
| 438 | |||
| 439 | struct xfrm_state_afinfo *afinfo; | 426 | struct xfrm_state_afinfo *afinfo; |
| 440 | struct module *owner; | 427 | struct module *owner; |
| 441 | u8 encap; | 428 | u8 encap; |
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index 500960172933..ba84b278e627 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c | |||
| @@ -17,71 +17,8 @@ | |||
| 17 | #include <net/ip.h> | 17 | #include <net/ip.h> |
| 18 | #include <net/xfrm.h> | 18 | #include <net/xfrm.h> |
| 19 | 19 | ||
| 20 | static 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 | |||
| 35 | /* Add encapsulation header. | ||
| 36 | * | ||
| 37 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 38 | */ | ||
| 39 | static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 40 | { | ||
| 41 | struct ip_beet_phdr *ph; | ||
| 42 | struct iphdr *top_iph; | ||
| 43 | int hdrlen, optlen; | ||
| 44 | |||
| 45 | hdrlen = 0; | ||
| 46 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 47 | if (unlikely(optlen)) | ||
| 48 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 49 | |||
| 50 | skb_set_network_header(skb, -x->props.header_len - | ||
| 51 | hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); | ||
| 52 | if (x->sel.family != AF_INET6) | ||
| 53 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 54 | skb->mac_header = skb->network_header + | ||
| 55 | offsetof(struct iphdr, protocol); | ||
| 56 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 57 | |||
| 58 | xfrm4_beet_make_header(skb); | ||
| 59 | |||
| 60 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen); | ||
| 61 | |||
| 62 | top_iph = ip_hdr(skb); | ||
| 63 | |||
| 64 | if (unlikely(optlen)) { | ||
| 65 | BUG_ON(optlen < 0); | ||
| 66 | |||
| 67 | ph->padlen = 4 - (optlen & 4); | ||
| 68 | ph->hdrlen = optlen / 8; | ||
| 69 | ph->nexthdr = top_iph->protocol; | ||
| 70 | if (ph->padlen) | ||
| 71 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 72 | |||
| 73 | top_iph->protocol = IPPROTO_BEETPH; | ||
| 74 | top_iph->ihl = sizeof(struct iphdr) / 4; | ||
| 75 | } | ||
| 76 | |||
| 77 | top_iph->saddr = x->props.saddr.a4; | ||
| 78 | top_iph->daddr = x->id.daddr.a4; | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | 20 | ||
| 83 | static struct xfrm_mode xfrm4_beet_mode = { | 21 | static struct xfrm_mode xfrm4_beet_mode = { |
| 84 | .output2 = xfrm4_beet_output, | ||
| 85 | .owner = THIS_MODULE, | 22 | .owner = THIS_MODULE, |
| 86 | .encap = XFRM_MODE_BEET, | 23 | .encap = XFRM_MODE_BEET, |
| 87 | .flags = XFRM_MODE_FLAG_TUNNEL, | 24 | .flags = XFRM_MODE_FLAG_TUNNEL, |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 31645319aaeb..b2b132c800fc 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
| @@ -15,56 +15,7 @@ | |||
| 15 | #include <net/ip.h> | 15 | #include <net/ip.h> |
| 16 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
| 17 | 17 | ||
| 18 | /* Add encapsulation header. | ||
| 19 | * | ||
| 20 | * The top IP header will be constructed per RFC 2401. | ||
| 21 | */ | ||
| 22 | static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 23 | { | ||
| 24 | struct dst_entry *dst = skb_dst(skb); | ||
| 25 | struct iphdr *top_iph; | ||
| 26 | int flags; | ||
| 27 | |||
| 28 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 29 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 30 | |||
| 31 | skb_set_network_header(skb, -x->props.header_len); | ||
| 32 | skb->mac_header = skb->network_header + | ||
| 33 | offsetof(struct iphdr, protocol); | ||
| 34 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 35 | top_iph = ip_hdr(skb); | ||
| 36 | |||
| 37 | top_iph->ihl = 5; | ||
| 38 | top_iph->version = 4; | ||
| 39 | |||
| 40 | top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 41 | |||
| 42 | /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */ | ||
| 43 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 44 | top_iph->tos = 0; | ||
| 45 | else | ||
| 46 | top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 47 | top_iph->tos = INET_ECN_encapsulate(top_iph->tos, | ||
| 48 | XFRM_MODE_SKB_CB(skb)->tos); | ||
| 49 | |||
| 50 | flags = x->props.flags; | ||
| 51 | if (flags & XFRM_STATE_NOECN) | ||
| 52 | IP_ECN_clear(top_iph); | ||
| 53 | |||
| 54 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
| 55 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); | ||
| 56 | |||
| 57 | top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 58 | |||
| 59 | top_iph->saddr = x->props.saddr.a4; | ||
| 60 | top_iph->daddr = x->id.daddr.a4; | ||
| 61 | ip_select_ident(dev_net(dst->dev), skb, NULL); | ||
| 62 | |||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static struct xfrm_mode xfrm4_tunnel_mode = { | 18 | static struct xfrm_mode xfrm4_tunnel_mode = { |
| 67 | .output2 = xfrm4_mode_tunnel_output, | ||
| 68 | .owner = THIS_MODULE, | 19 | .owner = THIS_MODULE, |
| 69 | .encap = XFRM_MODE_TUNNEL, | 20 | .encap = XFRM_MODE_TUNNEL, |
| 70 | .flags = XFRM_MODE_FLAG_TUNNEL, | 21 | .flags = XFRM_MODE_FLAG_TUNNEL, |
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index a0537b4f62f8..1c4a76bdd889 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c | |||
| @@ -19,65 +19,7 @@ | |||
| 19 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
| 20 | #include <net/xfrm.h> | 20 | #include <net/xfrm.h> |
| 21 | 21 | ||
| 22 | static void xfrm6_beet_make_header(struct sk_buff *skb) | ||
| 23 | { | ||
| 24 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 25 | |||
| 26 | iph->version = 6; | ||
| 27 | |||
| 28 | memcpy(iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 29 | sizeof(iph->flow_lbl)); | ||
| 30 | iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol; | ||
| 31 | |||
| 32 | ipv6_change_dsfield(iph, 0, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 33 | iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl; | ||
| 34 | } | ||
| 35 | |||
| 36 | /* Add encapsulation header. | ||
| 37 | * | ||
| 38 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 39 | */ | ||
| 40 | static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 41 | { | ||
| 42 | struct ipv6hdr *top_iph; | ||
| 43 | struct ip_beet_phdr *ph; | ||
| 44 | int optlen, hdr_len; | ||
| 45 | |||
| 46 | hdr_len = 0; | ||
| 47 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 48 | if (unlikely(optlen)) | ||
| 49 | hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 50 | |||
| 51 | skb_set_network_header(skb, -x->props.header_len - hdr_len); | ||
| 52 | if (x->sel.family != AF_INET6) | ||
| 53 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 54 | skb->mac_header = skb->network_header + | ||
| 55 | offsetof(struct ipv6hdr, nexthdr); | ||
| 56 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 57 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len); | ||
| 58 | |||
| 59 | xfrm6_beet_make_header(skb); | ||
| 60 | |||
| 61 | top_iph = ipv6_hdr(skb); | ||
| 62 | if (unlikely(optlen)) { | ||
| 63 | |||
| 64 | BUG_ON(optlen < 0); | ||
| 65 | |||
| 66 | ph->padlen = 4 - (optlen & 4); | ||
| 67 | ph->hdrlen = optlen / 8; | ||
| 68 | ph->nexthdr = top_iph->nexthdr; | ||
| 69 | if (ph->padlen) | ||
| 70 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 71 | |||
| 72 | top_iph->nexthdr = IPPROTO_BEETPH; | ||
| 73 | } | ||
| 74 | |||
| 75 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 76 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | static struct xfrm_mode xfrm6_beet_mode = { | 22 | static struct xfrm_mode xfrm6_beet_mode = { |
| 80 | .output2 = xfrm6_beet_output, | ||
| 81 | .owner = THIS_MODULE, | 23 | .owner = THIS_MODULE, |
| 82 | .encap = XFRM_MODE_BEET, | 24 | .encap = XFRM_MODE_BEET, |
| 83 | .flags = XFRM_MODE_FLAG_TUNNEL, | 25 | .flags = XFRM_MODE_FLAG_TUNNEL, |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 79c57decb472..e5c928dd70e3 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
| @@ -22,43 +22,7 @@ | |||
| 22 | * | 22 | * |
| 23 | * The top IP header will be constructed per RFC 2401. | 23 | * The top IP header will be constructed per RFC 2401. |
| 24 | */ | 24 | */ |
| 25 | static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 26 | { | ||
| 27 | struct dst_entry *dst = skb_dst(skb); | ||
| 28 | struct ipv6hdr *top_iph; | ||
| 29 | int dsfield; | ||
| 30 | |||
| 31 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 32 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 33 | |||
| 34 | skb_set_network_header(skb, -x->props.header_len); | ||
| 35 | skb->mac_header = skb->network_header + | ||
| 36 | offsetof(struct ipv6hdr, nexthdr); | ||
| 37 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 38 | top_iph = ipv6_hdr(skb); | ||
| 39 | |||
| 40 | top_iph->version = 6; | ||
| 41 | |||
| 42 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 43 | sizeof(top_iph->flow_lbl)); | ||
| 44 | top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 45 | |||
| 46 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 47 | dsfield = 0; | ||
| 48 | else | ||
| 49 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 50 | dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 51 | if (x->props.flags & XFRM_STATE_NOECN) | ||
| 52 | dsfield &= ~INET_ECN_MASK; | ||
| 53 | ipv6_change_dsfield(top_iph, 0, dsfield); | ||
| 54 | top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 55 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 56 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static struct xfrm_mode xfrm6_tunnel_mode = { | 25 | static struct xfrm_mode xfrm6_tunnel_mode = { |
| 61 | .output2 = xfrm6_mode_tunnel_output, | ||
| 62 | .owner = THIS_MODULE, | 26 | .owner = THIS_MODULE, |
| 63 | .encap = XFRM_MODE_TUNNEL, | 27 | .encap = XFRM_MODE_TUNNEL, |
| 64 | .flags = XFRM_MODE_FLAG_TUNNEL, | 28 | .flags = XFRM_MODE_FLAG_TUNNEL, |
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 05926dcf5d17..9bdf16f13606 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
| @@ -17,8 +17,11 @@ | |||
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
| 19 | #include <net/dst.h> | 19 | #include <net/dst.h> |
| 20 | #include <net/inet_ecn.h> | ||
| 20 | #include <net/xfrm.h> | 21 | #include <net/xfrm.h> |
| 21 | 22 | ||
| 23 | #include "xfrm_inout.h" | ||
| 24 | |||
| 22 | static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb); | 25 | static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb); |
| 23 | static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); | 26 | static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); |
| 24 | 27 | ||
| @@ -141,6 +144,190 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 141 | #endif | 144 | #endif |
| 142 | } | 145 | } |
| 143 | 146 | ||
| 147 | /* Add encapsulation header. | ||
| 148 | * | ||
| 149 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 150 | */ | ||
| 151 | static int xfrm4_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 152 | { | ||
| 153 | struct ip_beet_phdr *ph; | ||
| 154 | struct iphdr *top_iph; | ||
| 155 | int hdrlen, optlen; | ||
| 156 | |||
| 157 | hdrlen = 0; | ||
| 158 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 159 | if (unlikely(optlen)) | ||
| 160 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 161 | |||
| 162 | skb_set_network_header(skb, -x->props.header_len - hdrlen + | ||
| 163 | (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); | ||
| 164 | if (x->sel.family != AF_INET6) | ||
| 165 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 166 | skb->mac_header = skb->network_header + | ||
| 167 | offsetof(struct iphdr, protocol); | ||
| 168 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 169 | |||
| 170 | xfrm4_beet_make_header(skb); | ||
| 171 | |||
| 172 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen); | ||
| 173 | |||
| 174 | top_iph = ip_hdr(skb); | ||
| 175 | |||
| 176 | if (unlikely(optlen)) { | ||
| 177 | if (WARN_ON(optlen < 0)) | ||
| 178 | return -EINVAL; | ||
| 179 | |||
| 180 | ph->padlen = 4 - (optlen & 4); | ||
| 181 | ph->hdrlen = optlen / 8; | ||
| 182 | ph->nexthdr = top_iph->protocol; | ||
| 183 | if (ph->padlen) | ||
| 184 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 185 | |||
| 186 | top_iph->protocol = IPPROTO_BEETPH; | ||
| 187 | top_iph->ihl = sizeof(struct iphdr) / 4; | ||
| 188 | } | ||
| 189 | |||
| 190 | top_iph->saddr = x->props.saddr.a4; | ||
| 191 | top_iph->daddr = x->id.daddr.a4; | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | /* Add encapsulation header. | ||
| 197 | * | ||
| 198 | * The top IP header will be constructed per RFC 2401. | ||
| 199 | */ | ||
| 200 | static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 201 | { | ||
| 202 | struct dst_entry *dst = skb_dst(skb); | ||
| 203 | struct iphdr *top_iph; | ||
| 204 | int flags; | ||
| 205 | |||
| 206 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 207 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 208 | |||
| 209 | skb_set_network_header(skb, -x->props.header_len); | ||
| 210 | skb->mac_header = skb->network_header + | ||
| 211 | offsetof(struct iphdr, protocol); | ||
| 212 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 213 | top_iph = ip_hdr(skb); | ||
| 214 | |||
| 215 | top_iph->ihl = 5; | ||
| 216 | top_iph->version = 4; | ||
| 217 | |||
| 218 | top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 219 | |||
| 220 | /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */ | ||
| 221 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 222 | top_iph->tos = 0; | ||
| 223 | else | ||
| 224 | top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 225 | top_iph->tos = INET_ECN_encapsulate(top_iph->tos, | ||
| 226 | XFRM_MODE_SKB_CB(skb)->tos); | ||
| 227 | |||
| 228 | flags = x->props.flags; | ||
| 229 | if (flags & XFRM_STATE_NOECN) | ||
| 230 | IP_ECN_clear(top_iph); | ||
| 231 | |||
| 232 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
| 233 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); | ||
| 234 | |||
| 235 | top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 236 | |||
| 237 | top_iph->saddr = x->props.saddr.a4; | ||
| 238 | top_iph->daddr = x->id.daddr.a4; | ||
| 239 | ip_select_ident(dev_net(dst->dev), skb, NULL); | ||
| 240 | |||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 245 | static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 246 | { | ||
| 247 | struct dst_entry *dst = skb_dst(skb); | ||
| 248 | struct ipv6hdr *top_iph; | ||
| 249 | int dsfield; | ||
| 250 | |||
| 251 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 252 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 253 | |||
| 254 | skb_set_network_header(skb, -x->props.header_len); | ||
| 255 | skb->mac_header = skb->network_header + | ||
| 256 | offsetof(struct ipv6hdr, nexthdr); | ||
| 257 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 258 | top_iph = ipv6_hdr(skb); | ||
| 259 | |||
| 260 | top_iph->version = 6; | ||
| 261 | |||
| 262 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 263 | sizeof(top_iph->flow_lbl)); | ||
| 264 | top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 265 | |||
| 266 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 267 | dsfield = 0; | ||
| 268 | else | ||
| 269 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 270 | dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 271 | if (x->props.flags & XFRM_STATE_NOECN) | ||
| 272 | dsfield &= ~INET_ECN_MASK; | ||
| 273 | ipv6_change_dsfield(top_iph, 0, dsfield); | ||
| 274 | top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 275 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 276 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int xfrm6_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 281 | { | ||
| 282 | struct ipv6hdr *top_iph; | ||
| 283 | struct ip_beet_phdr *ph; | ||
| 284 | int optlen, hdr_len; | ||
| 285 | |||
| 286 | hdr_len = 0; | ||
| 287 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 288 | if (unlikely(optlen)) | ||
| 289 | hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 290 | |||
| 291 | skb_set_network_header(skb, -x->props.header_len - hdr_len); | ||
| 292 | if (x->sel.family != AF_INET6) | ||
| 293 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 294 | skb->mac_header = skb->network_header + | ||
| 295 | offsetof(struct ipv6hdr, nexthdr); | ||
| 296 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 297 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len); | ||
| 298 | |||
| 299 | xfrm6_beet_make_header(skb); | ||
| 300 | |||
| 301 | top_iph = ipv6_hdr(skb); | ||
| 302 | if (unlikely(optlen)) { | ||
| 303 | if (WARN_ON(optlen < 0)) | ||
| 304 | return -EINVAL; | ||
| 305 | |||
| 306 | ph->padlen = 4 - (optlen & 4); | ||
| 307 | ph->hdrlen = optlen / 8; | ||
| 308 | ph->nexthdr = top_iph->nexthdr; | ||
| 309 | if (ph->padlen) | ||
| 310 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 311 | |||
| 312 | top_iph->nexthdr = IPPROTO_BEETPH; | ||
| 313 | } | ||
| 314 | |||
| 315 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 316 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | #endif | ||
| 320 | |||
| 321 | /* Add encapsulation header. | ||
| 322 | * | ||
| 323 | * On exit, the transport header will be set to the start of the | ||
| 324 | * encapsulation header to be filled in by x->type->output and the mac | ||
| 325 | * header will be set to the nextheader (protocol for IPv4) field of the | ||
| 326 | * extension header directly preceding the encapsulation header, or in | ||
| 327 | * its absence, that of the top IP header. | ||
| 328 | * The value of the network header will always point to the top IP header | ||
| 329 | * while skb->data will point to the payload. | ||
| 330 | */ | ||
| 144 | static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | 331 | static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) |
| 145 | { | 332 | { |
| 146 | int err; | 333 | int err; |
| @@ -152,7 +339,15 @@ static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 152 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; | 339 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; |
| 153 | skb->protocol = htons(ETH_P_IP); | 340 | skb->protocol = htons(ETH_P_IP); |
| 154 | 341 | ||
| 155 | return x->outer_mode->output2(x, skb); | 342 | switch (x->outer_mode->encap) { |
| 343 | case XFRM_MODE_BEET: | ||
| 344 | return xfrm4_beet_encap_add(x, skb); | ||
| 345 | case XFRM_MODE_TUNNEL: | ||
| 346 | return xfrm4_tunnel_encap_add(x, skb); | ||
| 347 | } | ||
| 348 | |||
| 349 | WARN_ON_ONCE(1); | ||
| 350 | return -EOPNOTSUPP; | ||
| 156 | } | 351 | } |
| 157 | 352 | ||
| 158 | static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | 353 | static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) |
| @@ -167,11 +362,18 @@ static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 167 | skb->ignore_df = 1; | 362 | skb->ignore_df = 1; |
| 168 | skb->protocol = htons(ETH_P_IPV6); | 363 | skb->protocol = htons(ETH_P_IPV6); |
| 169 | 364 | ||
| 170 | return x->outer_mode->output2(x, skb); | 365 | switch (x->outer_mode->encap) { |
| 171 | #else | 366 | case XFRM_MODE_BEET: |
| 172 | WARN_ON_ONCE(1); | 367 | return xfrm6_beet_encap_add(x, skb); |
| 173 | return -EOPNOTSUPP; | 368 | case XFRM_MODE_TUNNEL: |
| 369 | return xfrm6_tunnel_encap_add(x, skb); | ||
| 370 | default: | ||
| 371 | WARN_ON_ONCE(1); | ||
| 372 | return -EOPNOTSUPP; | ||
| 373 | } | ||
| 174 | #endif | 374 | #endif |
| 375 | WARN_ON_ONCE(1); | ||
| 376 | return -EAFNOSUPPORT; | ||
| 175 | } | 377 | } |
| 176 | 378 | ||
| 177 | static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) | 379 | static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) |
