This provides a way to cast in data from a netlink message while
checking for proper size.  It will be used in upcoming commit
when working with complex netlink messages.

Signed-off-by: Aaron Conole <[email protected]>
---
 lib/netlink.c                 | 24 ++++++++++++
 lib/netlink.h                 |  3 ++
 tests/library.at              |  1 +
 tests/test-netlink-policy.c   | 72 +++++++++++++++++++++++++++++++++++
 utilities/checkpatch_dict.txt |  1 +
 5 files changed, 101 insertions(+)

diff --git a/lib/netlink.c b/lib/netlink.c
index 446a0679ed..6ded92fe1e 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -630,6 +630,30 @@ nl_attr_oversized(size_t payload_size)
 {
     return payload_size > UINT16_MAX - NLA_HDRLEN;
 }
+
+/* Gets a pointer to the data portion of a netlink message.
+ * Returns 0 on success, or an appropriate error for excaptions. */
+int nl_msg_data(const struct nlmsghdr *nlh, size_t size, void **data)
+{
+    size_t payload_len;
+
+    if (!nlh || !data) {
+        return EINVAL;
+    }
+
+    if (nlh->nlmsg_len < NLMSG_HDRLEN) {
+        return EBADMSG;
+    }
+
+    payload_len = nlh->nlmsg_len - NLMSG_HDRLEN;
+    if (payload_len < size) {
+        return EBADMSG;
+    }
+
+    *data = (char *) nlh + NLMSG_HDRLEN;
+    return 0;
+}
+
 
 /* Attributes. */
 
diff --git a/lib/netlink.h b/lib/netlink.h
index d98ef3a989..cf66458f0c 100644
--- a/lib/netlink.h
+++ b/lib/netlink.h
@@ -107,6 +107,9 @@ void nl_msg_push_string(struct ofpbuf *, uint16_t type, 
const char *value);
 /* Separating buffers into individual messages. */
 struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg);
 
+/* Data accessor for getting at the nlmsg data */
+int nl_msg_data(const struct nlmsghdr *, size_t, void **);
+
 /* Sizes of various attribute types, in bytes, including the attribute header
  * and padding.
  *
diff --git a/tests/library.at b/tests/library.at
index 82ac80a271..c5d0648b54 100644
--- a/tests/library.at
+++ b/tests/library.at
@@ -284,6 +284,7 @@ AT_SETUP([netlink policy])
 AT_SKIP_IF([test "$IS_WIN32" = "yes"])
 AT_SKIP_IF([test "$IS_BSD" = "yes"])
 AT_CHECK([ovstest test-netlink-policy ll_addr], [0])
+AT_CHECK([ovstest test-netlink-policy payload], [0])
 AT_CLEANUP
 
 AT_SETUP([mpsc-queue module])
diff --git a/tests/test-netlink-policy.c b/tests/test-netlink-policy.c
index 55083935a8..a0b82c990e 100644
--- a/tests/test-netlink-policy.c
+++ b/tests/test-netlink-policy.c
@@ -16,6 +16,7 @@
 
 #include <config.h>
 
+#include <errno.h>
 #include <string.h>
 
 #include "netlink.h"
@@ -29,6 +30,12 @@ struct nlattr_fixture {
     uint8_t data[32];
 };
 
+struct nl_dummy_payload {
+    int x;
+    char y;
+};
+
+
 /* nla_len is an inline function in the kernel net/netlink header, which we
  * don't necessarilly have at build time, so provide our own with
  * non-conflicting name. */
@@ -39,6 +46,62 @@ _nla_len(const struct nlattr *nla) {
 
 #define TEST_POLICY_ATTR 42
 
+
+
+static void
+test_nl_valid_data(void)
+{
+    union {
+        struct nlmsghdr align;
+        char buf[NLMSG_HDRLEN + sizeof(struct nl_dummy_payload)];
+    } u;
+    struct nlmsghdr *nlh = (struct nlmsghdr *) &u.align;
+    struct nl_dummy_payload *p;
+
+    nlh->nlmsg_len = NLMSG_HDRLEN + sizeof *p;
+    nlh->nlmsg_type = 0;
+    nlh->nlmsg_flags = 0;
+    nlh->nlmsg_seq = 0;
+    nlh->nlmsg_pid = 0;
+
+    int err = nl_msg_data(nlh, sizeof *p, (void **)&p);
+    ovs_assert(err == 0);
+    ovs_assert(p == (void *)((char *) nlh + NLMSG_HDRLEN));
+}
+
+static void
+test_nl_only_header(void)
+{
+    union {
+        struct nlmsghdr align;
+        char buf[NLMSG_HDRLEN + sizeof(struct nl_dummy_payload)];
+    } u;
+    struct nlmsghdr *nlh = (struct nlmsghdr *) &u.align;
+    struct nl_dummy_payload *p;
+
+    /* Too short: length only header, no payload */
+    nlh->nlmsg_len = NLMSG_HDRLEN;
+    int err = nl_msg_data(nlh, sizeof *p, (void **)&p);
+    ovs_assert(err == EBADMSG);
+}
+
+static void
+test_nl_short_data(void)
+{
+    union {
+        struct nlmsghdr align;
+        char buf[NLMSG_HDRLEN + 1]; /* only 1 byte of payload */
+    } u;
+    struct nlmsghdr *nlh = (struct nlmsghdr *) &u.align;
+    char *p;
+
+    nlh->nlmsg_len = sizeof u.buf;
+    int err = nl_msg_data(nlh, 8, (void **)&p);
+    ovs_assert(err == EBADMSG);
+}
+
+
+
 static void
 test_nl_policy_parse_ll_addr(struct ovs_cmdl_context *ctx OVS_UNUSED) {
     struct nl_policy policy[] = {
@@ -134,8 +197,17 @@ test_nl_policy_parse_ll_addr(struct ovs_cmdl_context *ctx 
OVS_UNUSED) {
     memset(&attrs, 0, sizeof *attrs);
 }
 
+static void
+test_nl_payload(struct ovs_cmdl_context *ctx OVS_UNUSED)
+{
+    test_nl_valid_data();
+    test_nl_only_header();
+    test_nl_short_data();
+}
+
 static const struct ovs_cmdl_command commands[] = {
     {"ll_addr", "", 0, 0, test_nl_policy_parse_ll_addr, OVS_RO},
+    {"payload", "", 0, 0, test_nl_payload, OVS_RO},
     {NULL, NULL, 0, 0, NULL, OVS_RO},
 };
 
diff --git a/utilities/checkpatch_dict.txt b/utilities/checkpatch_dict.txt
index b131290adc..efe2cfdb31 100644
--- a/utilities/checkpatch_dict.txt
+++ b/utilities/checkpatch_dict.txt
@@ -184,6 +184,7 @@ networkmanager
 nic
 nicira
 nics
+nlmsg
 ns
 nsec
 num
-- 
2.51.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to