* configure.ac: Verify existence of linux/genetlink.h. * socketutils.c (genl_families_xlat): exported function for building the xlat table. Include linux/genetlink.h. * defs.h (genl_families_xlat): add the declaration. (genl_send_dump_families, genl_parse_families_response): helper functions.
Changes in v3 (all suggested by ldv): * Check whether linux/genetlink.h is available or not. * Don't add NLM_F_ACK to nlmsg_type when dumping genl families. * Use xstrndup to extract family name from netlink data. xstrndup can limits the length of data copied and puts nul char at the end of buffer. * Free the buffer for storing family name before overwriting it. * Remove id_set local variable. id is now a pointer. So NULL check of id can be used to know whether the value is assigned or not. * Free the buffer for storing family name even if it is not stored to dyxlat. Changes in v4 (all suggested by ldv): * (genl_families_xlat) add const modifier. * (genl_families_xlat) just save the pointer for name instead of doing strdup. Don't update id pointer. Use new dyxlat interface. Signed-off-by: Masatake YAMATO <yam...@redhat.com> --- configure.ac | 1 + defs.h | 2 ++ socketutils.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/configure.ac b/configure.ac index 9bf89fc..ff9c7c5 100644 --- a/configure.ac +++ b/configure.ac @@ -367,6 +367,7 @@ AC_CHECK_HEADERS(m4_normalize([ linux/falloc.h linux/fiemap.h linux/filter.h + linux/genetlink.h linux/hiddev.h linux/ip_vs.h linux/ipc.h diff --git a/defs.h b/defs.h index f7b5709..29a681b 100644 --- a/defs.h +++ b/defs.h @@ -514,6 +514,8 @@ void dyxlat_free(struct dyxlat *); const struct xlat *dyxlat_get(const struct dyxlat *); void dyxlat_add_pair(struct dyxlat *, uint64_t val, const char *str, size_t len); +const struct xlat *genl_families_xlat(void); + extern unsigned long get_pagesize(void); extern int string_to_uint_ex(const char *str, char **endptr, diff --git a/socketutils.c b/socketutils.c index b93c98f..18b5e94 100644 --- a/socketutils.c +++ b/socketutils.c @@ -37,6 +37,9 @@ #include <linux/unix_diag.h> #include <linux/netlink_diag.h> #include <linux/rtnetlink.h> +#if HAVE_LINUX_GENETLINK_H +#include <linux/genetlink.h> +#endif #include <sys/un.h> #ifndef UNIX_PATH_MAX @@ -541,3 +544,108 @@ print_sockaddr_by_inode(struct tcb *const tcp, const int fd, return print_sockaddr_by_inode_cached(inode) ? true : print_sockaddr_by_inode_uncached(inode, getfdproto(tcp, fd)); } + +#ifdef HAVE_LINUX_GENETLINK_H +/* + * Managing the cache for decoding communications of Netlink GENERIC protocol + * + * As name shown Netlink GENERIC protocol is generic protocol. The + * numbers of msg types used in the protocol are not defined + * statically. Kernel defines them on demand. So the xlat converted + * from header files doesn't help for decoding the protocol. Following + * codes are building xlat(dyxlat) at runtime. + */ +static bool +genl_send_dump_families(const int fd) +{ + struct { + const struct nlmsghdr nlh; + struct genlmsghdr gnlh; + } req = { + .nlh = { + .nlmsg_len = sizeof(req), + .nlmsg_type = GENL_ID_CTRL, + .nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST, + }, + .gnlh = { + .cmd = CTRL_CMD_GETFAMILY, + } + }; + return send_query(fd, &req, sizeof(req)); +} + +static int +genl_parse_families_response(const void *const data, + const int data_len, const unsigned long inode, + void *user_data) +{ + struct dyxlat *dyxlat = user_data; + const struct genlmsghdr * const gnlh = data; + struct rtattr *attr; + int rta_len = data_len - NLMSG_LENGTH(sizeof(*gnlh)); + + char *name = NULL; + unsigned int name_len = 0; + uint16_t *id = NULL; + + if (rta_len < 0) + return -1; + if (gnlh->cmd != CTRL_CMD_NEWFAMILY) + return -1; + if (gnlh->version != 2) + return -1; + + for (attr = (struct rtattr *) (gnlh + 1); + RTA_OK(attr, rta_len); + attr = RTA_NEXT(attr, rta_len)) { + switch (attr->rta_type) { + case CTRL_ATTR_FAMILY_NAME: + if (!name) { + name = RTA_DATA(attr); + name_len = RTA_PAYLOAD(attr); + } + break; + case CTRL_ATTR_FAMILY_ID: + if (!id && RTA_PAYLOAD(attr) == sizeof(*id)) + id = (RTA_DATA(attr)); + break; + } + if (name && id) { + dyxlat_add_pair(dyxlat, *id, name, name_len); + name = NULL; + id = NULL; + } + } + + return 0; +} + +const struct xlat * +genl_families_xlat(void) +{ + static struct dyxlat *dyxlat; + + if (!dyxlat) { + int fd; + + dyxlat = dyxlat_alloc(32); + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + if (fd < 0) + goto out; + + if (genl_send_dump_families(fd)) + receive_responses(fd, 0, GENL_ID_CTRL, + genl_parse_families_response, dyxlat); + close(fd); + } + +out: + return dyxlat_get(dyxlat); +} +#else +const struct xlat * +genl_families_xlat(void) +{ + return NULL; +} +#endif -- 2.9.4 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel