diff options
Diffstat (limited to 'src/platform/nm-netlink.c')
| -rw-r--r-- | src/platform/nm-netlink.c | 2117 |
1 files changed, 1080 insertions, 1037 deletions
diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index d133d351..965a73bc 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -13,256 +13,306 @@ /*****************************************************************************/ #ifndef SOL_NETLINK -#define SOL_NETLINK 270 + #define SOL_NETLINK 270 #endif /*****************************************************************************/ -#define NL_SOCK_PASSCRED (1<<1) -#define NL_MSG_PEEK (1<<3) -#define NL_MSG_PEEK_EXPLICIT (1<<4) -#define NL_NO_AUTO_ACK (1<<5) +#define NL_SOCK_PASSCRED (1 << 1) +#define NL_MSG_PEEK (1 << 3) +#define NL_MSG_PEEK_EXPLICIT (1 << 4) +#define NL_NO_AUTO_ACK (1 << 5) #ifndef NETLINK_EXT_ACK -#define NETLINK_EXT_ACK 11 + #define NETLINK_EXT_ACK 11 #endif struct nl_msg { - int nm_protocol; - struct sockaddr_nl nm_src; - struct sockaddr_nl nm_dst; - struct ucred nm_creds; - struct nlmsghdr * nm_nlh; - size_t nm_size; - bool nm_creds_has:1; + int nm_protocol; + struct sockaddr_nl nm_src; + struct sockaddr_nl nm_dst; + struct ucred nm_creds; + struct nlmsghdr * nm_nlh; + size_t nm_size; + bool nm_creds_has : 1; }; struct nl_sock { - struct sockaddr_nl s_local; - struct sockaddr_nl s_peer; - int s_fd; - int s_proto; - unsigned int s_seq_next; - unsigned int s_seq_expect; - int s_flags; - size_t s_bufsize; + struct sockaddr_nl s_local; + struct sockaddr_nl s_peer; + int s_fd; + int s_proto; + unsigned int s_seq_next; + unsigned int s_seq_expect; + int s_flags; + size_t s_bufsize; }; /*****************************************************************************/ -NM_UTILS_ENUM2STR_DEFINE (nl_nlmsgtype2str, int, - NM_UTILS_ENUM2STR (NLMSG_NOOP, "NOOP"), - NM_UTILS_ENUM2STR (NLMSG_ERROR, "ERROR"), - NM_UTILS_ENUM2STR (NLMSG_DONE, "DONE"), - NM_UTILS_ENUM2STR (NLMSG_OVERRUN, "OVERRUN"), -); - -NM_UTILS_FLAGS2STR_DEFINE (nl_nlmsg_flags2str, int, - NM_UTILS_FLAGS2STR (NLM_F_REQUEST, "REQUEST"), - NM_UTILS_FLAGS2STR (NLM_F_MULTI, "MULTI"), - NM_UTILS_FLAGS2STR (NLM_F_ACK, "ACK"), - NM_UTILS_FLAGS2STR (NLM_F_ECHO, "ECHO"), - NM_UTILS_FLAGS2STR (NLM_F_ROOT, "ROOT"), - NM_UTILS_FLAGS2STR (NLM_F_MATCH, "MATCH"), - NM_UTILS_FLAGS2STR (NLM_F_ATOMIC, "ATOMIC"), - NM_UTILS_FLAGS2STR (NLM_F_REPLACE, "REPLACE"), - NM_UTILS_FLAGS2STR (NLM_F_EXCL, "EXCL"), - NM_UTILS_FLAGS2STR (NLM_F_CREATE, "CREATE"), - NM_UTILS_FLAGS2STR (NLM_F_APPEND, "APPEND"), -); +NM_UTILS_ENUM2STR_DEFINE(nl_nlmsgtype2str, + int, + NM_UTILS_ENUM2STR(NLMSG_NOOP, "NOOP"), + NM_UTILS_ENUM2STR(NLMSG_ERROR, "ERROR"), + NM_UTILS_ENUM2STR(NLMSG_DONE, "DONE"), + NM_UTILS_ENUM2STR(NLMSG_OVERRUN, "OVERRUN"), ); + +NM_UTILS_FLAGS2STR_DEFINE(nl_nlmsg_flags2str, + int, + NM_UTILS_FLAGS2STR(NLM_F_REQUEST, "REQUEST"), + NM_UTILS_FLAGS2STR(NLM_F_MULTI, "MULTI"), + NM_UTILS_FLAGS2STR(NLM_F_ACK, "ACK"), + NM_UTILS_FLAGS2STR(NLM_F_ECHO, "ECHO"), + NM_UTILS_FLAGS2STR(NLM_F_ROOT, "ROOT"), + NM_UTILS_FLAGS2STR(NLM_F_MATCH, "MATCH"), + NM_UTILS_FLAGS2STR(NLM_F_ATOMIC, "ATOMIC"), + NM_UTILS_FLAGS2STR(NLM_F_REPLACE, "REPLACE"), + NM_UTILS_FLAGS2STR(NLM_F_EXCL, "EXCL"), + NM_UTILS_FLAGS2STR(NLM_F_CREATE, "CREATE"), + NM_UTILS_FLAGS2STR(NLM_F_APPEND, "APPEND"), ); /*****************************************************************************/ const char * -nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) +nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) { - const char *b; - const char *s; - guint flags, flags_before; - const char *prefix; - - if (!nm_utils_to_string_buffer_init_null (hdr, &buf, &len)) - return buf; - - b = buf; - - switch (hdr->nlmsg_type) { - case RTM_GETLINK: s = "RTM_GETLINK"; break; - case RTM_NEWLINK: s = "RTM_NEWLINK"; break; - case RTM_DELLINK: s = "RTM_DELLINK"; break; - case RTM_SETLINK: s = "RTM_SETLINK"; break; - case RTM_GETADDR: s = "RTM_GETADDR"; break; - case RTM_NEWADDR: s = "RTM_NEWADDR"; break; - case RTM_DELADDR: s = "RTM_DELADDR"; break; - case RTM_GETROUTE: s = "RTM_GETROUTE"; break; - case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; - case RTM_DELROUTE: s = "RTM_DELROUTE"; break; - case RTM_GETRULE: s = "RTM_GETRULE"; break; - case RTM_NEWRULE: s = "RTM_NEWRULE"; break; - case RTM_DELRULE: s = "RTM_DELRULE"; break; - case RTM_GETQDISC: s = "RTM_GETQDISC"; break; - case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; - case RTM_DELQDISC: s = "RTM_DELQDISC"; break; - case RTM_GETTFILTER: s = "RTM_GETTFILTER"; break; - case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; - case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; - case NLMSG_NOOP: s = "NLMSG_NOOP"; break; - case NLMSG_ERROR: s = "NLMSG_ERROR"; break; - case NLMSG_DONE: s = "NLMSG_DONE"; break; - case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; - default: s = NULL; break; - } - - if (s) - nm_utils_strbuf_append_str (&buf, &len, s); - else - nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); - - flags = hdr->nlmsg_flags; - - if (!flags) { - nm_utils_strbuf_append_str (&buf, &len, ", flags 0"); - goto flags_done; - } - -#define _F(f, n) \ - G_STMT_START { \ - if (NM_FLAGS_ALL (flags, f)) { \ - flags &= ~(f); \ - nm_utils_strbuf_append (&buf, &len, "%s%s", prefix, n); \ - if (!flags) \ - goto flags_done; \ - prefix = ","; \ - } \ - } G_STMT_END - - prefix = ", flags "; - flags_before = flags; - _F (NLM_F_REQUEST, "request"); - _F (NLM_F_MULTI, "multi"); - _F (NLM_F_ACK, "ack"); - _F (NLM_F_ECHO, "echo"); - _F (NLM_F_DUMP_INTR, "dump_intr"); - _F (0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered"); - - if (flags_before != flags) - prefix = ";"; - - switch (hdr->nlmsg_type) { - case RTM_NEWLINK: - case RTM_NEWADDR: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: - _F (NLM_F_REPLACE, "replace"); - _F (NLM_F_EXCL, "excl"); - _F (NLM_F_CREATE, "create"); - _F (NLM_F_APPEND, "append"); - break; - case RTM_GETLINK: - case RTM_GETADDR: - case RTM_GETROUTE: - case RTM_DELQDISC: - case RTM_DELTFILTER: - _F (NLM_F_DUMP, "dump"); - _F (NLM_F_ROOT, "root"); - _F (NLM_F_MATCH, "match"); - _F (NLM_F_ATOMIC, "atomic"); - break; - } + const char *b; + const char *s; + guint flags, flags_before; + const char *prefix; + + if (!nm_utils_to_string_buffer_init_null(hdr, &buf, &len)) + return buf; + + b = buf; + + switch (hdr->nlmsg_type) { + case RTM_GETLINK: + s = "RTM_GETLINK"; + break; + case RTM_NEWLINK: + s = "RTM_NEWLINK"; + break; + case RTM_DELLINK: + s = "RTM_DELLINK"; + break; + case RTM_SETLINK: + s = "RTM_SETLINK"; + break; + case RTM_GETADDR: + s = "RTM_GETADDR"; + break; + case RTM_NEWADDR: + s = "RTM_NEWADDR"; + break; + case RTM_DELADDR: + s = "RTM_DELADDR"; + break; + case RTM_GETROUTE: + s = "RTM_GETROUTE"; + break; + case RTM_NEWROUTE: + s = "RTM_NEWROUTE"; + break; + case RTM_DELROUTE: + s = "RTM_DELROUTE"; + break; + case RTM_GETRULE: + s = "RTM_GETRULE"; + break; + case RTM_NEWRULE: + s = "RTM_NEWRULE"; + break; + case RTM_DELRULE: + s = "RTM_DELRULE"; + break; + case RTM_GETQDISC: + s = "RTM_GETQDISC"; + break; + case RTM_NEWQDISC: + s = "RTM_NEWQDISC"; + break; + case RTM_DELQDISC: + s = "RTM_DELQDISC"; + break; + case RTM_GETTFILTER: + s = "RTM_GETTFILTER"; + break; + case RTM_NEWTFILTER: + s = "RTM_NEWTFILTER"; + break; + case RTM_DELTFILTER: + s = "RTM_DELTFILTER"; + break; + case NLMSG_NOOP: + s = "NLMSG_NOOP"; + break; + case NLMSG_ERROR: + s = "NLMSG_ERROR"; + break; + case NLMSG_DONE: + s = "NLMSG_DONE"; + break; + case NLMSG_OVERRUN: + s = "NLMSG_OVERRUN"; + break; + default: + s = NULL; + break; + } + + if (s) + nm_utils_strbuf_append_str(&buf, &len, s); + else + nm_utils_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); + + flags = hdr->nlmsg_flags; + + if (!flags) { + nm_utils_strbuf_append_str(&buf, &len, ", flags 0"); + goto flags_done; + } + +#define _F(f, n) \ + G_STMT_START \ + { \ + if (NM_FLAGS_ALL(flags, f)) { \ + flags &= ~(f); \ + nm_utils_strbuf_append(&buf, &len, "%s%s", prefix, n); \ + if (!flags) \ + goto flags_done; \ + prefix = ","; \ + } \ + } \ + G_STMT_END + + prefix = ", flags "; + flags_before = flags; + _F(NLM_F_REQUEST, "request"); + _F(NLM_F_MULTI, "multi"); + _F(NLM_F_ACK, "ack"); + _F(NLM_F_ECHO, "echo"); + _F(NLM_F_DUMP_INTR, "dump_intr"); + _F(0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered"); + + if (flags_before != flags) + prefix = ";"; + + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: + _F(NLM_F_REPLACE, "replace"); + _F(NLM_F_EXCL, "excl"); + _F(NLM_F_CREATE, "create"); + _F(NLM_F_APPEND, "append"); + break; + case RTM_GETLINK: + case RTM_GETADDR: + case RTM_GETROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: + _F(NLM_F_DUMP, "dump"); + _F(NLM_F_ROOT, "root"); + _F(NLM_F_MATCH, "match"); + _F(NLM_F_ATOMIC, "atomic"); + break; + } #undef _F - if (flags_before != flags) - prefix = ";"; - nm_utils_strbuf_append (&buf, &len, "%s0x%04x", prefix, flags); + if (flags_before != flags) + prefix = ";"; + nm_utils_strbuf_append(&buf, &len, "%s0x%04x", prefix, flags); flags_done: - nm_utils_strbuf_append (&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); + nm_utils_strbuf_append(&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); - return b; + return b; } /*****************************************************************************/ struct nlmsghdr * -nlmsg_hdr (struct nl_msg *n) +nlmsg_hdr(struct nl_msg *n) { - return n->nm_nlh; + return n->nm_nlh; } void * -nlmsg_reserve (struct nl_msg *n, size_t len, int pad) +nlmsg_reserve(struct nl_msg *n, size_t len, int pad) { - char *buf = (char *) n->nm_nlh; - size_t nlmsg_len = n->nm_nlh->nlmsg_len; - size_t tlen; + char * buf = (char *) n->nm_nlh; + size_t nlmsg_len = n->nm_nlh->nlmsg_len; + size_t tlen; - nm_assert (pad >= 0); + nm_assert(pad >= 0); - if (len > n->nm_size) - return NULL; + if (len > n->nm_size) + return NULL; - tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; + tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; - if ((tlen + nlmsg_len) > n->nm_size) - return NULL; + if ((tlen + nlmsg_len) > n->nm_size) + return NULL; - buf += nlmsg_len; - n->nm_nlh->nlmsg_len += tlen; + buf += nlmsg_len; + n->nm_nlh->nlmsg_len += tlen; - if (tlen > len) - memset (buf + len, 0, tlen - len); + if (tlen > len) + memset(buf + len, 0, tlen - len); - return buf; + return buf; } /*****************************************************************************/ struct nlattr * -nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) +nla_reserve(struct nl_msg *msg, int attrtype, int attrlen) { - struct nlattr *nla; - int tlen; + struct nlattr *nla; + int tlen; - if (attrlen < 0) - return NULL; + if (attrlen < 0) + return NULL; - tlen = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) + nla_total_size (attrlen); + tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen); - if (tlen > msg->nm_size) - return NULL; + if (tlen > msg->nm_size) + return NULL; - nla = (struct nlattr *) nlmsg_tail (msg->nm_nlh); - nla->nla_type = attrtype; - nla->nla_len = nla_attr_size (attrlen); + nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh); + nla->nla_type = attrtype; + nla->nla_len = nla_attr_size(attrlen); - if (attrlen) - memset ((unsigned char *) nla + nla->nla_len, 0, nla_padlen (attrlen)); - msg->nm_nlh->nlmsg_len = tlen; + if (attrlen) + memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); + msg->nm_nlh->nlmsg_len = tlen; - return nla; + return nla; } /*****************************************************************************/ struct nl_msg * -nlmsg_alloc_size (size_t len) +nlmsg_alloc_size(size_t len) { - struct nl_msg *nm; - - if (len < sizeof (struct nlmsghdr)) - len = sizeof (struct nlmsghdr); - - nm = g_slice_new (struct nl_msg); - *nm = (struct nl_msg) { - .nm_protocol = -1, - .nm_size = len, - .nm_nlh = g_malloc0 (len), - }; - nm->nm_nlh->nlmsg_len = nlmsg_total_size (0); - return nm; + struct nl_msg *nm; + + if (len < sizeof(struct nlmsghdr)) + len = sizeof(struct nlmsghdr); + + nm = g_slice_new(struct nl_msg); + *nm = (struct nl_msg){ + .nm_protocol = -1, + .nm_size = len, + .nm_nlh = g_malloc0(len), + }; + nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); + return nm; } /** @@ -275,1201 +325,1194 @@ nlmsg_alloc_size (size_t len) * @return Newly allocated netlink message or NULL. */ struct nl_msg * -nlmsg_alloc (void) +nlmsg_alloc(void) { - return nlmsg_alloc_size (nm_utils_getpagesize ()); + return nlmsg_alloc_size(nm_utils_getpagesize()); } struct nl_msg * -nlmsg_alloc_convert (struct nlmsghdr *hdr) +nlmsg_alloc_convert(struct nlmsghdr *hdr) { - struct nl_msg *nm; + struct nl_msg *nm; - nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len)); - memcpy (nm->nm_nlh, hdr, hdr->nlmsg_len); - return nm; + nm = nlmsg_alloc_size(NLMSG_ALIGN(hdr->nlmsg_len)); + memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); + return nm; } struct nl_msg * -nlmsg_alloc_simple (int nlmsgtype, int flags) +nlmsg_alloc_simple(int nlmsgtype, int flags) { - struct nl_msg *nm; - struct nlmsghdr *new; - - nm = nlmsg_alloc (); - new = nm->nm_nlh; - new->nlmsg_type = nlmsgtype; - new->nlmsg_flags = flags; - return nm; + struct nl_msg *nm; + struct nlmsghdr *new; + + nm = nlmsg_alloc(); + new = nm->nm_nlh; + new->nlmsg_type = nlmsgtype; + new->nlmsg_flags = flags; + return nm; } -void nlmsg_free (struct nl_msg *msg) +void +nlmsg_free(struct nl_msg *msg) { - if (!msg) - return; + if (!msg) + return; - g_free (msg->nm_nlh); - g_slice_free (struct nl_msg, msg); + g_free(msg->nm_nlh); + g_slice_free(struct nl_msg, msg); } /*****************************************************************************/ int -nlmsg_append (struct nl_msg *n, - const void *data, - size_t len, - int pad) +nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad) { - void *tmp; + void *tmp; - nm_assert (n); - nm_assert (data); - nm_assert (len > 0); - nm_assert (pad >= 0); + nm_assert(n); + nm_assert(data); + nm_assert(len > 0); + nm_assert(pad >= 0); - tmp = nlmsg_reserve (n, len, pad); - if (tmp == NULL) - return -ENOMEM; + tmp = nlmsg_reserve(n, len, pad); + if (tmp == NULL) + return -ENOMEM; - memcpy (tmp, data, len); - return 0; + memcpy(tmp, data, len); + return 0; } /*****************************************************************************/ int -nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy) +nlmsg_parse(struct nlmsghdr * nlh, + int hdrlen, + struct nlattr * tb[], + int maxtype, + const struct nla_policy *policy) { - if (!nlmsg_valid_hdr (nlh, hdrlen)) - return -NME_NL_MSG_TOOSHORT; + if (!nlmsg_valid_hdr(nlh, hdrlen)) + return -NME_NL_MSG_TOOSHORT; - return nla_parse (tb, maxtype, nlmsg_attrdata (nlh, hdrlen), - nlmsg_attrlen (nlh, hdrlen), policy); + return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), policy); } struct nlmsghdr * -nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, - int type, int payload, int flags) +nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags) { - struct nlmsghdr *nlh; + struct nlmsghdr *nlh; - if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) - g_return_val_if_reached (NULL); + if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) + g_return_val_if_reached(NULL); - nlh = (struct nlmsghdr *) n->nm_nlh; - nlh->nlmsg_type = type; - nlh->nlmsg_flags = flags; - nlh->nlmsg_pid = pid; - nlh->nlmsg_seq = seq; + nlh = (struct nlmsghdr *) n->nm_nlh; + nlh->nlmsg_type = type; + nlh->nlmsg_flags = flags; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = seq; - if ( payload > 0 - && nlmsg_reserve (n, payload, NLMSG_ALIGNTO) == NULL) - return NULL; + if (payload > 0 && nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) + return NULL; - return nlh; + return nlh; } size_t -nla_strlcpy (char *dst, - const struct nlattr *nla, - size_t dstsize) +nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) { - const char *src; - size_t srclen; - size_t len; - - /* - Always writes @dstsize bytes to @dst - * - Copies the first non-NUL characters to @dst. - * Any characters after the first NUL bytes in @nla are ignored. - * - If the string @nla is longer than @dstsize, the string - * gets truncated. @dst will always be NUL terminated. */ - - if (G_UNLIKELY (dstsize <= 1)) { - if (dstsize == 1) - dst[0] = '\0'; - if ( nla - && (srclen = nla_len (nla)) > 0) - return strnlen (nla_data (nla), srclen); - return 0; - } - - nm_assert (dst); - - if (nla) { - srclen = nla_len (nla); - if (srclen > 0) { - src = nla_data (nla); - srclen = strnlen (src, srclen); - if (srclen > 0) { - len = NM_MIN (dstsize - 1, srclen); - memcpy (dst, src, len); - memset (&dst[len], 0, dstsize - len); - return srclen; - } - } - } - - memset (dst, 0, dstsize); - return 0; + const char *src; + size_t srclen; + size_t len; + + /* - Always writes @dstsize bytes to @dst + * - Copies the first non-NUL characters to @dst. + * Any characters after the first NUL bytes in @nla are ignored. + * - If the string @nla is longer than @dstsize, the string + * gets truncated. @dst will always be NUL terminated. */ + + if (G_UNLIKELY(dstsize <= 1)) { + if (dstsize == 1) + dst[0] = '\0'; + if (nla && (srclen = nla_len(nla)) > 0) + return strnlen(nla_data(nla), srclen); + return 0; + } + + nm_assert(dst); + + if (nla) { + srclen = nla_len(nla); + if (srclen > 0) { + src = nla_data(nla); + srclen = strnlen(src, srclen); + if (srclen > 0) { + len = NM_MIN(dstsize - 1, srclen); + memcpy(dst, src, len); + memset(&dst[len], 0, dstsize - len); + return srclen; + } + } + } + + memset(dst, 0, dstsize); + return 0; } size_t -nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize) +nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize) { - size_t len; - int srclen; - - if (!nla) - return 0; - - srclen = nla_len (nla); - - if (srclen <= 0) { - nm_assert (srclen == 0); - return 0; - } - - len = NM_MIN ((size_t) srclen, dstsize); - if (len > 0) { - /* there is a crucial difference between nla_strlcpy() and nla_memcpy(). - * The former always write @dstsize bytes (akin to strncpy()), here, we only - * write the bytes that we actually have (leaving the remainder undefined). */ - memcpy (dst, - nla_data (nla), - len); - } - - return srclen; + size_t len; + int srclen; + + if (!nla) + return 0; + + srclen = nla_len(nla); + + if (srclen <= 0) { + nm_assert(srclen == 0); + return 0; + } + + len = NM_MIN((size_t) srclen, dstsize); + if (len > 0) { + /* there is a crucial difference between nla_strlcpy() and nla_memcpy(). + * The former always write @dstsize bytes (akin to strncpy()), here, we only + * write the bytes that we actually have (leaving the remainder undefined). */ + memcpy(dst, nla_data(nla), len); + } + + return srclen; } int -nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) +nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data) { - struct nlattr *nla; + struct nlattr *nla; - nla = nla_reserve (msg, attrtype, datalen); - if (!nla) { - if (datalen < 0) - g_return_val_if_reached (-NME_BUG); + nla = nla_reserve(msg, attrtype, datalen); + if (!nla) { + if (datalen < 0) + g_return_val_if_reached(-NME_BUG); - return -ENOMEM; - } + return -ENOMEM; + } - if (datalen > 0) - memcpy (nla_data (nla), data, datalen); + if (datalen > 0) + memcpy(nla_data(nla), data, datalen); - return 0; + return 0; } struct nlattr * -nla_find (const struct nlattr *head, int len, int attrtype) +nla_find(const struct nlattr *head, int len, int attrtype) { - const struct nlattr *nla; - int rem; + const struct nlattr *nla; + int rem; - nla_for_each_attr (nla, head, len, rem) { - if (nla_type (nla) == attrtype) - return (struct nlattr*)nla; - } + nla_for_each_attr (nla, head, len, rem) { + if (nla_type(nla) == attrtype) + return (struct nlattr *) nla; + } - return NULL; + return NULL; } void -nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr) +nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr) { - ssize_t len; - - len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) attr; - if (len < 0) - g_return_if_reached (); - else if (len > 0) { - msg->nm_nlh->nlmsg_len -= len; - memset (nlmsg_tail (msg->nm_nlh), 0, len); - } + ssize_t len; + + len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr; + if (len < 0) + g_return_if_reached(); + else if (len > 0) { + msg->nm_nlh->nlmsg_len -= len; + memset(nlmsg_tail(msg->nm_nlh), 0, len); + } } struct nlattr * -nla_nest_start (struct nl_msg *msg, int attrtype) +nla_nest_start(struct nl_msg *msg, int attrtype) { - struct nlattr *start = (struct nlattr *) nlmsg_tail (msg->nm_nlh); + struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh); - if (nla_put (msg, NLA_F_NESTED | attrtype, 0, NULL) < 0) - return NULL; + if (nla_put(msg, NLA_F_NESTED | attrtype, 0, NULL) < 0) + return NULL; - return start; + return start; } static int -_nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) +_nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty) { - size_t pad, len; - - len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) start; - - if ( len > USHRT_MAX - || (!keep_empty && len == NLA_HDRLEN)) { - /* - * Max nlattr size exceeded or empty nested attribute, trim the - * attribute header again - */ - nla_nest_cancel (msg, start); - - /* Return error only if nlattr size was exceeded */ - return (len == NLA_HDRLEN) ? 0 : -NME_NL_ATTRSIZE; - } - - start->nla_len = len; - - pad = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; - if (pad > 0) { - /* - * Data inside attribute does not end at a alignment boundary. - * Pad accordingly and accoun for the additional space in - * the message. nlmsg_reserve() may never fail in this situation, - * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. - */ - if (!nlmsg_reserve (msg, pad, 0)) - g_return_val_if_reached (-NME_BUG); - } - - return 0; + size_t pad, len; + + len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start; + + if (len > USHRT_MAX || (!keep_empty && len == NLA_HDRLEN)) { + /* + * Max nlattr size exceeded or empty nested attribute, trim the + * attribute header again + */ + nla_nest_cancel(msg, start); + + /* Return error only if nlattr size was exceeded */ + return (len == NLA_HDRLEN) ? 0 : -NME_NL_ATTRSIZE; + } + + start->nla_len = len; + + pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; + if (pad > 0) { + /* + * Data inside attribute does not end at a alignment boundary. + * Pad accordingly and account for the additional space in + * the message. nlmsg_reserve() may never fail in this situation, + * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. + */ + if (!nlmsg_reserve(msg, pad, 0)) + g_return_val_if_reached(-NME_BUG); + } + + return 0; } int -nla_nest_end (struct nl_msg *msg, struct nlattr *start) +nla_nest_end(struct nl_msg *msg, struct nlattr *start) { - return _nest_end (msg, start, 0); + return _nest_end(msg, start, 0); } -static const uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof (uint8_t), - [NLA_U16] = sizeof (uint16_t), - [NLA_U32] = sizeof (uint32_t), - [NLA_U64] = sizeof (uint64_t), - [NLA_STRING] = 1, - [NLA_FLAG] = 0, +static const uint16_t nla_attr_minlen[NLA_TYPE_MAX + 1] = { + [NLA_U8] = sizeof(uint8_t), + [NLA_U16] = sizeof(uint16_t), + [NLA_U32] = sizeof(uint32_t), + [NLA_U64] = sizeof(uint64_t), + [NLA_STRING] = 1, + [NLA_FLAG] = 0, }; static int -validate_nla (const struct nlattr *nla, int maxtype, - const struct nla_policy *policy) +validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy) { - const struct nla_policy *pt; - unsigned int minlen = 0; - int type = nla_type (nla); + const struct nla_policy *pt; + unsigned int minlen = 0; + int type = nla_type(nla); - if (type < 0 || type > maxtype) - return 0; + if (type < 0 || type > maxtype) + return 0; - pt = &policy[type]; + pt = &policy[type]; - if (pt->type > NLA_TYPE_MAX) - g_return_val_if_reached (-NME_BUG); + if (pt->type > NLA_TYPE_MAX) + g_return_val_if_reached(-NME_BUG); - if (pt->minlen) - minlen = pt->minlen; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; + if (pt->minlen) + minlen = pt->minlen; + else if (pt->type != NLA_UNSPEC) + minlen = nla_attr_minlen[pt->type]; - if (nla_len (nla) < minlen) - return -NME_UNSPEC; + if (nla_len(nla) < minlen) + return -NME_UNSPEC; - if (pt->maxlen && nla_len (nla) > pt->maxlen) - return -NME_UNSPEC; + if (pt->maxlen && nla_len(nla) > pt->maxlen) + return -NME_UNSPEC; - if (pt->type == NLA_STRING) { - const char *data; + if (pt->type == NLA_STRING) { + const char *data; - nm_assert (minlen > 0); + nm_assert(minlen > 0); - data = nla_data (nla); - if (data[nla_len (nla) - 1] != '\0') - return -NME_UNSPEC; - } + data = nla_data(nla); + if (data[nla_len(nla) - 1] != '\0') + return -NME_UNSPEC; + } - return 0; + return 0; } int -nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - const struct nla_policy *policy) +nla_parse(struct nlattr * tb[], + int maxtype, + struct nlattr * head, + int len, + const struct nla_policy *policy) { - struct nlattr *nla; - int rem, nmerr; + struct nlattr *nla; + int rem, nmerr; - memset (tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); + memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - nla_for_each_attr (nla, head, len, rem) { - int type = nla_type (nla); + nla_for_each_attr (nla, head, len, rem) { + int type = nla_type(nla); - if (type > maxtype) - continue; + if (type > maxtype) + continue; - if (policy) { - nmerr = validate_nla (nla, maxtype, policy); - if (nmerr < 0) - return nmerr; - } + if (policy) { + nmerr = validate_nla(nla, maxtype, policy); + if (nmerr < 0) + return nmerr; + } - tb[type] = nla; - } + tb[type] = nla; + } - return 0; + return 0; } /*****************************************************************************/ int -nlmsg_get_proto (struct nl_msg *msg) +nlmsg_get_proto(struct nl_msg *msg) { - return msg->nm_protocol; + return msg->nm_protocol; } void -nlmsg_set_proto (struct nl_msg *msg, int protocol) +nlmsg_set_proto(struct nl_msg *msg, int protocol) { - msg->nm_protocol = protocol; + msg->nm_protocol = protocol; } void -nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr) +nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) { - memcpy (&msg->nm_src, addr, sizeof (*addr)); + memcpy(&msg->nm_src, addr, sizeof(*addr)); } struct ucred * -nlmsg_get_creds (struct nl_msg *msg) +nlmsg_get_creds(struct nl_msg *msg) { - if (msg->nm_creds_has) - return &msg->nm_creds; - return NULL; + if (msg->nm_creds_has) + return &msg->nm_creds; + return NULL; } void -nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds) +nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) { - if (creds) { - memcpy (&msg->nm_creds, creds, sizeof (*creds)); - msg->nm_creds_has = TRUE; - } else - msg->nm_creds_has = FALSE; + if (creds) { + memcpy(&msg->nm_creds, creds, sizeof(*creds)); + msg->nm_creds_has = TRUE; + } else + msg->nm_creds_has = FALSE; } /*****************************************************************************/ void * -genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, - int hdrlen, int flags, uint8_t cmd, uint8_t version) +genlmsg_put(struct nl_msg *msg, + uint32_t port, + uint32_t seq, + int family, + int hdrlen, + int flags, + uint8_t cmd, + uint8_t version) { - struct nlmsghdr *nlh; - struct genlmsghdr hdr = { - .cmd = cmd, - .version = version, - }; + struct nlmsghdr * nlh; + struct genlmsghdr hdr = { + .cmd = cmd, + .version = version, + }; - nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); - if (nlh == NULL) - return NULL; + nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); + if (nlh == NULL) + return NULL; - memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr)); + memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr)); - return (char *) nlmsg_data (nlh) + GENL_HDRLEN; + return (char *) nlmsg_data(nlh) + GENL_HDRLEN; } void * -genlmsg_data (const struct genlmsghdr *gnlh) +genlmsg_data(const struct genlmsghdr *gnlh) { - return ((unsigned char *) gnlh + GENL_HDRLEN); + return ((unsigned char *) gnlh + GENL_HDRLEN); } void * -genlmsg_user_hdr (const struct genlmsghdr *gnlh) +genlmsg_user_hdr(const struct genlmsghdr *gnlh) { - return genlmsg_data (gnlh); + return genlmsg_data(gnlh); } struct genlmsghdr * -genlmsg_hdr (struct nlmsghdr *nlh) +genlmsg_hdr(struct nlmsghdr *nlh) { - return nlmsg_data (nlh); + return nlmsg_data(nlh); } void * -genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen) +genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen) { - return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen); + return (char *) genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen); } struct nlattr * -genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen) +genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen) { - return genlmsg_user_data (gnlh, hdrlen); + return genlmsg_user_data(gnlh, hdrlen); } int -genlmsg_len (const struct genlmsghdr *gnlh) +genlmsg_len(const struct genlmsghdr *gnlh) { - const struct nlmsghdr *nlh; + const struct nlmsghdr *nlh; - nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); - return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); + nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); + return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); } int -genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen) +genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) { - return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen); + return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen); } int -genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen) +genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) { - struct genlmsghdr *ghdr; + struct genlmsghdr *ghdr; - if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN)) - return 0; + if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN)) + return 0; - ghdr = nlmsg_data (nlh); - if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen)) - return 0; + ghdr = nlmsg_data(nlh); + if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen)) + return 0; - return 1; + return 1; } int -genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy) +genlmsg_parse(struct nlmsghdr * nlh, + int hdrlen, + struct nlattr * tb[], + int maxtype, + const struct nla_policy *policy) { - struct genlmsghdr *ghdr; + struct genlmsghdr *ghdr; - if (!genlmsg_valid_hdr (nlh, hdrlen)) - return -NME_NL_MSG_TOOSHORT; + if (!genlmsg_valid_hdr(nlh, hdrlen)) + return -NME_NL_MSG_TOOSHORT; - ghdr = nlmsg_data (nlh); - return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), - genlmsg_attrlen (ghdr, hdrlen), policy); + ghdr = nlmsg_data(nlh); + return nla_parse(tb, + maxtype, + genlmsg_attrdata(ghdr, hdrlen), + genlmsg_attrlen(ghdr, hdrlen), + policy); } static int -_genl_parse_getfamily (struct nl_msg *msg, void *arg) +_genl_parse_getfamily(struct nl_msg *msg, void *arg) { - static const struct nla_policy ctrl_policy[] = { - [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, - [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, - .maxlen = GENL_NAMSIZ }, - [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, - [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, - [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, - [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, - [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, - }; - struct nlattr *tb[G_N_ELEMENTS (ctrl_policy)]; - struct nlmsghdr *nlh = nlmsg_hdr (msg); - gint32 *response_data = arg; - - if (genlmsg_parse_arr (nlh, 0, tb, ctrl_policy) < 0) - return NL_SKIP; - - if (tb[CTRL_ATTR_FAMILY_ID]) - *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]); - - return NL_STOP; + static const struct nla_policy ctrl_policy[] = { + [CTRL_ATTR_FAMILY_ID] = {.type = NLA_U16}, + [CTRL_ATTR_FAMILY_NAME] = {.type = NLA_STRING, .maxlen = GENL_NAMSIZ}, + [CTRL_ATTR_VERSION] = {.type = NLA_U32}, + [CTRL_ATTR_HDRSIZE] = {.type = NLA_U32}, + [CTRL_ATTR_MAXATTR] = {.type = NLA_U32}, + [CTRL_ATTR_OPS] = {.type = NLA_NESTED}, + [CTRL_ATTR_MCAST_GROUPS] = {.type = NLA_NESTED}, + }; + struct nlattr * tb[G_N_ELEMENTS(ctrl_policy)]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + gint32 * response_data = arg; + + if (genlmsg_parse_arr(nlh, 0, tb, ctrl_policy) < 0) + return NL_SKIP; + + if (tb[CTRL_ATTR_FAMILY_ID]) + *response_data = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]); + + return NL_STOP; } int -genl_ctrl_resolve (struct nl_sock *sk, const char *name) +genl_ctrl_resolve(struct nl_sock *sk, const char *name) { - nm_auto_nlmsg struct nl_msg *msg = NULL; - int nmerr; - gint32 response_data = -1; - const struct nl_cb cb = { - .valid_cb = _genl_parse_getfamily, - .valid_arg = &response_data, - }; + nm_auto_nlmsg struct nl_msg *msg = NULL; + int nmerr; + gint32 response_data = -1; + const struct nl_cb cb = { + .valid_cb = _genl_parse_getfamily, + .valid_arg = &response_data, + }; - msg = nlmsg_alloc (); + msg = nlmsg_alloc(); - if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, - 0, 0, CTRL_CMD_GETFAMILY, 1)) - return -ENOMEM; + if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, 1)) + return -ENOMEM; - nmerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name); - if (nmerr < 0) - return nmerr; + nmerr = nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, name); + if (nmerr < 0) + return nmerr; - nmerr = nl_send_auto (sk, msg); - if (nmerr < 0) - return nmerr; + nmerr = nl_send_auto(sk, msg); + if (nmerr < 0) + return nmerr; - nmerr = nl_recvmsgs (sk, &cb); - if (nmerr < 0) - return nmerr; + nmerr = nl_recvmsgs(sk, &cb); + if (nmerr < 0) + return nmerr; - /* If search was successful, request may be ACKed after data */ - nmerr = nl_wait_for_ack (sk, NULL); - if (nmerr < 0) - return nmerr; + /* If search was successful, request may be ACKed after data */ + nmerr = nl_wait_for_ack(sk, NULL); + if (nmerr < 0) + return nmerr; - if (response_data < 0) - return -NME_UNSPEC; + if (response_data < 0) + return -NME_UNSPEC; - return response_data; + return response_data; } /*****************************************************************************/ struct nl_sock * -nl_socket_alloc (void) +nl_socket_alloc(void) { - struct nl_sock *sk; + struct nl_sock *sk; - sk = g_slice_new0 (struct nl_sock); + sk = g_slice_new0(struct nl_sock); - sk->s_fd = -1; - sk->s_local.nl_family = AF_NETLINK; - sk->s_peer.nl_family = AF_NETLINK; - sk->s_seq_expect = sk->s_seq_next = time (NULL); + sk->s_fd = -1; + sk->s_local.nl_family = AF_NETLINK; + sk->s_peer.nl_family = AF_NETLINK; + sk->s_seq_expect = sk->s_seq_next = time(NULL); - return sk; + return sk; } void -nl_socket_free (struct nl_sock *sk) +nl_socket_free(struct nl_sock *sk) { - if (!sk) - return; + if (!sk) + return; - if (sk->s_fd >= 0) - nm_close (sk->s_fd); - g_slice_free (struct nl_sock, sk); + if (sk->s_fd >= 0) + nm_close(sk->s_fd); + g_slice_free(struct nl_sock, sk); } int -nl_socket_get_fd (const struct nl_sock *sk) +nl_socket_get_fd(const struct nl_sock *sk) { - return sk->s_fd; + return sk->s_fd; } uint32_t -nl_socket_get_local_port (const struct nl_sock *sk) +nl_socket_get_local_port(const struct nl_sock *sk) { - return sk->s_local.nl_pid; + return sk->s_local.nl_pid; } size_t -nl_socket_get_msg_buf_size (struct nl_sock *sk) +nl_socket_get_msg_buf_size(struct nl_sock *sk) { - return sk->s_bufsize; + return sk->s_bufsize; } int -nl_socket_set_passcred (struct nl_sock *sk, int state) +nl_socket_set_passcred(struct nl_sock *sk, int state) { - int err; + int err; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + if (sk->s_fd == -1) + return -NME_NL_BAD_SOCK; - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_PASSCRED, - &state, sizeof (state)); - if (err < 0) - return -nm_errno_from_native (errno); + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state)); + if (err < 0) + return -nm_errno_from_native(errno); - if (state) - sk->s_flags |= NL_SOCK_PASSCRED; - else - sk->s_flags &= ~NL_SOCK_PASSCRED; + if (state) + sk->s_flags |= NL_SOCK_PASSCRED; + else + sk->s_flags &= ~NL_SOCK_PASSCRED; - return 0; + return 0; } int -nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize) +nl_socket_set_msg_buf_size(struct nl_sock *sk, size_t bufsize) { - sk->s_bufsize = bufsize; + sk->s_bufsize = bufsize; - return 0; + return 0; } struct sockaddr_nl * -nlmsg_get_dst (struct nl_msg *msg) +nlmsg_get_dst(struct nl_msg *msg) { - return &msg->nm_dst; + return &msg->nm_dst; } int -nl_socket_set_nonblocking (const struct nl_sock *sk) +nl_socket_set_nonblocking(const struct nl_sock *sk) { - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + if (sk->s_fd == -1) + return -NME_NL_BAD_SOCK; - if (fcntl (sk->s_fd, F_SETFL, O_NONBLOCK) < 0) - return -nm_errno_from_native (errno); + if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) + return -nm_errno_from_native(errno); - return 0; + return 0; } int -nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf) +nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { - int err; + int err; - if (rxbuf <= 0) - rxbuf = 32768; + if (rxbuf <= 0) + rxbuf = 32768; - if (txbuf <= 0) - txbuf = 32768; + if (txbuf <= 0) + txbuf = 32768; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + if (sk->s_fd == -1) + return -NME_NL_BAD_SOCK; - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_SNDBUF, - &txbuf, sizeof (txbuf)); - if (err < 0) { - return -nm_errno_from_native (errno); - } + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf)); + if (err < 0) { + return -nm_errno_from_native(errno); + } - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_RCVBUF, - &rxbuf, sizeof (rxbuf)); - if (err < 0) { - return -nm_errno_from_native (errno); - } + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, &rxbuf, sizeof(rxbuf)); + if (err < 0) { + return -nm_errno_from_native(errno); + } - return 0; + return 0; } int -nl_socket_add_memberships (struct nl_sock *sk, int group, ...) +nl_socket_add_memberships(struct nl_sock *sk, int group, ...) { - int err; - va_list ap; + int err; + va_list ap; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + if (sk->s_fd == -1) + return -NME_NL_BAD_SOCK; - va_start (ap, group); + va_start(ap, group); - while (group != 0) { - if (group < 0) { - va_end (ap); - g_return_val_if_reached (-NME_BUG); - } + while (group != 0) { + if (group < 0) { + va_end(ap); + g_return_val_if_reached(-NME_BUG); + } - err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &group, sizeof (group)); - if (err < 0) { - int errsv = errno; + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); + if (err < 0) { + int errsv = errno; - va_end (ap); - return -nm_errno_from_native (errsv); - } + va_end(ap); + return -nm_errno_from_native(errsv); + } - group = va_arg (ap, int); - } + group = va_arg(ap, int); + } - va_end (ap); + va_end(ap); - return 0; + return 0; } int -nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable) +nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable) { - int err, val; + int err, val; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + if (sk->s_fd == -1) + return -NME_NL_BAD_SOCK; - val = !!enable; - err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof (val)); - if (err < 0) - return -nm_errno_from_native (errno); + val = !!enable; + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val)); + if (err < 0) + return -nm_errno_from_native(errno); - return 0; + return 0; } -void nl_socket_disable_msg_peek (struct nl_sock *sk) +void +nl_socket_disable_msg_peek(struct nl_sock *sk) { - sk->s_flags |= NL_MSG_PEEK_EXPLICIT; - sk->s_flags &= ~NL_MSG_PEEK; + sk->s_flags |= NL_MSG_PEEK_EXPLICIT; + sk->s_flags &= ~NL_MSG_PEEK; } int -nl_connect (struct nl_sock *sk, int protocol) +nl_connect(struct nl_sock *sk, int protocol) { - int err, nmerr; - socklen_t addrlen; - struct sockaddr_nl local = { 0 }; - - if (sk->s_fd != -1) - return -NME_NL_BAD_SOCK; - - sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); - if (sk->s_fd < 0) { - nmerr = -nm_errno_from_native (errno); - goto errout; - } - - nmerr = nl_socket_set_buffer_size (sk, 0, 0); - if (nmerr < 0) - goto errout; - - nm_assert (sk->s_local.nl_pid == 0); - - err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local, - sizeof (sk->s_local)); - if (err != 0) { - nmerr = -nm_errno_from_native (errno); - goto errout; - } - - addrlen = sizeof (local); - err = getsockname (sk->s_fd, (struct sockaddr *) &local, - &addrlen); - if (err < 0) { - nmerr = -nm_errno_from_native (errno); - goto errout; - } - - if (addrlen != sizeof (local)) { - nmerr = -NME_UNSPEC; - goto errout; - } - - if (local.nl_family != AF_NETLINK) { - nmerr = -NME_UNSPEC; - goto errout; - } - - sk->s_local = local; - sk->s_proto = protocol; - - return 0; + int err, nmerr; + socklen_t addrlen; + struct sockaddr_nl local = {0}; + + if (sk->s_fd != -1) + return -NME_NL_BAD_SOCK; + + sk->s_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); + if (sk->s_fd < 0) { + nmerr = -nm_errno_from_native(errno); + goto errout; + } + + nmerr = nl_socket_set_buffer_size(sk, 0, 0); + if (nmerr < 0) + goto errout; + + nm_assert(sk->s_local.nl_pid == 0); + + err = bind(sk->s_fd, (struct sockaddr *) &sk->s_local, sizeof(sk->s_local)); + if (err != 0) { + nmerr = -nm_errno_from_native(errno); + goto errout; + } + + addrlen = sizeof(local); + err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen); + if (err < 0) { + nmerr = -nm_errno_from_native(errno); + goto errout; + } + + if (addrlen != sizeof(local)) { + nmerr = -NME_UNSPEC; + goto errout; + } + + if (local.nl_family != AF_NETLINK) { + nmerr = -NME_UNSPEC; + goto errout; + } + + sk->s_local = local; + sk->s_proto = protocol; + + return 0; errout: - if (sk->s_fd != -1) { - close (sk->s_fd); - sk->s_fd = -1; - } - return nmerr; + if (sk->s_fd != -1) { + close(sk->s_fd); + sk->s_fd = -1; + } + return nmerr; } /*****************************************************************************/ static void -_cb_init (struct nl_cb *dst, const struct nl_cb *src) +_cb_init(struct nl_cb *dst, const struct nl_cb *src) { - nm_assert (dst); + nm_assert(dst); - if (src) - *dst = *src; - else - memset (dst, 0, sizeof (*dst)); + if (src) + *dst = *src; + else + memset(dst, 0, sizeof(*dst)); } -static int ack_wait_handler (struct nl_msg *msg, void *arg) +static int +ack_wait_handler(struct nl_msg *msg, void *arg) { - return NL_STOP; + return NL_STOP; } int -nl_wait_for_ack (struct nl_sock *sk, - const struct nl_cb *cb) +nl_wait_for_ack(struct nl_sock *sk, const struct nl_cb *cb) { - struct nl_cb cb2; + struct nl_cb cb2; - _cb_init (&cb2, cb); - cb2.ack_cb = ack_wait_handler; - return nl_recvmsgs (sk, &cb2); + _cb_init(&cb2, cb); + cb2.ack_cb = ack_wait_handler; + return nl_recvmsgs(sk, &cb2); } -#define NL_CB_CALL(cb, type, msg) \ -do { \ - const struct nl_cb *_cb = (cb); \ - \ - if (_cb && _cb->type##_cb) { \ - /* the returned value here must be either a negative - * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \ - nmerr = _cb->type##_cb ((msg), _cb->type##_arg); \ - switch (nmerr) { \ - case NL_OK: \ - nm_assert (nmerr == 0); \ - break; \ - case NL_SKIP: \ - goto skip; \ - case NL_STOP: \ - goto stop; \ - default: \ - if (nmerr >= 0) { \ - nm_assert_not_reached (); \ - nmerr = -NME_BUG; \ - } \ - goto out; \ - } \ - } \ -} while (0) +#define NL_CB_CALL(cb, type, msg) \ + do { \ + const struct nl_cb *_cb = (cb); \ + \ + if (_cb && _cb->type##_cb) { \ + /* the returned value here must be either a negative + * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \ + nmerr = _cb->type##_cb((msg), _cb->type##_arg); \ + switch (nmerr) { \ + case NL_OK: \ + nm_assert(nmerr == 0); \ + break; \ + case NL_SKIP: \ + goto skip; \ + case NL_STOP: \ + goto stop; \ + default: \ + if (nmerr >= 0) { \ + nm_assert_not_reached(); \ + nmerr = -NME_BUG; \ + } \ + goto out; \ + } \ + } \ + } while (0) int -nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) +nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb) { - int n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0; - gs_free unsigned char *buf = NULL; - struct nlmsghdr *hdr; - struct sockaddr_nl nla = { 0 }; - struct ucred creds; - gboolean creds_has; + int n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0; + gs_free unsigned char *buf = NULL; + struct nlmsghdr * hdr; + struct sockaddr_nl nla = {0}; + struct ucred creds; + gboolean creds_has; continue_reading: - n = nl_recv (sk, &nla, &buf, &creds, &creds_has); - if (n <= 0) - return n; - - hdr = (struct nlmsghdr *) buf; - while (nlmsg_ok (hdr, n)) { - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nlmsg_alloc_convert (hdr); - - nlmsg_set_proto (msg, sk->s_proto); - nlmsg_set_src (msg, &nla); - nlmsg_set_creds (msg, creds_has ? &creds : NULL); - - nrecv++; - - /* Only do sequence checking if auto-ack mode is enabled */ - if (! (sk->s_flags & NL_NO_AUTO_ACK)) { - if (hdr->nlmsg_seq != sk->s_seq_expect) { - nmerr = -NME_NL_SEQ_MISMATCH; - goto out; - } - } - - if (hdr->nlmsg_type == NLMSG_DONE || - hdr->nlmsg_type == NLMSG_ERROR || - hdr->nlmsg_type == NLMSG_NOOP || - hdr->nlmsg_type == NLMSG_OVERRUN) { - /* We can't check for !NLM_F_MULTI since some netlink - * users in the kernel are broken. */ - sk->s_seq_expect++; - } - - if (hdr->nlmsg_flags & NLM_F_MULTI) - multipart = 1; - - if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { - /* - * We have to continue reading to clear - * all messages until a NLMSG_DONE is - * received and report the inconsistency. - */ - interrupted = 1; - } - - /* messages terminates a multipart message, this is - * usually the end of a message and therefore we slip - * out of the loop by default. the user may overrule - * this action by skipping this packet. */ - if (hdr->nlmsg_type == NLMSG_DONE) { - multipart = 0; - NL_CB_CALL (cb, finish, msg); - } - - /* Message to be ignored, the default action is to - * skip this message if no callback is specified. The - * user may overrule this action by returning - * NL_PROCEED. */ - else if (hdr->nlmsg_type == NLMSG_NOOP) - goto skip; - - /* Data got lost, report back to user. The default action is to - * quit parsing. The user may overrule this action by retuning - * NL_SKIP or NL_PROCEED (dangerous) */ - else if (hdr->nlmsg_type == NLMSG_OVERRUN) { - nmerr = -NME_NL_MSG_OVERFLOW; - goto out; - } - - /* Message carries a nlmsgerr */ - else if (hdr->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *e = nlmsg_data (hdr); - - if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) { - /* Truncated error message, the default action - * is to stop parsing. The user may overrule - * this action by returning NL_SKIP or - * NL_PROCEED (dangerous) */ - nmerr = -NME_NL_MSG_TRUNC; - goto out; - } - if (e->error) { - /* Error message reported back from kernel. */ - if (cb && cb->err_cb) { - /* the returned value here must be either a negative - * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ - nmerr = cb->err_cb (&nla, e, - cb->err_arg); - if (nmerr < 0) - goto out; - else if (nmerr == NL_SKIP) - goto skip; - else if (nmerr == NL_STOP) { - nmerr = -nm_errno_from_native (e->error); - goto out; - } - nm_assert (nmerr == NL_OK); - } else { - nmerr = -nm_errno_from_native (e->error); - goto out; - } - } else - NL_CB_CALL (cb, ack, msg); - } else { - /* Valid message (not checking for MULTIPART bit to - * get along with broken kernels. NL_SKIP has no - * effect on this. */ - NL_CB_CALL (cb, valid, msg); - } + n = nl_recv(sk, &nla, &buf, &creds, &creds_has); + if (n <= 0) + return n; + + hdr = (struct nlmsghdr *) buf; + while (nlmsg_ok(hdr, n)) { + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = nlmsg_alloc_convert(hdr); + + nlmsg_set_proto(msg, sk->s_proto); + nlmsg_set_src(msg, &nla); + nlmsg_set_creds(msg, creds_has ? &creds : NULL); + + nrecv++; + + /* Only do sequence checking if auto-ack mode is enabled */ + if (!(sk->s_flags & NL_NO_AUTO_ACK)) { + if (hdr->nlmsg_seq != sk->s_seq_expect) { + nmerr = -NME_NL_SEQ_MISMATCH; + goto out; + } + } + + if (hdr->nlmsg_type == NLMSG_DONE || hdr->nlmsg_type == NLMSG_ERROR + || hdr->nlmsg_type == NLMSG_NOOP || hdr->nlmsg_type == NLMSG_OVERRUN) { + /* We can't check for !NLM_F_MULTI since some netlink + * users in the kernel are broken. */ + sk->s_seq_expect++; + } + + if (hdr->nlmsg_flags & NLM_F_MULTI) + multipart = 1; + + if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { + /* + * We have to continue reading to clear + * all messages until a NLMSG_DONE is + * received and report the inconsistency. + */ + interrupted = 1; + } + + /* messages terminates a multipart message, this is + * usually the end of a message and therefore we slip + * out of the loop by default. the user may overrule + * this action by skipping this packet. */ + if (hdr->nlmsg_type == NLMSG_DONE) { + multipart = 0; + NL_CB_CALL(cb, finish, msg); + } + + /* Message to be ignored, the default action is to + * skip this message if no callback is specified. The + * user may overrule this action by returning + * NL_PROCEED. */ + else if (hdr->nlmsg_type == NLMSG_NOOP) + goto skip; + + /* Data got lost, report back to user. The default action is to + * quit parsing. The user may overrule this action by returning + * NL_SKIP or NL_PROCEED (dangerous) */ + else if (hdr->nlmsg_type == NLMSG_OVERRUN) { + nmerr = -NME_NL_MSG_OVERFLOW; + goto out; + } + + /* Message carries a nlmsgerr */ + else if (hdr->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *e = nlmsg_data(hdr); + + if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) { + /* Truncated error message, the default action + * is to stop parsing. The user may overrule + * this action by returning NL_SKIP or + * NL_PROCEED (dangerous) */ + nmerr = -NME_NL_MSG_TRUNC; + goto out; + } + if (e->error) { + /* Error message reported back from kernel. */ + if (cb && cb->err_cb) { + /* the returned value here must be either a negative + * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ + nmerr = cb->err_cb(&nla, e, cb->err_arg); + if (nmerr < 0) + goto out; + else if (nmerr == NL_SKIP) + goto skip; + else if (nmerr == NL_STOP) { + nmerr = -nm_errno_from_native(e->error); + goto out; + } + nm_assert(nmerr == NL_OK); + } else { + nmerr = -nm_errno_from_native(e->error); + goto out; + } + } else + NL_CB_CALL(cb, ack, msg); + } else { + /* Valid message (not checking for MULTIPART bit to + * get along with broken kernels. NL_SKIP has no + * effect on this. */ + NL_CB_CALL(cb, valid, msg); + } skip: - nmerr = 0; - hdr = nlmsg_next (hdr, &n); - } + nmerr = 0; + hdr = nlmsg_next(hdr, &n); + } - if (multipart) { - /* Multipart message not yet complete, continue reading */ - nm_clear_g_free (&buf); + if (multipart) { + /* Multipart message not yet complete, continue reading */ + nm_clear_g_free(&buf); - nmerr = 0; - goto continue_reading; - } + nmerr = 0; + goto continue_reading; + } stop: - nmerr = 0; + nmerr = 0; out: - if (interrupted) - nmerr = -NME_NL_DUMP_INTR; + if (interrupted) + nmerr = -NME_NL_DUMP_INTR; - nm_assert (nmerr <= 0); - return nmerr ?: nrecv; + nm_assert(nmerr <= 0); + return nmerr ?: nrecv; } int -nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) +nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) { - int ret; + int ret; - if (sk->s_fd < 0) - return -NME_NL_BAD_SOCK; + if (sk->s_fd < 0) + return -NME_NL_BAD_SOCK; - nlmsg_set_src (msg, &sk->s_local); + nlmsg_set_src(msg, &sk->s_local); - ret = sendmsg (sk->s_fd, hdr, 0); - if (ret < 0) - return -nm_errno_from_native (errno); + ret = sendmsg(sk->s_fd, hdr, 0); + if (ret < 0) + return -nm_errno_from_native(errno); - return ret; + return ret; } int -nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) +nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) { - struct sockaddr_nl *dst; - struct ucred *creds; - struct msghdr hdr = { - .msg_name = (void *) &sk->s_peer, - .msg_namelen = sizeof (struct sockaddr_nl), - .msg_iov = iov, - .msg_iovlen = iovlen, - }; - char buf[CMSG_SPACE (sizeof (struct ucred))]; - - /* Overwrite destination if specified in the message itself, defaults - * to the peer address of the socket. - */ - dst = nlmsg_get_dst (msg); - if (dst->nl_family == AF_NETLINK) - hdr.msg_name = dst; - - /* Add credentials if present. */ - creds = nlmsg_get_creds (msg); - if (creds != NULL) { - struct cmsghdr *cmsg; - - hdr.msg_control = buf; - hdr.msg_controllen = sizeof (buf); - - cmsg = CMSG_FIRSTHDR (&hdr); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; - cmsg->cmsg_len = CMSG_LEN (sizeof (struct ucred)); - memcpy (CMSG_DATA (cmsg), creds, sizeof (struct ucred)); - } - - return nl_sendmsg (sk, msg, &hdr); + struct sockaddr_nl *dst; + struct ucred * creds; + struct msghdr hdr = { + .msg_name = (void *) &sk->s_peer, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = iov, + .msg_iovlen = iovlen, + }; + char buf[CMSG_SPACE(sizeof(struct ucred))]; + + /* Overwrite destination if specified in the message itself, defaults + * to the peer address of the socket. + */ + dst = nlmsg_get_dst(msg); + if (dst->nl_family == AF_NETLINK) + hdr.msg_name = dst; + + /* Add credentials if present. */ + creds = nlmsg_get_creds(msg); + if (creds != NULL) { + struct cmsghdr *cmsg; + + hdr.msg_control = buf; + hdr.msg_controllen = sizeof(buf); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); + } + + return nl_sendmsg(sk, msg, &hdr); } void -nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg) +nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg) { - struct nlmsghdr *nlh; + struct nlmsghdr *nlh; - nlh = nlmsg_hdr (msg); - if (nlh->nlmsg_pid == NL_AUTO_PORT) - nlh->nlmsg_pid = nl_socket_get_local_port (sk); + nlh = nlmsg_hdr(msg); + if (nlh->nlmsg_pid == NL_AUTO_PORT) + nlh->nlmsg_pid = nl_socket_get_local_port(sk); - if (nlh->nlmsg_seq == NL_AUTO_SEQ) - nlh->nlmsg_seq = sk->s_seq_next++; + if (nlh->nlmsg_seq == NL_AUTO_SEQ) + nlh->nlmsg_seq = sk->s_seq_next++; - if (msg->nm_protocol == -1) - msg->nm_protocol = sk->s_proto; + if (msg->nm_protocol == -1) + msg->nm_protocol = sk->s_proto; - nlh->nlmsg_flags |= NLM_F_REQUEST; + nlh->nlmsg_flags |= NLM_F_REQUEST; - if (!(sk->s_flags & NL_NO_AUTO_ACK)) - nlh->nlmsg_flags |= NLM_F_ACK; + if (!(sk->s_flags & NL_NO_AUTO_ACK)) + nlh->nlmsg_flags |= NLM_F_ACK; } int -nl_send (struct nl_sock *sk, struct nl_msg *msg) +nl_send(struct nl_sock *sk, struct nl_msg *msg) { - struct iovec iov = { - .iov_base = (void *) nlmsg_hdr (msg), - .iov_len = nlmsg_hdr (msg)->nlmsg_len, - }; + struct iovec iov = { + .iov_base = (void *) nlmsg_hdr(msg), + .iov_len = nlmsg_hdr(msg)->nlmsg_len, + }; - return nl_send_iovec (sk, msg, &iov, 1); + return nl_send_iovec(sk, msg, &iov, 1); } -int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg) +int +nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) { - nl_complete_msg (sk, msg); + nl_complete_msg(sk, msg); - return nl_send (sk, msg); + return nl_send(sk, msg); } int -nl_recv (struct nl_sock *sk, - struct sockaddr_nl *nla, - unsigned char **buf, - struct ucred *out_creds, - gboolean *out_creds_has) +nl_recv(struct nl_sock * sk, + struct sockaddr_nl *nla, + unsigned char ** buf, + struct ucred * out_creds, + gboolean * out_creds_has) { - ssize_t n; - int flags = 0; - struct iovec iov; - struct msghdr msg = { - .msg_name = (void *) nla, - .msg_namelen = sizeof (struct sockaddr_nl), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - struct ucred tmpcreds; - gboolean tmpcreds_has = FALSE; - int retval; - int errsv; - - nm_assert (nla); - nm_assert (buf && !*buf); - nm_assert (!out_creds_has == !out_creds); - - if ( (sk->s_flags & NL_MSG_PEEK) - || ( !(sk->s_flags & NL_MSG_PEEK_EXPLICIT) - && sk->s_bufsize == 0)) - flags |= MSG_PEEK | MSG_TRUNC; - - iov.iov_len = sk->s_bufsize - ?: (((size_t) nm_utils_getpagesize ()) * 4u); - iov.iov_base = g_malloc (iov.iov_len); - - if ( out_creds - && (sk->s_flags & NL_SOCK_PASSCRED)) { - msg.msg_controllen = CMSG_SPACE (sizeof (struct ucred)); - msg.msg_control = g_malloc (msg.msg_controllen); - } + ssize_t n; + int flags = 0; + struct iovec iov; + struct msghdr msg = { + .msg_name = (void *) nla, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + struct ucred tmpcreds; + gboolean tmpcreds_has = FALSE; + int retval; + int errsv; + + nm_assert(nla); + nm_assert(buf && !*buf); + nm_assert(!out_creds_has == !out_creds); + + if ((sk->s_flags & NL_MSG_PEEK) + || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0)) + flags |= MSG_PEEK | MSG_TRUNC; + + iov.iov_len = sk->s_bufsize ?: (((size_t) nm_utils_getpagesize()) * 4u); + iov.iov_base = g_malloc(iov.iov_len); + + if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); + msg.msg_control = g_malloc(msg.msg_controllen); + } retry: - n = recvmsg (sk->s_fd, &msg, flags); - if (!n) { - retval = 0; - goto abort; - } - - if (n < 0) { - errsv = errno; - if (errsv == EINTR) - goto retry; - retval = -nm_errno_from_native (errsv); - goto abort; - } - - if (msg.msg_flags & MSG_CTRUNC) { - if (msg.msg_controllen == 0) { - retval = -NME_NL_MSG_TRUNC; - goto abort; - } - - msg.msg_controllen *= 2; - msg.msg_control = g_realloc (msg.msg_control, msg.msg_controllen); - goto retry; - } - - if ( iov.iov_len < n - || (msg.msg_flags & MSG_TRUNC)) { - /* respond with error to an incomplete message */ - if (flags == 0) { - retval = -NME_NL_MSG_TRUNC; - goto abort; - } - - /* Provided buffer is not long enough, enlarge it - * to size of n (which should be total length of the message) - * and try again. */ - iov.iov_base = g_realloc (iov.iov_base, n); - iov.iov_len = n; - flags = 0; - goto retry; - } - - if (flags != 0) { - /* Buffer is big enough, do the actual reading */ - flags = 0; - goto retry; - } - - if (msg.msg_namelen != sizeof (struct sockaddr_nl)) { - retval = -NME_UNSPEC; - goto abort; - } - - if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { - struct cmsghdr *cmsg; - - for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET) - continue; - if (cmsg->cmsg_type != SCM_CREDENTIALS) - continue; - memcpy (&tmpcreds, CMSG_DATA (cmsg), sizeof (tmpcreds)); - tmpcreds_has = TRUE; - break; - } - } - - retval = n; + n = recvmsg(sk->s_fd, &msg, flags); + if (!n) { + retval = 0; + goto abort; + } + + if (n < 0) { + errsv = errno; + if (errsv == EINTR) + goto retry; + retval = -nm_errno_from_native(errsv); + goto abort; + } + + if (msg.msg_flags & MSG_CTRUNC) { + if (msg.msg_controllen == 0) { + retval = -NME_NL_MSG_TRUNC; + goto abort; + } + + msg.msg_controllen *= 2; + msg.msg_control = g_realloc(msg.msg_control, msg.msg_controllen); + goto retry; + } + + if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) { + /* respond with error to an incomplete message */ + if (flags == 0) { + retval = -NME_NL_MSG_TRUNC; + goto abort; + } + + /* Provided buffer is not long enough, enlarge it + * to size of n (which should be total length of the message) + * and try again. */ + iov.iov_base = g_realloc(iov.iov_base, n); + iov.iov_len = n; + flags = 0; + goto retry; + } + + if (flags != 0) { + /* Buffer is big enough, do the actual reading */ + flags = 0; + goto retry; + } + + if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + retval = -NME_UNSPEC; + goto abort; + } + + if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + if (cmsg->cmsg_type != SCM_CREDENTIALS) + continue; + memcpy(&tmpcreds, CMSG_DATA(cmsg), sizeof(tmpcreds)); + tmpcreds_has = TRUE; + break; + } + } + + retval = n; abort: - g_free (msg.msg_control); - - if (retval <= 0) { - g_free (iov.iov_base); - return retval; - } - - *buf = iov.iov_base; - if (out_creds && tmpcreds_has) - *out_creds = tmpcreds; - NM_SET_OUT (out_creds_has, tmpcreds_has); - return retval; + g_free(msg.msg_control); + + if (retval <= 0) { + g_free(iov.iov_base); + return retval; + } + + *buf = iov.iov_base; + if (out_creds && tmpcreds_has) + *out_creds = tmpcreds; + NM_SET_OUT(out_creds_has, tmpcreds_has); + return retval; } |