From 4a22abdda1595224dcad1b9b101e07d93e4a6637 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 16 Jun 2022 20:30:07 +0200 Subject: [PATCH 01/11] platform/netlink: add nm_auto_nlsock cleanup macro --- src/libnm-platform/nm-netlink.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index bb1e41eed..2ac851139 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -413,11 +413,7 @@ void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr); struct ucred *nlmsg_get_creds(struct nl_msg *msg); void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds); -static inline void -_nm_auto_nl_msg_cleanup(struct nl_msg **ptr) -{ - nlmsg_free(*ptr); -} +NM_AUTO_DEFINE_FCN0(struct nl_msg *, _nm_auto_nl_msg_cleanup, nlmsg_free); #define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) static inline void * @@ -496,6 +492,9 @@ struct nl_sock *nl_socket_alloc(void); void nl_socket_free(struct nl_sock *sk); +NM_AUTO_DEFINE_FCN0(struct nl_sock *, _nm_auto_nlsock, nl_socket_free); +#define nm_auto_nlsock nm_auto(_nm_auto_nlsock) + int nl_socket_get_fd(const struct nl_sock *sk); struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg); From f96fbc8ebec23dfe7c564c055cef2fd469fa2f7e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 16 Jun 2022 20:30:37 +0200 Subject: [PATCH 02/11] platform/netlink: combine nl_socket_alloc() and nl_connect() Create and use new nl_socket_new(). nl_socket_alloc() really does nothing but allocating the struct and initializing the fd to -1. In all cases, we want to call nl_connect() right after. Combine the two. Then we also cannot have a "struct nl_sock" without a valid fd. This means several error checks can be dropped. Note that former nl_connect() did several things at once. Maybe, for more flexibility one would need to tweak what should be done there. For now that is not necessary. In any case, if we need more flexibility, then we would control what nl_connect() (now nl_socket_new()) does, and not the split between nl_socket_alloc() and nl_connect(). --- src/libnm-platform/nm-linux-platform.c | 16 +-- src/libnm-platform/nm-netlink.c | 132 ++++++++++---------- src/libnm-platform/nm-netlink.h | 2 +- src/libnm-platform/tests/test-nm-platform.c | 3 +- 4 files changed, 71 insertions(+), 82 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 40cb43969..4fa63f806 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9721,21 +9721,13 @@ constructed(GObject *_object) nm_platform_get_use_udev(platform) ? "use" : "no", nm_platform_get_cache_tc(platform) ? "use" : "no"); - priv->genl = nl_socket_alloc(); - g_assert(priv->genl); - - nle = nl_connect(priv->genl, NETLINK_GENERIC); - if (nle) { + nle = nl_socket_new(&priv->genl, NETLINK_GENERIC); + if (nle) _LOGE("unable to connect the generic netlink socket \"%s\" (%d)", nm_strerror(nle), -nle); - nl_socket_free(priv->genl); - priv->genl = NULL; - } - priv->nlh = nl_socket_alloc(); - g_assert(priv->nlh); - - nle = nl_connect(priv->nlh, NETLINK_ROUTE); + nle = nl_socket_new(&priv->nlh, NETLINK_ROUTE); g_assert(!nle); + nle = nl_socket_set_passcred(priv->nlh, 1); g_assert(!nle); diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 697ae5919..d7a74c7a0 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -18,6 +18,16 @@ /*****************************************************************************/ +#define nm_assert_sk(sk) \ + G_STMT_START \ + { \ + const struct nl_sock *_sk = (sk); \ + \ + nm_assert(_sk); \ + nm_assert(_sk->s_fd >= 0); \ + } \ + G_STMT_END + #define NL_SOCK_PASSCRED (1 << 1) #define NL_MSG_PEEK (1 << 3) #define NL_MSG_PEEK_EXPLICIT (1 << 4) @@ -879,30 +889,14 @@ genl_ctrl_resolve(struct nl_sock *sk, const char *name) /*****************************************************************************/ -struct nl_sock * -nl_socket_alloc(void) -{ - struct nl_sock *sk; - - 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); - - return sk; -} - void nl_socket_free(struct nl_sock *sk) { if (!sk) return; - if (sk->s_fd >= 0) - nm_close(sk->s_fd); - g_slice_free(struct nl_sock, sk); + nm_close(sk->s_fd); + nm_g_slice_free(sk); } int @@ -928,8 +922,7 @@ nl_socket_set_passcred(struct nl_sock *sk, int state) { int err; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state)); if (err < 0) @@ -960,8 +953,7 @@ nlmsg_get_dst(struct nl_msg *msg) int nl_socket_set_nonblocking(const struct nl_sock *sk) { - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) return -nm_errno_from_native(errno); @@ -974,15 +966,14 @@ nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { int err; + nm_assert_sk(sk); + if (rxbuf <= 0) rxbuf = 32768; if (txbuf <= 0) txbuf = 32768; - 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); @@ -1002,8 +993,7 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...) int err; va_list ap; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); va_start(ap, group); @@ -1032,10 +1022,10 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...) int nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable) { - int err, val; + int err; + int val; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); val = !!enable; err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val)); @@ -1052,62 +1042,70 @@ nl_socket_disable_msg_peek(struct nl_sock *sk) sk->s_flags &= ~NL_MSG_PEEK; } +/*****************************************************************************/ + int -nl_connect(struct nl_sock *sk, int protocol) +nl_socket_new(struct nl_sock **out_sk, int protocol) { - int err, nmerr; - socklen_t addrlen; - struct sockaddr_nl local = {0}; + nm_auto_nlsock struct nl_sock *sk = NULL; + nm_auto_close int fd = -1; + time_t t; + int err; + int nmerr; + socklen_t addrlen; + struct sockaddr_nl local = {0}; - if (sk->s_fd != -1) - return -NME_NL_BAD_SOCK; + nm_assert(out_sk && !*out_sk); - sk->s_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); - if (sk->s_fd < 0) { - nmerr = -nm_errno_from_native(errno); - goto errout; - } + fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); + if (fd < 0) + return -nm_errno_from_native(errno); + + t = time(NULL); + + sk = g_slice_new(struct nl_sock); + *sk = (struct nl_sock){ + .s_fd = nm_steal_fd(&fd), + .s_local = + { + .nl_pid = 0, + .nl_family = AF_NETLINK, + .nl_groups = 0, + }, + .s_peer = + { + .nl_pid = 0, + .nl_family = AF_NETLINK, + .nl_groups = 0, + }, + .s_seq_expect = t, + .s_seq_next = t, + }; nmerr = nl_socket_set_buffer_size(sk, 0, 0); if (nmerr < 0) - goto errout; - - nm_assert(sk->s_local.nl_pid == 0); + return nmerr; 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; - } + if (err != 0) + return -nm_errno_from_native(errno); addrlen = sizeof(local); err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen); - if (err < 0) { - nmerr = -nm_errno_from_native(errno); - goto errout; - } + if (err < 0) + return -nm_errno_from_native(errno); - if (addrlen != sizeof(local)) { - nmerr = -NME_UNSPEC; - goto errout; - } + if (addrlen != sizeof(local)) + return -NME_UNSPEC; - if (local.nl_family != AF_NETLINK) { - nmerr = -NME_UNSPEC; - goto errout; - } + if (local.nl_family != AF_NETLINK) + return -NME_UNSPEC; sk->s_local = local; sk->s_proto = protocol; + *out_sk = g_steal_pointer(&sk); return 0; - -errout: - if (sk->s_fd != -1) { - close(sk->s_fd); - sk->s_fd = -1; - } - return nmerr; } /*****************************************************************************/ diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index 2ac851139..441a12333 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -488,7 +488,7 @@ nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, i struct nl_sock; -struct nl_sock *nl_socket_alloc(void); +int nl_socket_new(struct nl_sock **out_sk, int protocol); void nl_socket_free(struct nl_sock *sk); diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 9ac69bded..9263a6e7d 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -59,7 +59,7 @@ test_use_symbols(void) (void (*)(void)) genlmsg_valid_hdr, (void (*)(void)) genlmsg_parse, (void (*)(void)) genl_ctrl_resolve, - (void (*)(void)) nl_socket_alloc, + (void (*)(void)) nl_socket_new, (void (*)(void)) nl_socket_free, (void (*)(void)) nl_socket_get_fd, (void (*)(void)) nl_socket_get_local_port, @@ -72,7 +72,6 @@ test_use_symbols(void) (void (*)(void)) nl_socket_add_memberships, (void (*)(void)) nl_socket_set_ext_ack, (void (*)(void)) nl_socket_disable_msg_peek, - (void (*)(void)) nl_connect, (void (*)(void)) nl_wait_for_ack, (void (*)(void)) nl_recvmsgs, (void (*)(void)) nl_sendmsg, From 67d64fd4e5479895d73e3c4976303912da46e540 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 16 Jun 2022 20:37:33 +0200 Subject: [PATCH 03/11] platform/netlink: also set NETLINK_EXT_ACK for genl socket There are only two callers of nl_socket_new(). One for NETLINK_GENERIC and one for NETLINK_ROUTE. We already were enabling ext-ack for the rtnetlink socket. Also enable it for the genl socket. Do that, but just moving this inside nl_socket_new(). I cannot imagine a case where we don't want this. --- src/libnm-platform/nm-linux-platform.c | 4 ---- src/libnm-platform/nm-netlink.c | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 4fa63f806..880244a40 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9739,10 +9739,6 @@ constructed(GObject *_object) nle = nl_socket_set_buffer_size(priv->nlh, 8 * 1024 * 1024, 0); g_assert(!nle); - nle = nl_socket_set_ext_ack(priv->nlh, TRUE); - if (nle) - _LOGD("could not enable extended acks on netlink socket"); - /* explicitly set the msg buffer size and disable MSG_PEEK. * We use our own receive buffer priv->netlink_recv_buf. * If we encounter NME_NL_MSG_TRUNC, we will increase the buffer diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index d7a74c7a0..4c5567998 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -1101,6 +1101,8 @@ nl_socket_new(struct nl_sock **out_sk, int protocol) if (local.nl_family != AF_NETLINK) return -NME_UNSPEC; + (void) nl_socket_set_ext_ack(sk, TRUE); + sk->s_local = local; sk->s_proto = protocol; From 9c8b957704c33a28f9c3a499f8a41f5dbde158f1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 16 Jun 2022 23:18:00 +0200 Subject: [PATCH 04/11] platform: drop _genl_sock() function and directly access data --- src/libnm-platform/nm-linux-platform.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 880244a40..7bd7b9d96 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -570,8 +570,7 @@ static void cache_on_change(NMPlatform *platform, const NMPObject *obj_old, const NMPObject *obj_new); static void cache_prune_all(NMPlatform *platform); -static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks); -static struct nl_sock *_genl_sock(NMLinuxPlatform *platform); +static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks); /*****************************************************************************/ @@ -3222,13 +3221,13 @@ _new_from_nl_link(NMPlatform *platform, case NM_LINK_TYPE_OLPC_MESH: obj->_link.ext_data = (GObject *) nm_wifi_utils_new(ifi->ifi_index, - _genl_sock(NM_LINUX_PLATFORM(platform)), + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl, TRUE); break; case NM_LINK_TYPE_WPAN: obj->_link.ext_data = (GObject *) nm_wpan_utils_new(ifi->ifi_index, - _genl_sock(NM_LINUX_PLATFORM(platform)), + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl, TRUE); break; default: @@ -5204,14 +5203,6 @@ nla_put_failure: /*****************************************************************************/ -static struct nl_sock * -_genl_sock(NMLinuxPlatform *platform) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - - return priv->genl; -} - #define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \ G_STMT_START \ { \ From aa2fd36db47abb2dc66ae3927790df6c32aff26e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 08:24:09 +0200 Subject: [PATCH 05/11] platform: require generic netlink socket Sockets are really a fundamental thing we require to operate. We cannot meaningfully operate, if we fail to create them. That is also why a too low file descriptor limit is fatal and unsupported. This is similar with out of memory situations. Just require that we always are able to create the generic netlink socket. --- src/libnm-platform/nm-linux-platform.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 7bd7b9d96..48b64169d 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9713,8 +9713,7 @@ constructed(GObject *_object) nm_platform_get_cache_tc(platform) ? "use" : "no"); nle = nl_socket_new(&priv->genl, NETLINK_GENERIC); - if (nle) - _LOGE("unable to connect the generic netlink socket \"%s\" (%d)", nm_strerror(nle), -nle); + g_assert(!nle); nle = nl_socket_new(&priv->nlh, NETLINK_ROUTE); g_assert(!nle); From c7fea44e47caf72b39c342f799b57b63916e4f62 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 08:33:28 +0200 Subject: [PATCH 06/11] platform/trivial: rename netlink sockets in NMLinuxPlatform - "priv->nlh" to "priv->sk_rtnl": as we also have an genl socket, "nlh" is not a good name. The point is that this is rtnetlink. Also, "h" sounds like a handle, that is, a file descriptor. Make this clearer with a "sk_" prefix. - "priv->genl" to "priv->sk_genl_sync": This socket is only used for synchronous operations, that is, it is passed to various independent components, that use it to send a request and wait for the response (while consuming all messages). We will have a use for a second socket, hence the "_sync" part. The "sk_" prefix is for consistency with "sk_rtnl". - "priv->event_source" to "priv->rtnl_event_source". Just make it clearer, that this is for the rtnetlink socket. In any case, this field is hardly used at all, it can have a sturdy name. --- src/libnm-platform/nm-linux-platform.c | 62 +++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 48b64169d..96ab0c368 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -415,11 +415,11 @@ typedef struct { /*****************************************************************************/ typedef struct { - struct nl_sock *genl; + struct nl_sock *sk_genl_sync; - struct nl_sock *nlh; + struct nl_sock *sk_rtnl; - GSource *event_source; + GSource *rtnl_event_source; guint32 nlh_seq_next; #if NM_MORE_LOGGING @@ -2542,7 +2542,7 @@ _wireguard_get_family_id(NMPlatform *platform, int ifindex_try) wireguard_family_id = NMP_OBJECT_UP_CAST(plink)->_link.wireguard_family_id; } if (wireguard_family_id < 0) - wireguard_family_id = genl_ctrl_resolve(priv->genl, "wireguard"); + wireguard_family_id = genl_ctrl_resolve(priv->sk_genl_sync, "wireguard"); return wireguard_family_id; } @@ -2572,7 +2572,7 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) lnk_new = nmp_object_ref(plink->_link.netlink.lnk); } else { - lnk_new = _wireguard_read_info(platform, priv->genl, wireguard_family_id, ifindex); + lnk_new = _wireguard_read_info(platform, priv->sk_genl_sync, wireguard_family_id, ifindex); if (!lnk_new) { if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) lnk_new = nmp_object_ref(plink->_link.netlink.lnk); @@ -2881,14 +2881,14 @@ link_wireguard_change(NMPlatform *platform, } for (i = 0; i < msgs->len; i++) { - r = nl_send_auto(priv->genl, msgs->pdata[i]); + r = nl_send_auto(priv->sk_genl_sync, msgs->pdata[i]); if (r < 0) { _LOGW("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror(r)); return r; } do { - r = nl_recvmsgs(priv->genl, NULL); + r = nl_recvmsgs(priv->sk_genl_sync, NULL); } while (r == -EAGAIN); if (r < 0) { _LOGW("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror(r)); @@ -3221,13 +3221,13 @@ _new_from_nl_link(NMPlatform *platform, case NM_LINK_TYPE_OLPC_MESH: obj->_link.ext_data = (GObject *) nm_wifi_utils_new(ifi->ifi_index, - NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl, + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, TRUE); break; case NM_LINK_TYPE_WPAN: obj->_link.ext_data = (GObject *) nm_wpan_utils_new(ifi->ifi_index, - NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl, + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, TRUE); break; default: @@ -3237,7 +3237,7 @@ _new_from_nl_link(NMPlatform *platform, if (obj->link.type == NM_LINK_TYPE_WIREGUARD) { const NMPObject *lnk_data_new = NULL; - struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl; + struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync; /* The WireGuard kernel module does not yet send link update * notifications, so we don't actually update the cache. For @@ -6680,12 +6680,12 @@ _nl_send_nlmsghdr(NMPlatform *platform, int try_count; if (!nlhdr->nlmsg_pid) - nlhdr->nlmsg_pid = nl_socket_get_local_port(priv->nlh); + nlhdr->nlmsg_pid = nl_socket_get_local_port(priv->sk_rtnl); nlhdr->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK); try_count = 0; again: - errsv = sendmsg(nl_socket_get_fd(priv->nlh), &msg, 0); + errsv = sendmsg(nl_socket_get_fd(priv->sk_rtnl), &msg, 0); if (errsv < 0) { errsv = errno; if (errsv == EINTR && try_count++ < 100) @@ -6733,7 +6733,7 @@ _nl_send_nlmsg(NMPlatform *platform, seq = _nlh_seq_next_get(priv); nlhdr->nlmsg_seq = seq; - nle = nl_send_auto(priv->nlh, nlmsg); + nle = nl_send_auto(priv->sk_rtnl, nlmsg); if (nle < 0) { _LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle); return nle; @@ -9190,7 +9190,7 @@ tfilter_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_e /*****************************************************************************/ static gboolean -event_handler(int fd, GIOCondition io_condition, gpointer user_data) +rtnl_event_handler(int fd, GIOCondition io_condition, gpointer user_data) { delayed_action_handle_all(NM_PLATFORM(user_data), TRUE); return TRUE; @@ -9203,7 +9203,7 @@ static int event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - struct nl_sock *sk = priv->nlh; + struct nl_sock *sk = priv->sk_rtnl; int n; int err = 0; gboolean multipart = 0; @@ -9512,7 +9512,7 @@ after_read: timeout_msec); memset(&pfd, 0, sizeof(pfd)); - pfd.fd = nl_socket_get_fd(priv->nlh); + pfd.fd = nl_socket_get_fd(priv->sk_rtnl); pfd.events = POLLIN; r = poll(&pfd, 1, timeout_msec); @@ -9712,30 +9712,30 @@ constructed(GObject *_object) nm_platform_get_use_udev(platform) ? "use" : "no", nm_platform_get_cache_tc(platform) ? "use" : "no"); - nle = nl_socket_new(&priv->genl, NETLINK_GENERIC); + nle = nl_socket_new(&priv->sk_genl_sync, NETLINK_GENERIC); g_assert(!nle); - nle = nl_socket_new(&priv->nlh, NETLINK_ROUTE); + nle = nl_socket_new(&priv->sk_rtnl, NETLINK_ROUTE); g_assert(!nle); - nle = nl_socket_set_passcred(priv->nlh, 1); + nle = nl_socket_set_passcred(priv->sk_rtnl, 1); g_assert(!nle); /* No blocking for event socket, so that we can drain it safely. */ - nle = nl_socket_set_nonblocking(priv->nlh); + nle = nl_socket_set_nonblocking(priv->sk_rtnl); g_assert(!nle); /* use 8 MB for receive socket kernel queue. */ - nle = nl_socket_set_buffer_size(priv->nlh, 8 * 1024 * 1024, 0); + nle = nl_socket_set_buffer_size(priv->sk_rtnl, 8 * 1024 * 1024, 0); g_assert(!nle); /* explicitly set the msg buffer size and disable MSG_PEEK. * We use our own receive buffer priv->netlink_recv_buf. * If we encounter NME_NL_MSG_TRUNC, we will increase the buffer * and resync (as we would have lost the message without NL_MSG_PEEK). */ - nl_socket_disable_msg_peek(priv->nlh); + nl_socket_disable_msg_peek(priv->sk_rtnl); - nle = nl_socket_add_memberships(priv->nlh, + nle = nl_socket_add_memberships(priv->sk_rtnl, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV4_RULE, @@ -9747,20 +9747,20 @@ constructed(GObject *_object) g_assert(!nle); if (nm_platform_get_cache_tc(platform)) { - nle = nl_socket_add_memberships(priv->nlh, RTNLGRP_TC, 0); + nle = nl_socket_add_memberships(priv->sk_rtnl, RTNLGRP_TC, 0); nm_assert(!nle); } - fd = nl_socket_get_fd(priv->nlh); + fd = nl_socket_get_fd(priv->sk_rtnl); _LOGD("Netlink socket for events established: port=%u, fd=%d", - nl_socket_get_local_port(priv->nlh), + nl_socket_get_local_port(priv->sk_rtnl), fd); - priv->event_source = + priv->rtnl_event_source = nm_g_unix_fd_add_source(fd, G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, - event_handler, + rtnl_event_handler, platform); /* complete construction of the GObject instance before populating the cache. */ @@ -9877,11 +9877,11 @@ finalize(GObject *object) g_ptr_array_unref(priv->delayed_action.list_refresh_link); g_array_unref(priv->delayed_action.list_wait_for_nl_response); - nl_socket_free(priv->genl); + nl_socket_free(priv->sk_genl_sync); - nm_clear_g_source_inst(&priv->event_source); + nm_clear_g_source_inst(&priv->rtnl_event_source); - nl_socket_free(priv->nlh); + nl_socket_free(priv->sk_rtnl); { NM_G_MUTEX_LOCKED(&sysctl_clear_cache_lock); From 2d211cfd5c808cc9da85ea757e6702926ae965b0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 08:44:35 +0200 Subject: [PATCH 07/11] platform: log information about (sync) genetlink socket --- src/libnm-platform/nm-linux-platform.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 96ab0c368..18ccb4669 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9712,20 +9712,26 @@ constructed(GObject *_object) nm_platform_get_use_udev(platform) ? "use" : "no", nm_platform_get_cache_tc(platform) ? "use" : "no"); + /*************************************************************************/ + nle = nl_socket_new(&priv->sk_genl_sync, NETLINK_GENERIC); g_assert(!nle); + _LOGD("genl: generic netlink socket for sync operations created: port=%u, fd=%d", + nl_socket_get_local_port(priv->sk_genl_sync), + nl_socket_get_fd(priv->sk_genl_sync)); + + /*************************************************************************/ + nle = nl_socket_new(&priv->sk_rtnl, NETLINK_ROUTE); g_assert(!nle); nle = nl_socket_set_passcred(priv->sk_rtnl, 1); g_assert(!nle); - /* No blocking for event socket, so that we can drain it safely. */ nle = nl_socket_set_nonblocking(priv->sk_rtnl); g_assert(!nle); - /* use 8 MB for receive socket kernel queue. */ nle = nl_socket_set_buffer_size(priv->sk_rtnl, 8 * 1024 * 1024, 0); g_assert(!nle); @@ -9753,7 +9759,7 @@ constructed(GObject *_object) fd = nl_socket_get_fd(priv->sk_rtnl); - _LOGD("Netlink socket for events established: port=%u, fd=%d", + _LOGD("rtnl: rtnetlink socket created: port=%u, fd=%d", nl_socket_get_local_port(priv->sk_rtnl), fd); @@ -9763,6 +9769,8 @@ constructed(GObject *_object) rtnl_event_handler, platform); + /*************************************************************************/ + /* complete construction of the GObject instance before populating the cache. */ G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object); From 3ab66fd341c77d54c87d637fadb809e28663b946 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 09:40:16 +0200 Subject: [PATCH 08/11] platform: move nl_recv() to separate function Will be reused later. --- src/libnm-platform/nm-linux-platform.c | 76 ++++++++++++++++---------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 18ccb4669..767e957cf 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9189,6 +9189,49 @@ tfilter_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_e /*****************************************************************************/ +static int +_netlink_recv(NMPlatform *platform, + struct nl_sock *sk, + struct sockaddr_nl *nla, + struct ucred *out_creds, + gboolean *out_creds_has) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + unsigned char *buf = NULL; + int n; + + nm_assert(nla); + nm_assert(out_creds); + nm_assert(out_creds_has); + + /* We use a pre-allocated receive buffer. */ + + n = nl_recv(sk, + priv->netlink_recv_buf.buf, + priv->netlink_recv_buf.len, + nla, + &buf, + out_creds, + out_creds_has); + + nm_assert((n <= 0 && !buf) + || (n > 0 && n <= priv->netlink_recv_buf.len && buf == priv->netlink_recv_buf.buf)); + + if (n == -NME_NL_MSG_TRUNC) { + /* the message receive buffer was too small. We lost one message, which + * is unfortunate. Try to double the buffer size for the next time. */ + priv->netlink_recv_buf.len *= 2; + priv->netlink_recv_buf.buf = + g_realloc(priv->netlink_recv_buf.buf, priv->netlink_recv_buf.len); + _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %zu bytes", + priv->netlink_recv_buf.len); + } + + return n; +} + +/*****************************************************************************/ + static gboolean rtnl_event_handler(int fd, GIOCondition io_condition, gpointer user_data) { @@ -9203,7 +9246,6 @@ static int event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - struct nl_sock *sk = priv->sk_rtnl; int n; int err = 0; gboolean multipart = 0; @@ -9213,39 +9255,17 @@ event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) struct sockaddr_nl nla; struct ucred creds; gboolean creds_has; - unsigned char *buf; continue_reading: - buf = NULL; - - n = nl_recv(sk, - priv->netlink_recv_buf.buf, - priv->netlink_recv_buf.len, - &nla, - &buf, - &creds, - &creds_has); - - nm_assert((n <= 0 && !buf) - || (n > 0 && n <= priv->netlink_recv_buf.len && buf == priv->netlink_recv_buf.buf)); - - if (n <= 0) { - if (n == -NME_NL_MSG_TRUNC) { - /* the message receive buffer was too small. We lost one message, which - * is unfortunate. Try to double the buffer size for the next time. */ - priv->netlink_recv_buf.len *= 2; - priv->netlink_recv_buf.buf = - g_realloc(priv->netlink_recv_buf.buf, priv->netlink_recv_buf.len); - _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %zu bytes", - priv->netlink_recv_buf.len); - if (!handle_events) - goto continue_reading; - } + n = _netlink_recv(platform, priv->sk_rtnl, &nla, &creds, &creds_has); + if (n < 0) { + if (n == -NME_NL_MSG_TRUNC && !handle_events) + goto continue_reading; return n; } - hdr = (struct nlmsghdr *) buf; + hdr = (struct nlmsghdr *) priv->netlink_recv_buf.buf; while (nlmsg_ok(hdr, n)) { nm_auto_nlmsg struct nl_msg *msg = NULL; gboolean abort_parsing = FALSE; From f5d94284688f9e739658b73809335f3057360db0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 10:26:47 +0200 Subject: [PATCH 09/11] platform/netlink: add netlink_protocol argument to nl_nlmsghdr_to_str() The meaning of the header depends on the netlink protocol. Add that parameter, so we can also handle genl. --- src/libnm-platform/nm-linux-platform.c | 6 +- src/libnm-platform/nm-netlink.c | 194 +++++++++++++------------ src/libnm-platform/nm-netlink.h | 3 +- 3 files changed, 105 insertions(+), 98 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 767e957cf..15c5c6db7 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -7053,7 +7053,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events obj = nmp_object_new_from_nl(platform, cache, msg, is_del, &parse_nlmsg_iter); if (!obj) { _LOGT("event-notification: %s: ignore", - nl_nlmsghdr_to_str(msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + nl_nlmsghdr_to_str(NETLINK_ROUTE, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); return; } @@ -7071,7 +7071,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events } _LOGT("event-notification: %s%s: %s", - nl_nlmsghdr_to_str(msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)), + nl_nlmsghdr_to_str(NETLINK_ROUTE, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)), is_dump ? ", in-dump" : "", nmp_object_to_string(obj, is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, @@ -9289,7 +9289,7 @@ continue_reading: } _LOGt("netlink: recvmsg: new message %s", - nl_nlmsghdr_to_str(hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + nl_nlmsghdr_to_str(NETLINK_ROUTE, hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); nlmsg_set_creds(msg, &creds); diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 4c5567998..05790cb05 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -84,10 +84,10 @@ NM_UTILS_FLAGS2STR_DEFINE(nl_nlmsg_flags2str, /*****************************************************************************/ const char * -nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) +nl_nlmsghdr_to_str(int netlink_protocol, const struct nlmsghdr *hdr, char *buf, gsize len) { const char *b; - const char *s; + const char *s = NULL; guint flags, flags_before; const char *prefix; @@ -96,78 +96,81 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; - switch (hdr->nlmsg_type) { - case RTM_GETLINK: - s = "RTM_GETLINK"; + switch (netlink_protocol) { + case NETLINK_ROUTE: + 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; + } 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; + case NETLINK_GENERIC: break; } @@ -208,27 +211,30 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) 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; + switch (netlink_protocol) { + case NETLINK_ROUTE: + 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 diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index 441a12333..11dd55976 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -49,7 +49,8 @@ const char *nl_nlmsgtype2str(int type, char *buf, size_t size); const char *nl_nlmsg_flags2str(int flags, char *buf, size_t len); -const char *nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len); +const char * +nl_nlmsghdr_to_str(int netlink_protocol, const struct nlmsghdr *hdr, char *buf, gsize len); /*****************************************************************************/ From ddbcd668ec6f8136a54ecfe1d91ac1e900a5d672 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 10:36:54 +0200 Subject: [PATCH 10/11] platform: move credential check in event_handler_recvmsgs() --- src/libnm-platform/nm-linux-platform.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 15c5c6db7..f64bb506a 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9265,6 +9265,15 @@ continue_reading: return n; } + if (!creds_has || creds.pid) { + if (!creds_has) + _LOGT("netlink: recvmsg: received message without credentials"); + else + _LOGT("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); + err = 0; + goto stop; + } + hdr = (struct nlmsghdr *) priv->netlink_recv_buf.buf; while (nlmsg_ok(hdr, n)) { nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -9278,21 +9287,11 @@ continue_reading: nlmsg_set_proto(msg, NETLINK_ROUTE); nlmsg_set_src(msg, &nla); - - if (!creds_has || creds.pid) { - if (!creds_has) - _LOGT("netlink: recvmsg: received message without credentials"); - else - _LOGT("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); - err = 0; - goto stop; - } + nlmsg_set_creds(msg, &creds); _LOGt("netlink: recvmsg: new message %s", nl_nlmsghdr_to_str(NETLINK_ROUTE, hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); - nlmsg_set_creds(msg, &creds); - if (hdr->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; From 2f8d8bba8f45d01de40beb7fc598146c6457140e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 17 Jun 2022 10:40:37 +0200 Subject: [PATCH 11/11] platform: extend netlink processing of messages for different protocols Later, the same loop should also handle genl. --- src/libnm-platform/nm-linux-platform.c | 198 +++++++++++++------------ 1 file changed, 106 insertions(+), 92 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index f64bb506a..b997ca2e0 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9241,11 +9241,11 @@ rtnl_event_handler(int fd, GIOCondition io_condition, gpointer user_data) /*****************************************************************************/ -/* copied from libnl3's recvmsgs() */ static int -event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) +_netlink_recv_handle(NMPlatform *platform, int netlink_protocol, gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + struct nl_sock *sk; int n; int err = 0; gboolean multipart = 0; @@ -9255,10 +9255,15 @@ event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) struct sockaddr_nl nla; struct ucred creds; gboolean creds_has; + const char *log_prefix; + + nm_assert(netlink_protocol == NETLINK_ROUTE); + sk = priv->sk_rtnl; + log_prefix = "rtnl"; continue_reading: - n = _netlink_recv(platform, priv->sk_rtnl, &nla, &creds, &creds_has); + n = _netlink_recv(platform, sk, &nla, &creds, &creds_has); if (n < 0) { if (n == -NME_NL_MSG_TRUNC && !handle_events) goto continue_reading; @@ -9267,9 +9272,9 @@ continue_reading: if (!creds_has || creds.pid) { if (!creds_has) - _LOGT("netlink: recvmsg: received message without credentials"); + _LOGT("%s: recvmsg: received message without credentials", log_prefix); else - _LOGT("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); + _LOGT("%s: recvmsg: received non-kernel message (pid %d)", log_prefix, creds.pid); err = 0; goto stop; } @@ -9284,13 +9289,13 @@ continue_reading: const char *extack_msg = NULL; msg = nlmsg_alloc_convert(hdr); - - nlmsg_set_proto(msg, NETLINK_ROUTE); + nlmsg_set_proto(msg, netlink_protocol); nlmsg_set_src(msg, &nla); nlmsg_set_creds(msg, &creds); - _LOGt("netlink: recvmsg: new message %s", - nl_nlmsghdr_to_str(NETLINK_ROUTE, hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + _LOGt("%s: recvmsg: new message %s", + log_prefix, + nl_nlmsghdr_to_str(netlink_protocol, hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); if (hdr->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; @@ -9309,95 +9314,104 @@ continue_reading: /* FIXME: implement */ } - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; + switch (netlink_protocol) { + case NETLINK_ROUTE: + { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; - if (hdr->nlmsg_type == NLMSG_DONE) { - /* 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. */ - multipart = FALSE; - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; - } else if (hdr->nlmsg_type == NLMSG_NOOP) { - /* 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_OVERRUN) { - /* 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) */ - err = -NME_NL_MSG_OVERFLOW; - abort_parsing = TRUE; - } else if (hdr->nlmsg_type == NLMSG_ERROR) { - /* Message carries a nlmsgerr */ - 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) */ - err = -NME_NL_MSG_TRUNC; - abort_parsing = TRUE; - } else if (e->error) { - int errsv = nm_errno_native(e->error); - - if (NM_FLAGS_HAS(hdr->nlmsg_flags, NLM_F_ACK_TLVS) - && hdr->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[] = { - [NLMSGERR_ATTR_MSG] = {.type = NLA_STRING}, - [NLMSGERR_ATTR_OFFS] = {.type = NLA_U32}, - }; - struct nlattr *tb[G_N_ELEMENTS(policy)]; - struct nlattr *tlvs; - - tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len - - NLMSG_HDRLEN); - if (nla_parse_arr(tb, - tlvs, - hdr->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, - policy) - >= 0) { - if (tb[NLMSGERR_ATTR_MSG]) - extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]); - } - } - - /* Error message reported back from kernel. */ - _LOGD("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", - nm_strerror_native(errsv), - errsv, - NM_PRINT_FMT_QUOTED(extack_msg, " \"", extack_msg, "\"", ""), - nlmsg_hdr(msg)->nlmsg_seq); - seq_result = -NM_ERRNO_NATIVE(errsv); - } else + if (hdr->nlmsg_type == NLMSG_DONE) { + /* 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. */ + multipart = FALSE; seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; - } else - process_valid_msg = TRUE; + } else if (hdr->nlmsg_type == NLMSG_NOOP) { + /* 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_OVERRUN) { + /* 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) */ + err = -NME_NL_MSG_OVERFLOW; + abort_parsing = TRUE; + } else if (hdr->nlmsg_type == NLMSG_ERROR) { + /* Message carries a nlmsgerr */ + struct nlmsgerr *e = nlmsg_data(hdr); - seq_number = nlmsg_hdr(msg)->nlmsg_seq; + 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) */ + err = -NME_NL_MSG_TRUNC; + abort_parsing = TRUE; + } else if (e->error) { + int errsv = nm_errno_native(e->error); - /* check whether the seq number is different from before, and - * whether the previous number (@nlh_seq_last_seen) is a pending - * refresh-all request. In that case, the pending request is thereby - * completed. - * - * We must do that before processing the message with event_valid_msg(), - * because we must track the completion of the pending request before that. */ - event_seq_check_refresh_all(platform, seq_number); + if (NM_FLAGS_HAS(hdr->nlmsg_flags, NLM_F_ACK_TLVS) + && hdr->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) { + static const struct nla_policy policy[] = { + [NLMSGERR_ATTR_MSG] = {.type = NLA_STRING}, + [NLMSGERR_ATTR_OFFS] = {.type = NLA_U32}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + struct nlattr *tlvs; - if (process_valid_msg) { - /* Valid message (not checking for MULTIPART bit to - * get along with broken kernels. NL_SKIP has no - * effect on this. */ + tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len + - NLMSG_HDRLEN); + if (nla_parse_arr(tb, + tlvs, + hdr->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, + policy) + >= 0) { + if (tb[NLMSGERR_ATTR_MSG]) + extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]); + } + } - event_valid_msg(platform, msg, handle_events); + /* Error message reported back from kernel. */ + _LOGD( + "netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", + nm_strerror_native(errsv), + errsv, + NM_PRINT_FMT_QUOTED(extack_msg, " \"", extack_msg, "\"", ""), + nlmsg_hdr(msg)->nlmsg_seq); + seq_result = -NM_ERRNO_NATIVE(errsv); + } else + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + } else + process_valid_msg = TRUE; - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + seq_number = nlmsg_hdr(msg)->nlmsg_seq; + + /* check whether the seq number is different from before, and + * whether the previous number (@nlh_seq_last_seen) is a pending + * refresh-all request. In that case, the pending request is thereby + * completed. + * + * We must do that before processing the message with event_valid_msg(), + * because we must track the completion of the pending request before that. */ + event_seq_check_refresh_all(platform, seq_number); + + if (process_valid_msg) { + /* Valid message (not checking for MULTIPART bit to + * get along with broken kernels. NL_SKIP has no + * effect on this. */ + + event_valid_msg(platform, msg, handle_events); + + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + } + + event_seq_check(platform, seq_number, seq_result, extack_msg); + break; + } + default: + nm_assert_not_reached(); } - - event_seq_check(platform, seq_number, seq_result, extack_msg); if (abort_parsing) goto stop; @@ -9450,7 +9464,7 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) for (;;) { int nle; - nle = event_handler_recvmsgs(platform, TRUE); + nle = _netlink_recv_handle(platform, NETLINK_ROUTE, TRUE); if (nle < 0) { switch (nle) { @@ -9475,7 +9489,7 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) } _reason; })); - event_handler_recvmsgs(platform, FALSE); + _netlink_recv_handle(platform, NETLINK_ROUTE, FALSE); delayed_action_wait_for_nl_response_complete_all( platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);