* 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. Signed-off-by: Masatake YAMATO <yam...@redhat.com> --- configure.ac | 1 + defs.h | 2 ++ socketutils.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/configure.ac b/configure.ac index dc49d39..0974743 100644 --- a/configure.ac +++ b/configure.ac @@ -366,6 +366,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 063394e..f50b474 100644 --- a/defs.h +++ b/defs.h @@ -511,6 +511,8 @@ void dyxlat_free(struct dyxlat *dyxlat); struct xlat *dyxlat_get(struct dyxlat *dyxlat); void dyxlat_add_pair(struct dyxlat *dyxlat, uint64_t val, const char *str); +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 6486e27..bc18430 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,110 @@ 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; + 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) + free(name); + name = xstrndup(RTA_DATA(attr), RTA_PAYLOAD(attr)); + break; + case CTRL_ATTR_FAMILY_ID: + if (RTA_PAYLOAD(attr) >= 2) + id = (RTA_DATA(attr)); + break; + } + if (name && id) { + dyxlat_add_pair(dyxlat, *id, name); + free(name); + name = NULL; + id = NULL; + } + } + + if (name) + free(name); + + return 0; +} + +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 +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