diff options
Diffstat (limited to 'src/platform/nm-netlink.c')
| -rw-r--r-- | src/platform/nm-netlink.c | 433 |
1 files changed, 222 insertions, 211 deletions
diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 3e2ad911..71506a2c 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -42,16 +42,14 @@ #define NETLINK_EXT_ACK 11 #endif -#define NL_MSG_CRED_PRESENT 1 - struct nl_msg { int nm_protocol; - int nm_flags; 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 { @@ -67,38 +65,6 @@ struct nl_sock { /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_ITEM (NLE_UNSPEC, "NLE_UNSPEC"), - NM_UTILS_LOOKUP_ITEM (NLE_BUG, "NLE_BUG"), - NM_UTILS_LOOKUP_ITEM (NLE_NATIVE_ERRNO, "NLE_NATIVE_ERRNO"), - - NM_UTILS_LOOKUP_ITEM (NLE_ATTRSIZE, "NLE_ATTRSIZE"), - NM_UTILS_LOOKUP_ITEM (NLE_BAD_SOCK, "NLE_BAD_SOCK"), - NM_UTILS_LOOKUP_ITEM (NLE_DUMP_INTR, "NLE_DUMP_INTR"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_OVERFLOW, "NLE_MSG_OVERFLOW"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TOOSHORT, "NLE_MSG_TOOSHORT"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TRUNC, "NLE_MSG_TRUNC"), - NM_UTILS_LOOKUP_ITEM (NLE_SEQ_MISMATCH, "NLE_SEQ_MISMATCH"), -) - -const char * -nl_geterror (int nlerr) -{ - const char *s; - - nlerr = nl_errno (nlerr); - - if (nlerr >= _NLE_BASE) { - s = _geterror (nlerr); - if (s) - return s; - } - return g_strerror (nlerr); -} - -/*****************************************************************************/ - NM_UTILS_ENUM2STR_DEFINE (nl_nlmsgtype2str, int, NM_UTILS_ENUM2STR (NLMSG_NOOP, "NOOP"), NM_UTILS_ENUM2STR (NLMSG_ERROR, "ERROR"), @@ -136,21 +102,30 @@ nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; switch (hdr->nlmsg_type) { - case RTM_NEWLINK: s = "RTM_NEWLINK"; break; - case RTM_DELLINK: s = "RTM_DELLINK"; break; - case RTM_NEWADDR: s = "RTM_NEWADDR"; break; - case RTM_DELADDR: s = "RTM_DELADDR"; break; - case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; - case RTM_DELROUTE: s = "RTM_DELROUTE"; break; - case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; - case RTM_DELQDISC: s = "RTM_DELQDISC"; 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; + 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) @@ -239,6 +214,8 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad) size_t nlmsg_len = n->nm_nlh->nlmsg_len; size_t tlen; + nm_assert (pad >= 0); + if (len > n->nm_size) return NULL; @@ -285,20 +262,6 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) /*****************************************************************************/ -static int -get_default_page_size (void) -{ - static int val = 0; - int v; - - if (G_UNLIKELY (val == 0)) { - v = getpagesize (); - g_assert (v > 0); - val = v; - } - return val; -} - struct nl_msg * nlmsg_alloc_size (size_t len) { @@ -307,11 +270,12 @@ nlmsg_alloc_size (size_t len) if (len < sizeof (struct nlmsghdr)) len = sizeof (struct nlmsghdr); - nm = g_slice_new0 (struct nl_msg); - - nm->nm_protocol = -1; - nm->nm_size = len; - nm->nm_nlh = g_malloc0 (len); + 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; } @@ -328,7 +292,7 @@ nlmsg_alloc_size (size_t len) struct nl_msg * nlmsg_alloc (void) { - return nlmsg_alloc_size (get_default_page_size ()); + return nlmsg_alloc_size (nm_utils_getpagesize ()); } struct nl_msg * @@ -366,10 +330,18 @@ void nlmsg_free (struct nl_msg *msg) /*****************************************************************************/ int -nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) +nlmsg_append (struct nl_msg *n, + const void *data, + size_t len, + int pad) { void *tmp; + 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; @@ -385,7 +357,7 @@ nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { if (!nlmsg_valid_hdr (nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; + return -NME_NL_MSG_TOOSHORT; return nla_parse (tb, maxtype, nlmsg_attrdata (nlh, hdrlen), nlmsg_attrlen (nlh, hdrlen), policy); @@ -413,48 +385,77 @@ nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, return nlh; } -uint64_t -nla_get_u64 (const struct nlattr *nla) -{ - uint64_t tmp = 0; - - if (nla && nla_len (nla) >= sizeof (tmp)) - memcpy (&tmp, nla_data (nla), sizeof (tmp)); - - return tmp; -} - size_t -nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len (nla); - const char *src = nla_data (nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; +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; + } - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; + nm_assert (dst); - memset (dst, 0, dstsize); - memcpy (dst, src, len); + 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; + } + } } - return srclen; + memset (dst, 0, dstsize); + return 0; } -int -nla_memcpy (void *dest, const struct nlattr *src, int count) +size_t +nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize) { - int minlen; + size_t len; + int srclen; - if (!src) + if (!nla) return 0; - minlen = NM_MIN (count, (int) nla_len (src)); - memcpy (dest, nla_data (src), minlen); + srclen = nla_len (nla); - return minlen; + 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 @@ -465,7 +466,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) nla = nla_reserve (msg, attrtype, datalen); if (!nla) { if (datalen < 0) - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); return -ENOMEM; } @@ -531,7 +532,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) nla_nest_cancel (msg, start); /* Return error only if nlattr size was exceeded */ - return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE; + return (len == NLA_HDRLEN) ? 0 : -NME_NL_ATTRSIZE; } start->nla_len = len; @@ -539,13 +540,13 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) 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 boundry. + * 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 (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); } return 0; @@ -580,7 +581,7 @@ validate_nla (const struct nlattr *nla, int maxtype, pt = &policy[type]; if (pt->type > NLA_TYPE_MAX) - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); if (pt->minlen) minlen = pt->minlen; @@ -588,15 +589,19 @@ validate_nla (const struct nlattr *nla, int maxtype, minlen = nla_attr_minlen[pt->type]; if (nla_len (nla) < minlen) - return -NLE_UNSPEC; + return -NME_UNSPEC; if (pt->maxlen && nla_len (nla) > pt->maxlen) - return -NLE_UNSPEC; + return -NME_UNSPEC; if (pt->type == NLA_STRING) { - const char *data = nla_data (nla); + const char *data; + + nm_assert (minlen > 0); + + data = nla_data (nla); if (data[nla_len (nla) - 1] != '\0') - return -NLE_UNSPEC; + return -NME_UNSPEC; } return 0; @@ -607,7 +612,7 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy) { struct nlattr *nla; - int rem, nlerr; + int rem, nmerr; memset (tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); @@ -618,17 +623,15 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, continue; if (policy) { - nlerr = validate_nla (nla, maxtype, policy); - if (nlerr < 0) - goto errout; + nmerr = validate_nla (nla, maxtype, policy); + if (nmerr < 0) + return nmerr; } tb[type] = nla; } - nlerr = 0; -errout: - return nlerr; + return 0; } /*****************************************************************************/ @@ -654,7 +657,7 @@ nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr) struct ucred * nlmsg_get_creds (struct nl_msg *msg) { - if (msg->nm_flags & NL_MSG_CRED_PRESENT) + if (msg->nm_creds_has) return &msg->nm_creds; return NULL; } @@ -662,8 +665,11 @@ nlmsg_get_creds (struct nl_msg *msg) void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds) { - memcpy (&msg->nm_creds, creds, sizeof (*creds)); - msg->nm_flags |= NL_MSG_CRED_PRESENT; + if (creds) { + memcpy (&msg->nm_creds, creds, sizeof (*creds)); + msg->nm_creds_has = TRUE; + } else + msg->nm_creds_has = FALSE; } /*****************************************************************************/ @@ -754,7 +760,7 @@ genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], struct genlmsghdr *ghdr; if (!genlmsg_valid_hdr (nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; + return -NME_NL_MSG_TOOSHORT; ghdr = nlmsg_data (nlh); return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), @@ -764,21 +770,21 @@ genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], static int _genl_parse_getfamily (struct nl_msg *msg, void *arg) { - static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + static const struct nla_policy ctrl_policy[] = { [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, - .maxlen = GENL_NAMSIZ }, + .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[CTRL_ATTR_MAX+1]; + struct nlattr *tb[G_N_ELEMENTS (ctrl_policy)]; struct nlmsghdr *nlh = nlmsg_hdr (msg); gint32 *response_data = arg; - if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) + if (genlmsg_parse_arr (nlh, 0, tb, ctrl_policy) < 0) return NL_SKIP; if (tb[CTRL_ATTR_FAMILY_ID]) @@ -791,7 +797,7 @@ int genl_ctrl_resolve (struct nl_sock *sk, const char *name) { nm_auto_nlmsg struct nl_msg *msg = NULL; - int nlerr; + int nmerr; gint32 response_data = -1; const struct nl_cb cb = { .valid_cb = _genl_parse_getfamily, @@ -804,25 +810,25 @@ genl_ctrl_resolve (struct nl_sock *sk, const char *name) 0, 0, CTRL_CMD_GETFAMILY, 1)) return -ENOMEM; - nlerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name); - if (nlerr < 0) - return nlerr; + nmerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name); + if (nmerr < 0) + return nmerr; - nlerr = nl_send_auto (sk, msg); - if (nlerr < 0) - return nlerr; + nmerr = nl_send_auto (sk, msg); + if (nmerr < 0) + return nmerr; - nlerr = nl_recvmsgs (sk, &cb); - if (nlerr < 0) - return nlerr; + nmerr = nl_recvmsgs (sk, &cb); + if (nmerr < 0) + return nmerr; /* If search was successful, request may be ACKed after data */ - nlerr = nl_wait_for_ack (sk, NULL); - if (nlerr < 0) - return nlerr; + nmerr = nl_wait_for_ack (sk, NULL); + if (nmerr < 0) + return nmerr; if (response_data < 0) - return -NLE_UNSPEC; + return -NME_UNSPEC; return response_data; } @@ -879,12 +885,12 @@ nl_socket_set_passcred (struct nl_sock *sk, int state) int err; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; err = setsockopt (sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof (state)); if (err < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); if (state) sk->s_flags |= NL_SOCK_PASSCRED; @@ -912,10 +918,10 @@ int nl_socket_set_nonblocking (const struct nl_sock *sk) { if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; if (fcntl (sk->s_fd, F_SETFL, O_NONBLOCK) < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); return 0; } @@ -932,18 +938,18 @@ nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf) txbuf = 32768; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; err = setsockopt (sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof (txbuf)); if (err < 0) { - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); } err = setsockopt (sk->s_fd, SOL_SOCKET, SO_RCVBUF, &rxbuf, sizeof (rxbuf)); if (err < 0) { - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); } return 0; @@ -956,14 +962,14 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...) va_list ap; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; va_start (ap, group); while (group != 0) { if (group < 0) { va_end (ap); - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); } err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, @@ -972,7 +978,7 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...) int errsv = errno; va_end (ap); - return -nl_syserr2nlerr (errsv); + return -nm_errno_from_native (errsv); } group = va_arg (ap, int); @@ -989,12 +995,12 @@ nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable) int err, val; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; val = !!enable; err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof (val)); if (err < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); return 0; } @@ -1008,21 +1014,21 @@ void nl_socket_disable_msg_peek (struct nl_sock *sk) int nl_connect (struct nl_sock *sk, int protocol) { - int err, nlerr; + int err, nmerr; socklen_t addrlen; struct sockaddr_nl local = { 0 }; if (sk->s_fd != -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); if (sk->s_fd < 0) { - nlerr = -nl_syserr2nlerr (errno); + nmerr = -nm_errno_from_native (errno); goto errout; } - nlerr = nl_socket_set_buffer_size (sk, 0, 0); - if (nlerr < 0) + nmerr = nl_socket_set_buffer_size (sk, 0, 0); + if (nmerr < 0) goto errout; nm_assert (sk->s_local.nl_pid == 0); @@ -1030,7 +1036,7 @@ nl_connect (struct nl_sock *sk, int protocol) err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local, sizeof (sk->s_local)); if (err != 0) { - nlerr = -nl_syserr2nlerr (errno); + nmerr = -nm_errno_from_native (errno); goto errout; } @@ -1038,17 +1044,17 @@ nl_connect (struct nl_sock *sk, int protocol) err = getsockname (sk->s_fd, (struct sockaddr *) &local, &addrlen); if (err < 0) { - nlerr = -nl_syserr2nlerr (errno); + nmerr = -nm_errno_from_native (errno); goto errout; } if (addrlen != sizeof (local)) { - nlerr = -NLE_UNSPEC; + nmerr = -NME_UNSPEC; goto errout; } if (local.nl_family != AF_NETLINK) { - nlerr = -NLE_UNSPEC; + nmerr = -NME_UNSPEC; goto errout; } @@ -1062,7 +1068,7 @@ errout: close (sk->s_fd); sk->s_fd = -1; } - return nlerr; + return nmerr; } /*****************************************************************************/ @@ -1098,22 +1104,22 @@ nl_wait_for_ack (struct nl_sock *sk, do { \ const struct nl_cb *_cb = (cb); \ \ - if (_cb->type##_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. */ \ - nlerr = _cb->type##_cb ((msg), _cb->type##_arg); \ - switch (nlerr) { \ + nmerr = _cb->type##_cb ((msg), _cb->type##_arg); \ + switch (nmerr) { \ case NL_OK: \ - nlerr = 0; \ + nm_assert (nmerr == 0); \ break; \ case NL_SKIP: \ goto skip; \ case NL_STOP: \ goto stop; \ default: \ - if (nlerr >= 0) { \ + if (nmerr >= 0) { \ nm_assert_not_reached (); \ - nlerr = -NLE_BUG; \ + nmerr = -NME_BUG; \ } \ goto out; \ } \ @@ -1123,14 +1129,15 @@ do { \ int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) { - int n, nlerr = 0, multipart = 0, interrupted = 0, nrecv = 0; + int n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0; gs_free unsigned char *buf = NULL; struct nlmsghdr *hdr; struct sockaddr_nl nla = { 0 }; - gs_free struct ucred *creds = NULL; + struct ucred creds; + gboolean creds_has; continue_reading: - n = nl_recv (sk, &nla, &buf, &creds); + n = nl_recv (sk, &nla, &buf, &creds, &creds_has); if (n <= 0) return n; @@ -1142,15 +1149,14 @@ continue_reading: nlmsg_set_proto (msg, sk->s_proto); nlmsg_set_src (msg, &nla); - if (creds) - nlmsg_set_creds (msg, creds); + 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) { - nlerr = -NLE_SEQ_MISMATCH; + nmerr = -NME_NL_SEQ_MISMATCH; goto out; } } @@ -1196,7 +1202,7 @@ continue_reading: * quit parsing. The user may overrule this action by retuning * NL_SKIP or NL_PROCEED (dangerous) */ else if (hdr->nlmsg_type == NLMSG_OVERRUN) { - nlerr = -NLE_MSG_OVERFLOW; + nmerr = -NME_NL_MSG_OVERFLOW; goto out; } @@ -1209,27 +1215,27 @@ continue_reading: * is to stop parsing. The user may overrule * this action by returning NL_SKIP or * NL_PROCEED (dangerous) */ - nlerr = -NLE_MSG_TRUNC; + nmerr = -NME_NL_MSG_TRUNC; goto out; } if (e->error) { /* Error message reported back from kernel. */ - if (cb->err_cb) { + 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. */ - nlerr = cb->err_cb (&nla, e, + nmerr = cb->err_cb (&nla, e, cb->err_arg); - if (nlerr < 0) + if (nmerr < 0) goto out; - else if (nlerr == NL_SKIP) + else if (nmerr == NL_SKIP) goto skip; - else if (nlerr == NL_STOP) { - nlerr = -nl_syserr2nlerr (e->error); + else if (nmerr == NL_STOP) { + nmerr = -nm_errno_from_native (e->error); goto out; } - nm_assert (nlerr == NL_OK); + nm_assert (nmerr == NL_OK); } else { - nlerr = -nl_syserr2nlerr (e->error); + nmerr = -nm_errno_from_native (e->error); goto out; } } else @@ -1241,27 +1247,27 @@ continue_reading: NL_CB_CALL (cb, valid, msg); } skip: - nlerr = 0; + nmerr = 0; hdr = nlmsg_next (hdr, &n); } if (multipart) { /* Multipart message not yet complete, continue reading */ - nm_clear_g_free (&creds); nm_clear_g_free (&buf); + nmerr = 0; goto continue_reading; } stop: - nlerr = 0; + nmerr = 0; out: if (interrupted) - nlerr = -NLE_DUMP_INTR; + nmerr = -NME_NL_DUMP_INTR; - nm_assert (nlerr <= 0); - return nlerr ?: nrecv; + nm_assert (nmerr <= 0); + return nmerr ?: nrecv; } int @@ -1270,13 +1276,13 @@ nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) int ret; if (sk->s_fd < 0) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; nlmsg_set_src (msg, &sk->s_local); ret = sendmsg (sk->s_fd, hdr, 0); if (ret < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); return ret; } @@ -1359,12 +1365,14 @@ int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg) } int -nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds) +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; - static int page_size = 0; struct iovec iov; struct msghdr msg = { .msg_name = (void *) nla, @@ -1372,25 +1380,25 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, .msg_iov = &iov, .msg_iovlen = 1, }; - gs_free struct ucred* tmpcreds = NULL; + struct ucred tmpcreds; + gboolean tmpcreds_has = FALSE; int retval; + int errsv; nm_assert (nla); nm_assert (buf && !*buf); - nm_assert (!creds || !*creds); + 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; - if (page_size == 0) - page_size = getpagesize () * 4; - - iov.iov_len = sk->s_bufsize ?: page_size; + iov.iov_len = sk->s_bufsize + ?: (((size_t) nm_utils_getpagesize ()) * 4u); iov.iov_base = g_malloc (iov.iov_len); - if ( creds + 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); @@ -1404,16 +1412,16 @@ retry: } if (n < 0) { - if (errno == EINTR) + errsv = errno; + if (errsv == EINTR) goto retry; - - retval = -nl_syserr2nlerr (errno); + retval = -nm_errno_from_native (errsv); goto abort; } if (msg.msg_flags & MSG_CTRUNC) { if (msg.msg_controllen == 0) { - retval = -NLE_MSG_TRUNC; + retval = -NME_NL_MSG_TRUNC; goto abort; } @@ -1426,7 +1434,7 @@ retry: || (msg.msg_flags & MSG_TRUNC)) { /* respond with error to an incomplete message */ if (flags == 0) { - retval = -NLE_MSG_TRUNC; + retval = -NME_NL_MSG_TRUNC; goto abort; } @@ -1446,11 +1454,11 @@ retry: } if (msg.msg_namelen != sizeof (struct sockaddr_nl)) { - retval = -NLE_UNSPEC; + retval = -NME_UNSPEC; goto abort; } - if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { @@ -1458,7 +1466,8 @@ retry: continue; if (cmsg->cmsg_type != SCM_CREDENTIALS) continue; - tmpcreds = nm_memdup (CMSG_DATA (cmsg), sizeof (*tmpcreds)); + memcpy (&tmpcreds, CMSG_DATA (cmsg), sizeof (tmpcreds)); + tmpcreds_has = TRUE; break; } } @@ -1474,6 +1483,8 @@ abort: } *buf = iov.iov_base; - NM_SET_OUT (creds, g_steal_pointer (&tmpcreds)); + if (out_creds && tmpcreds_has) + *out_creds = tmpcreds; + NM_SET_OUT (out_creds_has, tmpcreds_has); return retval; } |