[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1559253021-16772-3-git-send-email-tom@quantonium.net>
Date: Thu, 30 May 2019 14:50:17 -0700
From: Tom Herbert <tom@...bertland.com>
To: davem@...emloft.net, netdev@...r.kernel.org, dlebrun@...gle.com
Cc: Tom Herbert <tom@...ntonium.net>
Subject: [PATCH net-next 2/6] seg6: Implement a TLV parsing loop
Implement a TLV parsing loop for segment routing. The code is uniform
with other instances of TLV parsing loops in the stack (e.g. parsing of
Hop-by-Hop and Destination Options).
seg_validate_srh calls this function. Note, this fixes a bug in the
original parsing code that PAD1 was not supported.
Signed-off-by: Tom Herbert <tom@...ntonium.net>
---
include/net/seg6.h | 6 ++++++
net/ipv6/seg6.c | 60 +++++++++++++++++++++++++++++++-----------------------
2 files changed, 40 insertions(+), 26 deletions(-)
diff --git a/include/net/seg6.h b/include/net/seg6.h
index 8b2dc68..563d4a6 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -38,6 +38,11 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
}
+static inline unsigned int seg6_tlv_offset(struct ipv6_sr_hdr *srh)
+{
+ return sizeof(*srh) + ((srh->first_segment + 1) << 4);
+}
+
struct seg6_pernet_data {
struct mutex lock;
struct in6_addr __rcu *tun_src;
@@ -62,6 +67,7 @@ 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_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);
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
index 0c5479e..e461357 100644
--- a/net/ipv6/seg6.c
+++ b/net/ipv6/seg6.c
@@ -30,44 +30,52 @@
#include <net/seg6_hmac.h>
#endif
-bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
+bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
{
- int trailing;
- unsigned int tlv_offset;
+ int len = ipv6_optlen((struct ipv6_opt_hdr *)srh);
+ unsigned char *opt = (unsigned char *)srh;
+ unsigned int off;
- if (srh->type != IPV6_SRCRT_TYPE_4)
- return false;
+ off = seg6_tlv_offset(srh);
+ len -= off;
- if (((srh->hdrlen + 1) << 3) != len)
- return false;
+ while (len > 0) {
+ struct sr6_tlv *tlv;
+ unsigned int optlen;
- if (srh->segments_left > srh->first_segment)
- return false;
+ switch (opt[off]) {
+ case SR6_TLV_PAD1:
+ optlen = 1;
+ break;
+ default:
+ if (len < sizeof(*tlv))
+ return false;
- tlv_offset = sizeof(*srh) + ((srh->first_segment + 1) << 4);
+ tlv = (struct sr6_tlv *)&opt[off];
+ optlen = sizeof(*tlv) + tlv->len;
- trailing = len - tlv_offset;
- if (trailing < 0)
- return false;
+ break;
+ }
- while (trailing) {
- struct sr6_tlv *tlv;
- unsigned int tlv_len;
+ off += optlen;
+ len -= optlen;
+ }
- if (trailing < sizeof(*tlv))
- return false;
+ return !len;
+}
- tlv = (struct sr6_tlv *)((unsigned char *)srh + tlv_offset);
- tlv_len = sizeof(*tlv) + tlv->len;
+bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
+{
+ if (srh->type != IPV6_SRCRT_TYPE_4)
+ return false;
- trailing -= tlv_len;
- if (trailing < 0)
- return false;
+ if (ipv6_optlen((struct ipv6_opt_hdr *)srh) != len)
+ return false;
- tlv_offset += tlv_len;
- }
+ if (srh->segments_left > srh->first_segment)
+ return false;
- return true;
+ return __seg6_parse_srh(srh);
}
static struct genl_family seg6_genl_family;
--
2.7.4
Powered by blists - more mailing lists