From 920b5ad85a53236dbd1cb1f1b7f93368b7418883 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Sat, 29 Jul 2023 07:40:52 +0000 Subject: [PATCH] iptfs: xfrm: generic iptfs support -- replace --- net/ipv4/esp4_offload.c | 5 ++++ net/ipv6/esp6_offload.c | 5 ++++ net/xfrm/xfrm_output.c | 60 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c index 3969fa805679cd..d04ba13288c232 100644 --- a/net/ipv4/esp4_offload.c +++ b/net/ipv4/esp4_offload.c @@ -184,6 +184,11 @@ static struct sk_buff *xfrm4_outer_mode_gso_segment(struct xfrm_state *x, return xfrm4_transport_gso_segment(x, skb, features); case XFRM_MODE_BEET: return xfrm4_beet_gso_segment(x, skb, features); +#if 0 + case XFRM_MODE_IPTFS: + /* XXX chopps: writeme */ + return xfrm4_iptfs_gso_segment(x, skb, features); +#endif } return ERR_PTR(-EOPNOTSUPP); diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index 75c02992c520f9..abd7283c817ec5 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c @@ -222,6 +222,11 @@ static struct sk_buff *xfrm6_outer_mode_gso_segment(struct xfrm_state *x, return xfrm6_transport_gso_segment(x, skb, features); case XFRM_MODE_BEET: return xfrm6_beet_gso_segment(x, skb, features); +#if 0 + case XFRM_MODE_IPTFS: + /* XXX chopps: writeme */ + return xfrm6_iptfs_gso_segment(x, skb, features); +#endif } return ERR_PTR(-EOPNOTSUPP); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 294003345a661b..8660da5254cd44 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -269,7 +269,8 @@ static int xfrm4_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb) * * The top IP header will be constructed per RFC 2401. */ -static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) +static int __xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb, + u8 ipproto, u8 hdradj) { bool small_ipv6 = (skb->protocol == htons(ETH_P_IPV6)) && (skb->len <= IPV6_MIN_MTU); struct dst_entry *dst = skb_dst(skb); @@ -279,7 +280,8 @@ static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) skb_set_inner_network_header(skb, skb_network_offset(skb)); skb_set_inner_transport_header(skb, skb_transport_offset(skb)); - skb_set_network_header(skb, -x->props.header_len); + /* backup to add space for the outer encap */ + skb_set_network_header(skb, -(x->props.header_len - hdradj)); skb->mac_header = skb->network_header + offsetof(struct iphdr, protocol); skb->transport_header = skb->network_header + sizeof(*top_iph); @@ -288,7 +290,7 @@ static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) top_iph->ihl = 5; top_iph->version = 4; - top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); + top_iph->protocol = ipproto; /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */ if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) @@ -314,8 +316,15 @@ static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) return 0; } +static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) +{ + u8 ipproto = xfrm_af2proto(skb_dst(skb)->ops->family); + return __xfrm4_tunnel_encap_add(x, skb, ipproto, 0); +} + #if IS_ENABLED(CONFIG_IPV6) -static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) +static int __xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb, + u8 nexthdr, u8 hdradj) { struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *top_iph; @@ -324,7 +333,7 @@ static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) skb_set_inner_network_header(skb, skb_network_offset(skb)); skb_set_inner_transport_header(skb, skb_transport_offset(skb)); - skb_set_network_header(skb, -x->props.header_len); + skb_set_network_header(skb, -(x->props.header_len - hdradj)); skb->mac_header = skb->network_header + offsetof(struct ipv6hdr, nexthdr); skb->transport_header = skb->network_header + sizeof(*top_iph); @@ -334,7 +343,7 @@ static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, sizeof(top_iph->flow_lbl)); - top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); + top_iph->nexthdr = nexthdr; if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) dsfield = 0; @@ -350,6 +359,12 @@ static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) return 0; } +static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) +{ + u8 nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); + return __xfrm6_tunnel_encap_add(x, skb, nexthdr, 0); +} + static int xfrm6_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *top_iph; @@ -449,6 +464,37 @@ static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) return -EAFNOSUPPORT; } +static int xfrm_prepare_iptfs_output(struct xfrm_state *x, struct sk_buff *skb) +{ + /* XXX what we really want to do is this: + * + * Add an extra_hdr_len to props along with header_len and trailer_len + * use this in the places that verify there's enough room saved in the + * skb_buff for the entire encap. Do *not* use this here in the + * encap_add functions, this way we do not have to subtract it back out + * like we are doing here.. So do a search on `header_len` and figure + * out which ones need to have extra_header_len added to them (all + * except here??) + */ +#if IS_ENABLED(CONFIG_XFRM_IPTFS) + /* XXX actually get this from the sub-type CC or non-CC mode */ + size_t hsz = sizeof(struct ip_iptfs_hdr); + + if (x->outer_mode.family == AF_INET) + return __xfrm4_tunnel_encap_add(x, skb, XFRM_PROTO_IPTFS, hsz); + else if (x->outer_mode.family == AF_INET6) { +#if IS_ENABLED(CONFIG_IPV6) + return __xfrm6_tunnel_encap_add(x, skb, XFRM_PROTO_IPTFS, hsz); +#else + WARN_ON_ONCE(1); + return -EAFNOSUPPORT; +#endif + } +#endif + WARN_ON_ONCE(1); + return -EOPNOTSUPP; +} + static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) { switch (x->props.mode) { @@ -459,6 +505,8 @@ static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) if (x->props.family == AF_INET6) return xfrm6_prepare_output(x, skb); break; + case XFRM_MODE_IPTFS: + return xfrm_prepare_iptfs_output(x, skb); case XFRM_MODE_TRANSPORT: if (x->props.family == AF_INET) return xfrm4_transport_output(x, skb);