[PATCH net v3 3/4] psp: support ipv6 extension headers in psp_dev_encapsulate()
From: Todd Freed
Date: Fri Oct 23 2026 - 19:49:59 EST
psp_dev_encapsulate() inserts the udp and psp headers and rewrites the
l3 next header to udp.
if the packet is an ipv6 packet with extension headers, the transport
header comes after them, so rewriting the next header of the ipv6 fixed
header produces a malformed packet.
a psp tcp socket emits such packets if certain socket options are set on
it (e.g. IPV6_DSTOPTS). with mlx5, these packets also go out
unencrypted.
fix by walking the extension header chain to rewrite the nexthdr on the
last one in the chain instead. the walk also rejects packets with
extension headers that aren't supported in transport mode,
- NEXTHDR_FRAGMENT. this could work, but udp+psp would need to come
before it, which is different than how the other option types are
handled. for now, keep fragments unsupported for transport mode.
- NEXTHDR_AUTH. changing what follows would break the AH ICV. Also, AH
adds little incremental value when used with psp, whose ICV already
authenticates the payload. AH remains unsupported for psp transport
mode.
note that the stack doesn't fragment ipv6 tcp packets, so a psp socket
won't be able to exercise the tx fragment path.
Suggested-by: Daniel Zahka <daniel.zahka@xxxxxxxxx>
Fixes: fc724515741a ("psp: provide encapsulation helper for drivers")
Signed-off-by: Todd Freed <toddfreed@xxxxxxxx>
---
net/psp/psp_main.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 946047440ed3..e6d2136cb9a7 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -277,7 +277,7 @@ static void psp_write_headers(struct net *net, struct sk_buff *skb, __be32 spi,
}
/* Encapsulate a TCP packet with PSP by adding the UDP+PSP headers and filling
- * them in.
+ * them in. With IPv6, they go after any extension headers.
*/
bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi,
u8 ver, __be16 sport)
@@ -285,10 +285,17 @@ bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi,
u32 network_len = skb_network_header_len(skb);
u32 ethr_len = skb_mac_header_len(skb);
u32 bufflen = ethr_len + network_len;
+ int nh_off = 0;
- if (skb->protocol != htons(ETH_P_IP) &&
- skb->protocol != htons(ETH_P_IPV6))
+ if (skb->protocol == htons(ETH_P_IPV6)) {
+ /* UDP + PSP after the extension headers, if any */
+ nh_off = psp_ipv6_nexthdr_off(skb_network_header(skb),
+ network_len);
+ if (nh_off < 0)
+ return false;
+ } else if (skb->protocol != htons(ETH_P_IP)) {
return false;
+ }
if (skb_cow_head(skb, PSP_ENCAP_HLEN))
return false;
@@ -306,7 +313,7 @@ bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi,
ip_hdr(skb)->check =
ip_fast_csum((u8 *)ip_hdr(skb), ip_hdr(skb)->ihl);
} else {
- ipv6_hdr(skb)->nexthdr = IPPROTO_UDP;
+ skb_network_header(skb)[nh_off] = IPPROTO_UDP;
be16_add_cpu(&ipv6_hdr(skb)->payload_len, PSP_ENCAP_HLEN);
}
--
2.53.0-Meta