From c8a0a5cdfba51f7de5d203aa13a97377b215515a Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 10 Jan 2008 12:35:38 +0100 Subject: Added additional parsing and validation functions for generic netlink Also adds better example documentation for generic netlink --- include/netlink/genl/genl.h | 8 ++++ include/netlink/msg.h | 1 + lib/cache.c | 2 +- lib/defs.h | 4 +- lib/genl/genl.c | 110 +++++++++++++++++++++++++++++++++----------- lib/msg.c | 12 ++++- 6 files changed, 106 insertions(+), 31 deletions(-) diff --git a/include/netlink/genl/genl.h b/include/netlink/genl/genl.h index 623ec3f..de142d0 100644 --- a/include/netlink/genl/genl.h +++ b/include/netlink/genl/genl.h @@ -13,6 +13,8 @@ #define NETLINK_GENL_H_ #include +#include +#include #ifdef __cplusplus extern "C" { @@ -25,6 +27,12 @@ extern int genl_send_simple(struct nl_handle *, int, int, extern void * genlmsg_put(struct nl_msg *, uint32_t, uint32_t, int, int, int, uint8_t, uint8_t); + +extern int genlmsg_valid_hdr(struct nlmsghdr *, int); +extern int genlmsg_validate(struct nlmsghdr *, int, int, + struct nla_policy *); +extern int genlmsg_parse(struct nlmsghdr *, int, struct nlattr **, + int, struct nla_policy *); extern void * genlmsg_data(const struct genlmsghdr *); extern int genlmsg_len(const struct genlmsghdr *); extern struct nlattr * genlmsg_attrdata(const struct genlmsghdr *, int); diff --git a/include/netlink/msg.h b/include/netlink/msg.h index d7da2cf..263503a 100644 --- a/include/netlink/msg.h +++ b/include/netlink/msg.h @@ -59,6 +59,7 @@ extern struct nlattr * nlmsg_attrdata(const struct nlmsghdr *, int); extern int nlmsg_attrlen(const struct nlmsghdr *, int); /* message parsing */ +extern int nlmsg_valid_hdr(const struct nlmsghdr *, int); extern int nlmsg_ok(const struct nlmsghdr *, int); extern struct nlmsghdr * nlmsg_next(struct nlmsghdr *, int *); extern int nlmsg_parse(struct nlmsghdr *, int, struct nlattr **, diff --git a/lib/cache.c b/lib/cache.c index c770765..c1fbea6 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -604,7 +604,7 @@ int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, { int i, err; - if (nlh->nlmsg_len < nlmsg_msg_size(ops->co_hdrsize)) { + if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) { err = nl_error(EINVAL, "netlink message too short to be " "of kind %s", ops->co_name); goto errout; diff --git a/lib/defs.h b/lib/defs.h index aa85c16..ac3916c 100644 --- a/lib/defs.h +++ b/lib/defs.h @@ -8,13 +8,13 @@ #define PACKAGE_NAME "libnl" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libnl 1.0-pre8" +#define PACKAGE_STRING "libnl 1.0-pre9" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libnl" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.0-pre8" +#define PACKAGE_VERSION "1.0-pre9" /* verbose errors */ /* #undef VERBOSE_ERRORS */ diff --git a/lib/genl/genl.c b/lib/genl/genl.c index c600579..cb067a5 100644 --- a/lib/genl/genl.c +++ b/lib/genl/genl.c @@ -32,43 +32,61 @@ * genlmsg_attrdata(ghdr, hdrlen)------------------------- * @endcode * - * @par 1) Creating a new generic netlink message + * @par Example * @code + * #include + * #include + * #include + * + * struct nl_handle *sock; * struct nl_msg *msg; - * struct myhdr { - * int a; - * int b; - * } *hdr; + * int family; * - * // Create a new empty netlink message - * msg = nlmsg_alloc(); + * // Allocate a new netlink socket + * sock = nl_handle_alloc(); * - * // Append the netlink and generic netlink message header, this - * // operation also reserves room for the family specific header. - * hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, sizeof(hdr), - * NLM_F_ECHO, MYOP, VERSION); + * // Connect to generic netlink socket on kernel side + * genl_connect(sock); * - * // Fill out your own family specific header. - * hdr->a = 1; - * hdr->b = 2; + * // Ask kernel to resolve family name to family id + * family = genl_ctrl_resolve(sock, "generic_netlink_family_name"); * - * // Append the optional attributes. - * nla_put_u32(msg, 1, 0x10); + * // Construct a generic netlink by allocating a new message, fill in + * // the header and append a simple integer attribute. + * msg = nlmsg_alloc(); + * genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, + * CMD_FOO_GET, FOO_VERSION); + * nla_put_u32(msg, ATTR_FOO, 123); * - * // Message is ready to be sent. - * nl_send_auto_complete(nl_handle, msg); + * // Send message over netlink socket + * nl_send_auto_complete(sock, msg); * - * // All done? Free the message. + * // Free message * nlmsg_free(msg); - * @endcode * - * @par 2) Sending of trivial messages - * @code - * // For trivial messages not requiring any family specific header or - * // attributes, genl_send_simple() may be used to send messages directly. - * genl_send_simple(nl_handle, family, MY_SIMPLE_CMD, VERSION, 0); + * // Prepare socket to receive the answer by specifying the callback + * // function to be called for valid messages. + * nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL); + * + * // Wait for the answer and receive it + * nl_recvmsgs_default(sock); + * + * static int parse_cb(struct nl_msg *msg, void *arg) + * { + * struct nlmsghdr *nlh = nlmsg_hdr(msg); + * struct nlattr *attrs[ATTR_MAX+1]; + * + * // Validate message and parse attributes + * genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy); + * + * if (attrs[ATTR_FOO]) { + * uint32_t value = nla_get_u32(attrs[ATTR_FOO]); + * ... + * } + * + * return 0; + * } * @endcode - * @{ */ #include @@ -125,6 +143,46 @@ int genl_send_simple(struct nl_handle *handle, int family, int cmd, * @{ */ +int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) +{ + struct genlmsghdr *ghdr; + + if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN)) + return 0; + + ghdr = nlmsg_data(nlh); + if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen)) + return 0; + + return 1; +} + +int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, + struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr(nlh, hdrlen)) + return nl_errno(EINVAL); + + ghdr = nlmsg_data(nlh); + return nla_validate(genlmsg_attrdata(ghdr, hdrlen), + genlmsg_attrlen(ghdr, hdrlen), maxtype, policy); +} + +int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr(nlh, hdrlen)) + return nl_errno(EINVAL); + + ghdr = nlmsg_data(nlh); + return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen), + genlmsg_attrlen(ghdr, hdrlen), policy); +} + /** * Get head of message payload * @arg gnlh genetlink messsage header diff --git a/lib/msg.c b/lib/msg.c index 589fcb9..3ae8909 100644 --- a/lib/msg.c +++ b/lib/msg.c @@ -261,6 +261,14 @@ int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) * @{ */ +int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + return 0; + + return 1; +} + /** * check if the netlink message fits into the remaining bytes * @arg nlh netlink message header @@ -303,7 +311,7 @@ struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, struct nla_policy *policy) { - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + if (!nlmsg_valid_hdr(nlh, hdrlen)) return nl_errno(EINVAL); return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), @@ -334,7 +342,7 @@ struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, struct nla_policy *policy) { - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + if (!nlmsg_valid_hdr(nlh, hdrlen)) return nl_errno(EINVAL); return nla_validate(nlmsg_attrdata(nlh, hdrlen), -- cgit v0.12