@@ -17,6 +17,7 @@
#include <linux/net.h>
#include <linux/ipv6.h>
#include <linux/seg6.h>
+#include <linux/seg6_hmac.h>
#include <linux/rhashtable-types.h>
static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
@@ -67,11 +68,20 @@ extern void seg6_iptunnel_exit(void);
extern int seg6_local_init(void);
extern void seg6_local_exit(void);
-extern bool __seg6_parse_srh(struct ipv6_sr_hdr *srh);
+extern bool __seg6_parse_srh(struct ipv6_sr_hdr *srh,
+ struct sr6_tlv_hmac **hmacp);
extern bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len);
extern int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
int proto);
extern int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh);
extern int seg6_lookup_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
u32 tbl_id);
+
+static inline struct sr6_tlv_hmac *seg6_find_hmac_tlv(struct ipv6_sr_hdr *srh)
+{
+ struct sr6_tlv_hmac *hmacp = NULL;
+
+ return __seg6_parse_srh(srh, &hmacp) ? hmacp : NULL;
+}
+
#endif
@@ -36,14 +36,11 @@ struct ipv6_sr_hdr {
#define SR6_FLAG1_PROTECTED (1 << 6)
#define SR6_FLAG1_OAM (1 << 5)
#define SR6_FLAG1_ALERT (1 << 4)
-#define SR6_FLAG1_HMAC (1 << 3)
#define SR6_TLV_PAD1 0
#define SR6_TLV_PADDING 1
#define SR6_TLV_HMAC 5
-#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
-
struct sr6_tlv {
__u8 type;
__u8 len;
@@ -922,7 +922,7 @@ static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
}
#ifdef CONFIG_IPV6_SEG6_HMAC
- if (sr_has_hmac(sr_phdr)) {
+ if (seg6_find_hmac_tlv(sr_phdr)) {
struct net *net = NULL;
if (skb->dev)
@@ -30,7 +30,7 @@
#include <net/seg6_hmac.h>
#endif
-bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
+bool __seg6_parse_srh(struct ipv6_sr_hdr *srh, struct sr6_tlv_hmac **hmacp)
{
int len = ipv6_optlen((struct ipv6_opt_hdr *)srh);
unsigned char *opt = (unsigned char *)srh;
@@ -39,6 +39,8 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
off = seg6_tlv_offset(srh);
len -= off;
+ *hmacp = NULL;
+
while (len > 0) {
struct sr6_tlv *tlv;
unsigned int optlen;
@@ -47,6 +49,10 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
case SR6_TLV_PAD1:
optlen = 1;
break;
+ case SR6_TLV_HMAC:
+ if (!*hmacp)
+ *hmacp = (struct sr6_tlv_hmac *)&opt[off];
+ /* Fall through */
default:
if (len < sizeof(*tlv))
return false;
@@ -66,6 +72,8 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
{
+ struct sr6_tlv_hmac *hmacp;
+
if (srh->type != IPV6_SRCRT_TYPE_4)
return false;
@@ -75,7 +83,7 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
if (srh->segments_left > srh->first_segment)
return false;
- return __seg6_parse_srh(srh);
+ return __seg6_parse_srh(srh, &hmacp);
}
static struct genl_family seg6_genl_family;
@@ -95,13 +95,11 @@ static struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh)
if (srh->hdrlen < (srh->first_segment + 1) * 2 + 5)
return NULL;
- if (!sr_has_hmac(srh))
+ tlv = seg6_find_hmac_tlv(srh);
+ if (!tlv)
return NULL;
- tlv = (struct sr6_tlv_hmac *)
- ((char *)srh + ((srh->hdrlen + 1) << 3) - 40);
-
- if (tlv->tlvhdr.type != SR6_TLV_HMAC || tlv->tlvhdr.len != 38)
+ if (tlv->tlvhdr.len != sizeof(*tlv) - 2)
return NULL;
return tlv;
@@ -161,7 +161,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
#ifdef CONFIG_IPV6_SEG6_HMAC
- if (sr_has_hmac(isrh)) {
+ if (seg6_find_hmac_tlv(isrh)) {
err = seg6_push_hmac(net, &hdr->saddr, isrh);
if (unlikely(err))
return err;
@@ -211,7 +211,7 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
hdr->daddr = isrh->segments[isrh->first_segment];
#ifdef CONFIG_IPV6_SEG6_HMAC
- if (sr_has_hmac(isrh)) {
+ if (seg6_find_hmac_tlv(isrh)) {
struct net *net = dev_net(skb_dst(skb)->dev);
err = seg6_push_hmac(net, &hdr->saddr, isrh);
The HMAC flag is no longer defined in the SRH specification. Remove it and any uses of it. This includes removal of sr_has_hmac. We replace this function with seg6_find_hmac_tlv. That function parses (via __seg6_parse_srh) a TLV list and returns the pointer to an HMAC TLV if one exists. The parsing function also eliminates the assumption in seg6_get_tlv_hmac that the HMAC TLV must be the first TLV. Signed-off-by: Tom Herbert <tom@quantonium.net> --- include/net/seg6.h | 12 +++++++++++- include/uapi/linux/seg6.h | 3 --- net/ipv6/exthdrs.c | 2 +- net/ipv6/seg6.c | 12 ++++++++++-- net/ipv6/seg6_hmac.c | 8 +++----- net/ipv6/seg6_iptunnel.c | 4 ++-- 6 files changed, 27 insertions(+), 14 deletions(-)