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
