diff options
author | Thomas Haller <thaller@redhat.com> | 2022-06-24 11:09:09 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-06-24 11:09:09 +0200 |
commit | eb90ebc5307e6feb81703d81858164b899637215 (patch) | |
tree | a54f12a525d29d1209d7a5fd33e22d711405f4cd | |
parent | 6b0f67b7368d361cee2cfbfe3866264714556a5b (diff) | |
parent | f8e061d7d675bdf0c973aa3e78a77eab3b39a19f (diff) | |
download | NetworkManager-eb90ebc5307e6feb81703d81858164b899637215.tar.gz |
platform: merge branch 'th/platform-genl-2'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1270
-rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 265 | ||||
-rw-r--r-- | src/libnm-platform/nm-netlink.c | 370 | ||||
-rw-r--r-- | src/libnm-platform/nm-netlink.h | 93 | ||||
-rw-r--r-- | src/libnm-platform/tests/test-nm-platform.c | 2 |
4 files changed, 389 insertions, 341 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index b997ca2e0a..a3d3b50c6e 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -2924,10 +2924,10 @@ _nmp_link_address_set(NMPLinkAddress *dst, const struct nlattr *nla) /* Copied and heavily modified from libnl3's link_msg_parser(). */ static NMPObject * -_new_from_nl_link(NMPlatform *platform, - const NMPCache *cache, - struct nlmsghdr *nlh, - gboolean id_only) +_new_from_nl_link(NMPlatform *platform, + const NMPCache *cache, + const struct nlmsghdr *nlh, + gboolean id_only) { static const struct nla_policy policy[] = { [IFLA_IFNAME] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, @@ -3275,7 +3275,7 @@ _new_from_nl_link(NMPlatform *platform, /* Copied and heavily modified from libnl3's addr_msg_parser(). */ static NMPObject * -_new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_addr(const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [IFA_LABEL] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, @@ -3390,7 +3390,7 @@ _new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only) /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */ static NMPObject * -_new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse_nlmsg_iter) +_new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse_nlmsg_iter) { static const struct nla_policy policy[] = { [RTA_TABLE] = {.type = NLA_U32}, @@ -3698,7 +3698,7 @@ rta_multipath_done: } static NMPObject * -_new_from_nl_routing_rule(struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_routing_rule(const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [FRA_UNSPEC] = {}, @@ -3974,7 +3974,7 @@ psched_tick_to_time(NMPlatform *platform, guint32 tick) } static NMPObject * -_new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_qdisc(NMPlatform *platform, const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [TCA_KIND] = {.type = NLA_STRING}, @@ -4087,7 +4087,7 @@ _new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) } static NMPObject * -_new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_tfilter(NMPlatform *platform, const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [TCA_KIND] = {.type = NLA_STRING}, @@ -4132,18 +4132,17 @@ _new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_onl * Returns: %NULL or a newly created NMPObject instance. **/ static NMPObject * -nmp_object_new_from_nl(NMPlatform *platform, - const NMPCache *cache, - struct nl_msg *msg, - gboolean id_only, - ParseNlmsgIter *parse_nlmsg_iter) +nmp_object_new_from_nl(NMPlatform *platform, + const NMPCache *cache, + const struct nl_msg_lite *msg, + gboolean id_only, + ParseNlmsgIter *parse_nlmsg_iter) { - struct nlmsghdr *msghdr; + const struct nlmsghdr *msghdr; - if (nlmsg_get_proto(msg) != NETLINK_ROUTE) - return NULL; + nm_assert(msg->nm_protocol == NETLINK_ROUTE); - msghdr = nlmsg_hdr(msg); + msghdr = msg->nm_nlh; switch (msghdr->nlmsg_type) { case RTM_NEWLINK: @@ -7016,13 +7015,13 @@ event_seq_check(NMPlatform *platform, } static void -event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events) +_rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg, gboolean handle_events) { char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; NMLinuxPlatformPrivate *priv; nm_auto_nmpobj NMPObject *obj = NULL; NMPCacheOpsType cache_op; - struct nlmsghdr *msghdr; + const struct nlmsghdr *msghdr; char buf_nlmsghdr[400]; gboolean is_del = FALSE; gboolean is_dump = FALSE; @@ -7032,7 +7031,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events if (!handle_events) return; - msghdr = nlmsg_hdr(msg); + msghdr = msg->nm_nlh; if (NM_IN_SET(msghdr->nlmsg_type, RTM_DELLINK, @@ -7053,7 +7052,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(NETLINK_ROUTE, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + nl_nlmsghdr_to_str(NETLINK_ROUTE, 0, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); return; } @@ -7071,7 +7070,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events } _LOGT("event-notification: %s%s: %s", - nl_nlmsghdr_to_str(NETLINK_ROUTE, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)), + nl_nlmsghdr_to_str(NETLINK_ROUTE, 0, 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, @@ -7123,7 +7122,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET && data->response.out_route_get) { nm_assert(!*data->response.out_route_get); - if (data->seq_number == nlmsg_hdr(msg)->nlmsg_seq) { + if (data->seq_number == msg->nm_nlh->nlmsg_seq) { *data->response.out_route_get = nmp_object_clone(obj, FALSE); data->response.out_route_get = NULL; break; @@ -9212,7 +9211,9 @@ _netlink_recv(NMPlatform *platform, nla, &buf, out_creds, - out_creds_has); + out_creds_has, + NULL, + NULL); nm_assert((n <= 0 && !buf) || (n > 0 && n <= priv->netlink_recv_buf.len && buf == priv->netlink_recv_buf.buf)); @@ -9247,11 +9248,10 @@ _netlink_recv_handle(NMPlatform *platform, int netlink_protocol, gboolean handle NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); struct nl_sock *sk; int n; - int err = 0; + int retval = 0; gboolean multipart = 0; gboolean interrupted = FALSE; struct nlmsghdr *hdr; - WaitForNlResponseResult seq_result; struct sockaddr_nl nla; struct ucred creds; gboolean creds_has; @@ -9275,32 +9275,38 @@ continue_reading: _LOGT("%s: recvmsg: received message without credentials", log_prefix); else _LOGT("%s: recvmsg: received non-kernel message (pid %d)", log_prefix, 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; - gboolean abort_parsing = FALSE; - gboolean process_valid_msg = FALSE; - guint32 seq_number; - char buf_nlmsghdr[400]; - const char *extack_msg = NULL; - - msg = nlmsg_alloc_convert(hdr); - nlmsg_set_proto(msg, netlink_protocol); - nlmsg_set_src(msg, &nla); - nlmsg_set_creds(msg, &creds); + WaitForNlResponseResult seq_result; + gboolean process_valid_msg = FALSE; + char buf_nlmsghdr[400]; + const char *extack_msg = NULL; + const struct nl_msg_lite msg = { + .nm_protocol = netlink_protocol, + .nm_src = &nla, + .nm_creds = &creds, + .nm_size = NLMSG_ALIGN(hdr->nlmsg_len), + .nm_nlh = hdr, + }; + const guint32 seq_number = msg.nm_nlh->nlmsg_seq; + + nm_assert((((uintptr_t) (const void *) msg.nm_nlh) % NLMSG_ALIGNTO) == 0); _LOGt("%s: recvmsg: new message %s", log_prefix, - nl_nlmsghdr_to_str(netlink_protocol, hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + nl_nlmsghdr_to_str(netlink_protocol, + 0, + msg.nm_nlh, + buf_nlmsghdr, + sizeof(buf_nlmsghdr))); - if (hdr->nlmsg_flags & NLM_F_MULTI) + if (msg.nm_nlh->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; - if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { + if (msg.nm_nlh->nlmsg_flags & NLM_F_DUMP_INTR) { /* * We have to continue reading to clear * all messages until a NLMSG_DONE is @@ -9310,89 +9316,86 @@ continue_reading: } /* Other side wishes to see an ack for this message */ - if (hdr->nlmsg_flags & NLM_F_ACK) { + if (msg.nm_nlh->nlmsg_flags & NLM_F_ACK) { /* FIXME: implement */ } - 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]); - } + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; + + if (msg.nm_nlh->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 (msg.nm_nlh->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 (msg.nm_nlh->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) */ + retval = -NME_NL_MSG_OVERFLOW; + } else if (msg.nm_nlh->nlmsg_type == NLMSG_ERROR) { + /* Message carries a nlmsgerr */ + struct nlmsgerr *e = nlmsg_data(msg.nm_nlh); + + if (msg.nm_nlh->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) */ + retval = -NME_NL_MSG_TRUNC; + } else if (e->error) { + int errsv = nm_errno_native(e->error); + + if (NM_FLAGS_HAS(msg.nm_nlh->nlmsg_flags, NLM_F_ACK_TLVS) + && msg.nm_nlh->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, + msg.nm_nlh->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 - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + /* 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, "\"", ""), + msg.nm_nlh->nlmsg_seq); + seq_result = -NM_ERRNO_NATIVE(errsv); } else - process_valid_msg = TRUE; - - seq_number = nlmsg_hdr(msg)->nlmsg_seq; + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + } else + process_valid_msg = TRUE; + switch (netlink_protocol) { + default: + nm_assert_not_reached(); + /* fall-through */ + case NETLINK_ROUTE: /* 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(), + * We must do that before processing the message with _rtnl_handle_msg(), * because we must track the completion of the pending request before that. */ event_seq_check_refresh_all(platform, seq_number); @@ -9401,7 +9404,7 @@ continue_reading: * get along with broken kernels. NL_SKIP has no * effect on this. */ - event_valid_msg(platform, msg, handle_events); + _rtnl_handle_msg(platform, &msg, handle_events); seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } @@ -9409,14 +9412,10 @@ continue_reading: event_seq_check(platform, seq_number, seq_result, extack_msg); break; } - default: - nm_assert_not_reached(); - } - if (abort_parsing) + if (retval != 0) goto stop; - err = 0; hdr = nlmsg_next(hdr, &n); } @@ -9424,6 +9423,7 @@ continue_reading: /* Multipart message not yet complete, continue reading */ goto continue_reading; } + stop: if (!handle_events) { /* when we don't handle events, we want to drain all messages from the socket @@ -9434,7 +9434,7 @@ stop: if (interrupted) return -NME_NL_DUMP_INTR; - return err; + return retval; } /*****************************************************************************/ @@ -9747,7 +9747,7 @@ constructed(GObject *_object) /*************************************************************************/ - nle = nl_socket_new(&priv->sk_genl_sync, NETLINK_GENERIC); + nle = nl_socket_new(&priv->sk_genl_sync, NETLINK_GENERIC, NL_SOCKET_FLAGS_NONE, 0, 0); g_assert(!nle); _LOGD("genl: generic netlink socket for sync operations created: port=%u, fd=%d", @@ -9756,24 +9756,15 @@ constructed(GObject *_object) /*************************************************************************/ - nle = nl_socket_new(&priv->sk_rtnl, NETLINK_ROUTE); + /* disable MSG_PEEK, we will handle lost messages ourselves. */ + nle = nl_socket_new(&priv->sk_rtnl, + NETLINK_ROUTE, + NL_SOCKET_FLAGS_NONBLOCK | NL_SOCKET_FLAGS_PASSCRED + | NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, + 8 * 1024 * 1024, + 0); g_assert(!nle); - nle = nl_socket_set_passcred(priv->sk_rtnl, 1); - g_assert(!nle); - - nle = nl_socket_set_nonblocking(priv->sk_rtnl); - g_assert(!nle); - - 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->sk_rtnl); - nle = nl_socket_add_memberships(priv->sk_rtnl, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE, diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 05790cb054..267a5bc51e 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -28,11 +28,6 @@ } \ G_STMT_END -#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 #endif @@ -50,12 +45,13 @@ struct nl_msg { struct nl_sock { struct sockaddr_nl s_local; struct sockaddr_nl s_peer; + size_t s_bufsize; int s_fd; int s_proto; unsigned int s_seq_next; unsigned int s_seq_expect; - int s_flags; - size_t s_bufsize; + bool s_msg_peek : 1; + bool s_auto_ack : 1; }; /*****************************************************************************/ @@ -81,10 +77,57 @@ NM_UTILS_FLAGS2STR_DEFINE(nl_nlmsg_flags2str, NM_UTILS_FLAGS2STR(NLM_F_CREATE, "CREATE"), NM_UTILS_FLAGS2STR(NLM_F_APPEND, "APPEND"), ); +static NM_UTILS_LOOKUP_STR_DEFINE(_rtnl_type_to_str, + guint16, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETLINK, "RTM_GETLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWLINK, "RTM_NEWLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELLINK, "RTM_DELLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_SETLINK, "RTM_SETLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETADDR, "RTM_GETADDR"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWADDR, "RTM_NEWADDR"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELADDR, "RTM_DELADDR"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETROUTE, "RTM_GETROUTE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWROUTE, "RTM_NEWROUTE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELROUTE, "RTM_DELROUTE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETRULE, "RTM_GETRULE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWRULE, "RTM_NEWRULE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELRULE, "RTM_DELRULE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETQDISC, "RTM_GETQDISC"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWQDISC, "RTM_NEWQDISC"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELQDISC, "RTM_DELQDISC"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETTFILTER, "RTM_GETTFILTER"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWTFILTER, "RTM_NEWTFILTER"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELTFILTER, "RTM_DELTFILTER"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_NOOP, "NLMSG_NOOP"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_ERROR, "NLMSG_ERROR"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_DONE, "NLMSG_DONE"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_OVERRUN, "NLMSG_OVERRUN"), ); + +static NM_UTILS_LOOKUP_STR_DEFINE( + _genl_ctrl_cmd_to_str, + guint8, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_UNSPEC, "CTRL_CMD_UNSPEC"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_NEWFAMILY, "CTRL_CMD_NEWFAMILY"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_DELFAMILY, "CTRL_CMD_DELFAMILY"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETFAMILY, "CTRL_CMD_GETFAMILY"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_NEWOPS, "CTRL_CMD_NEWOPS"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_DELOPS, "CTRL_CMD_DELOPS"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETOPS, "CTRL_CMD_GETOPS"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_NEWMCAST_GRP, "CTRL_CMD_NEWMCAST_GRP"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_DELMCAST_GRP, "CTRL_CMD_DELMCAST_GRP"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETMCAST_GRP, "CTRL_CMD_GETMCAST_GRP"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETPOLICY, "CTRL_CMD_GETPOLICY"), ); + /*****************************************************************************/ const char * -nl_nlmsghdr_to_str(int netlink_protocol, const struct nlmsghdr *hdr, char *buf, gsize len) +nl_nlmsghdr_to_str(int netlink_protocol, + guint32 pktinfo_group, + const struct nlmsghdr *hdr, + char *buf, + gsize len) { const char *b; const char *s = NULL; @@ -98,87 +141,44 @@ nl_nlmsghdr_to_str(int netlink_protocol, const struct nlmsghdr *hdr, char *buf, 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; - } + s = _rtnl_type_to_str(hdr->nlmsg_type); + if (s) + nm_strbuf_append_str(&buf, &len, s); + else + nm_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); break; + default: + nm_assert_not_reached(); + /* fall-through */ case NETLINK_GENERIC: + if (pktinfo_group == 0) + nm_strbuf_append(&buf, &len, "group:unicast"); + else + nm_strbuf_append(&buf, &len, "group:multicast(%u)", (unsigned) pktinfo_group); + + s = NULL; + if (hdr->nlmsg_type == GENL_ID_CTRL) + s = "GENL_ID_CTRL"; + if (s) + nm_strbuf_append(&buf, &len, ", msg-type:%s", s); + else + nm_strbuf_append(&buf, &len, ", msg-type:(%u)", (unsigned) hdr->nlmsg_type); + + if (genlmsg_valid_hdr(hdr, 0)) { + const struct genlmsghdr *ghdr; + + ghdr = nlmsg_data(hdr); + s = NULL; + if (hdr->nlmsg_type == GENL_ID_CTRL) + s = _genl_ctrl_cmd_to_str(ghdr->cmd); + if (s) + nm_strbuf_append(&buf, &len, ", cmd:%s", s); + else + nm_strbuf_append(&buf, &len, ", cmd:(%u)", (unsigned) ghdr->cmd); + } break; } - if (s) - nm_strbuf_append_str(&buf, &len, s); - else - nm_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); - flags = hdr->nlmsg_flags; if (!flags) { @@ -402,7 +402,7 @@ nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad) /*****************************************************************************/ int -nlmsg_parse(struct nlmsghdr *nlh, +nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, @@ -761,8 +761,8 @@ genlmsg_user_hdr(const struct genlmsghdr *gnlh) return genlmsg_data(gnlh); } -struct genlmsghdr * -genlmsg_hdr(struct nlmsghdr *nlh) +const struct genlmsghdr * +genlmsg_hdr(const struct nlmsghdr *nlh) { return nlmsg_data(nlh); } @@ -795,7 +795,7 @@ genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) } int -genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) +genlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) { struct genlmsghdr *ghdr; @@ -810,13 +810,13 @@ genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) } int -genlmsg_parse(struct nlmsghdr *nlh, +genlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { - struct genlmsghdr *ghdr; + const struct genlmsghdr *ghdr; if (!genlmsg_valid_hdr(nlh, hdrlen)) return -NME_NL_MSG_TOOSHORT; @@ -829,23 +829,24 @@ genlmsg_parse(struct nlmsghdr *nlh, policy); } +const struct nla_policy genl_ctrl_policy[CTRL_ATTR_MCAST_GROUPS + 1] = { + [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}, +}; + static int _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 nlattr *tb[G_N_ELEMENTS(genl_ctrl_policy)]; struct nlmsghdr *nlh = nlmsg_hdr(msg); gint32 *response_data = arg; - if (genlmsg_parse_arr(nlh, 0, tb, ctrl_policy) < 0) + if (genlmsg_parse_arr(nlh, 0, tb, genl_ctrl_policy) < 0) return NL_SKIP; if (tb[CTRL_ATTR_FAMILY_ID]) @@ -933,12 +934,19 @@ nl_socket_set_passcred(struct nl_sock *sk, int state) err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state)); if (err < 0) return -nm_errno_from_native(errno); + return 0; +} - if (state) - sk->s_flags |= NL_SOCK_PASSCRED; - else - sk->s_flags &= ~NL_SOCK_PASSCRED; +int +nl_socket_set_pktinfo(struct nl_sock *sk, int state) +{ + int err; + + nm_assert_sk(sk); + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO, &state, sizeof(state)); + if (err < 0) + return -nm_errno_from_native(errno); return 0; } @@ -1025,33 +1033,14 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...) return 0; } -int -nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable) -{ - int err; - int val; - - nm_assert_sk(sk); - - 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; -} - -void -nl_socket_disable_msg_peek(struct nl_sock *sk) -{ - sk->s_flags |= NL_MSG_PEEK_EXPLICIT; - sk->s_flags &= ~NL_MSG_PEEK; -} - /*****************************************************************************/ int -nl_socket_new(struct nl_sock **out_sk, int protocol) +nl_socket_new(struct nl_sock **out_sk, + int protocol, + NLSocketFlags flags, + int bufsize_rx, + int bufsize_tx) { nm_auto_nlsock struct nl_sock *sk = NULL; nm_auto_close int fd = -1; @@ -1060,10 +1049,14 @@ nl_socket_new(struct nl_sock **out_sk, int protocol) int nmerr; socklen_t addrlen; struct sockaddr_nl local = {0}; + int i_val; nm_assert(out_sk && !*out_sk); - fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); + fd = socket(AF_NETLINK, + SOCK_RAW | SOCK_CLOEXEC + | (NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_NONBLOCK) ? SOCK_NONBLOCK : 0), + protocol); if (fd < 0) return -nm_errno_from_native(errno); @@ -1086,12 +1079,30 @@ nl_socket_new(struct nl_sock **out_sk, int protocol) }, .s_seq_expect = t, .s_seq_next = t, + .s_bufsize = 0, + .s_msg_peek = !NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK), + .s_auto_ack = TRUE, }; - nmerr = nl_socket_set_buffer_size(sk, 0, 0); + nmerr = nl_socket_set_buffer_size(sk, bufsize_rx, bufsize_tx); if (nmerr < 0) return nmerr; + i_val = 1; + (void) setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &i_val, sizeof(i_val)); + + if (NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_PASSCRED)) { + err = nl_socket_set_passcred(sk, 1); + if (err < 0) + return err; + } + + if (NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_PKTINFO)) { + err = nl_socket_set_pktinfo(sk, 1); + if (err < 0) + return err; + } + err = bind(sk->s_fd, (struct sockaddr *) &sk->s_local, sizeof(sk->s_local)); if (err != 0) return -nm_errno_from_native(errno); @@ -1107,8 +1118,6 @@ 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; @@ -1182,7 +1191,7 @@ nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb) gboolean creds_has; continue_reading: - n = nl_recv(sk, NULL, 0, &nla, &buf, &creds, &creds_has); + n = nl_recv(sk, NULL, 0, &nla, &buf, &creds, &creds_has, NULL, NULL); if (n <= 0) return n; @@ -1199,7 +1208,7 @@ continue_reading: nrecv++; /* Only do sequence checking if auto-ack mode is enabled */ - if (!(sk->s_flags & NL_NO_AUTO_ACK)) { + if (sk->s_auto_ack) { if (hdr->nlmsg_seq != sk->s_seq_expect) { nmerr = -NME_NL_SEQ_MISMATCH; goto out; @@ -1384,7 +1393,7 @@ nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg) nlh->nlmsg_flags |= NLM_F_REQUEST; - if (!(sk->s_flags & NL_NO_AUTO_ACK)) + if (sk->s_auto_ack) nlh->nlmsg_flags |= NLM_F_ACK; } @@ -1419,6 +1428,10 @@ nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) * on success. * @out_creds_has: (out) (allow-none): result indicating whether * @out_creds was filled. +* @out_pktinfo_group: (out) (allow-none): optional out buffer for NETLINK_PKTINFO +* group on success. + * @out_pktinfo_has: (out) (allow-none): result indicating whether + * @out_pktinfo_group was filled. * * If @buf0_len is zero, the function will g_malloc() a new receive buffer of size * nl_socket_get_msg_buf_size(). If @buf0_len is larger than zero, then @buf0 @@ -1441,18 +1454,20 @@ nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred *out_creds, - gboolean *out_creds_has) + gboolean *out_creds_has, + uint32_t *out_pktinfo_group, + gboolean *out_pktinfo_has) { - /* We really expect msg_contol_buf to be large enough and MSG_CTRUNC not - * happening. We nm_assert() against that. However, in release builds - * we don't assert, so add some extra safety space for the unexpected - * case where we might need more than CMSG_SPACE(sizeof(struct ucred)). - * It should not hurt and should not be necessary. It's just some - * extra defensive space. */ -#define _MSG_CONTROL_BUF_EXTRA_SPACE (NM_MORE_ASSERTS ? 512u : 0u) union { - struct cmsghdr cmsghdr; - char buf[CMSG_SPACE(sizeof(struct ucred)) + _MSG_CONTROL_BUF_EXTRA_SPACE]; + struct cmsghdr _dummy_for_alignment; + struct { + char buf[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(struct nl_pktinfo))]; + + /* We really expect that "buf" is large enough end even assert against + * that. We don't expect and don't want to handle MSG_CTRUNC error. + * Still, add some extra safety. This is on the stack and essentially for free. */ + char _extra[512]; + }; } msg_contol_buf; ssize_t n; int flags = 0; @@ -1465,17 +1480,16 @@ nl_recv(struct nl_sock *sk, .msg_controllen = 0, .msg_control = NULL, }; - struct ucred tmpcreds; - gboolean tmpcreds_has = FALSE; - int retval; - int errsv; + struct cmsghdr *cmsg; + int retval; + int errsv; nm_assert(nla); nm_assert(buf && !*buf); - nm_assert(!out_creds_has == !out_creds); + nm_assert(!out_creds_has || out_creds); + nm_assert(!out_pktinfo_has || out_pktinfo_group); - if ((sk->s_flags & NL_MSG_PEEK) - || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0)) + if (sk->s_msg_peek) flags |= MSG_PEEK | MSG_TRUNC; if (buf0_len > 0) { @@ -1486,7 +1500,7 @@ nl_recv(struct nl_sock *sk, iov.iov_base = g_malloc(iov.iov_len); } - if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + if (out_creds_has || out_pktinfo_has) { msg.msg_controllen = sizeof(msg_contol_buf); msg.msg_control = msg_contol_buf.buf; } @@ -1506,11 +1520,14 @@ retry: goto abort; } + nm_assert((gsize) n <= G_MAXINT); + /* We really don't expect truncation of ancillary data. We provided a large * enough buffer, so this is likely a bug. In the worst case, we might lack * the requested credentials and the caller likely will reject the message * later. */ nm_assert(!(msg.msg_flags & MSG_CTRUNC)); + nm_assert(msg.msg_controllen <= G_STRUCT_OFFSET(typeof(msg_contol_buf), _extra)); if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) { /* respond with error to an incomplete message */ @@ -1539,32 +1556,35 @@ retry: goto abort; } - if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { - struct cmsghdr *cmsg; - + if (out_creds_has || out_pktinfo_has) { + NM_SET_OUT(out_creds_has, FALSE); + NM_SET_OUT(out_pktinfo_has, FALSE); 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; + switch (cmsg->cmsg_level) { + case SOL_SOCKET: + if (cmsg->cmsg_type == SCM_CREDENTIALS && out_creds_has) { + memcpy(out_creds, CMSG_DATA(cmsg), sizeof(*out_creds)); + *out_creds_has = TRUE; + } + break; + case SOL_NETLINK: + if (cmsg->cmsg_type == NETLINK_PKTINFO && out_pktinfo_has) { + struct nl_pktinfo p; + + memcpy(&p, CMSG_DATA(cmsg), sizeof(p)); + *out_pktinfo_group = p.group; + *out_pktinfo_has = TRUE; + } + break; + } } } - retval = n; + *buf = iov.iov_base; + return (int) n; abort: - if (retval <= 0) { - if (iov.iov_base != buf0) - 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); + if (iov.iov_base != buf0) + g_free(iov.iov_base); return retval; } diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index 11dd559766..efc9585313 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -43,14 +43,37 @@ enum { struct nl_msg; +/* This is similar to "struct nl_msg", in that it contains a + * netlink message including additional information like the + * src, creds, protocol. + * + * The difference is that "struct nl_msg" is an opaque type and + * contains a copy of the message (requiring two heap allocations). + * "struct nl_msg_lite" can be on the stack and it can directly + * point to the receive buffer, without need to copy the message. + * That can be useful, if you don't need to clone the message and + * just need to pass it "down the stack" for somebody to parse + * the message. */ +struct nl_msg_lite { + int nm_protocol; + const struct sockaddr_nl *nm_src; + const struct sockaddr_nl *nm_dst; + const struct ucred *nm_creds; + const struct nlmsghdr *nm_nlh; + size_t nm_size; +}; + /*****************************************************************************/ 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(int netlink_protocol, const struct nlmsghdr *hdr, char *buf, gsize len); +const char *nl_nlmsghdr_to_str(int netlink_protocol, + guint32 pktinfo_group, + const struct nlmsghdr *hdr, + char *buf, + gsize len); /*****************************************************************************/ @@ -465,7 +488,7 @@ nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) return nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), attrtype); } -int nlmsg_parse(struct nlmsghdr *nlh, +int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, @@ -484,12 +507,26 @@ nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, i /*****************************************************************************/ +typedef enum { + NL_SOCKET_FLAGS_NONE = 0, + NL_SOCKET_FLAGS_NONBLOCK = 0x1, + NL_SOCKET_FLAGS_PASSCRED = 0x2, + NL_SOCKET_FLAGS_PKTINFO = 0x4, + NL_SOCKET_FLAGS_DISABLE_MSG_PEEK = 0x8, + + _NL_SOCKET_FLAGS_ALL = (NL_SOCKET_FLAGS_DISABLE_MSG_PEEK << 1) - 1, +} NLSocketFlags; + #define NL_AUTO_PORT 0 #define NL_AUTO_SEQ 0 struct nl_sock; -int nl_socket_new(struct nl_sock **out_sk, int protocol); +int nl_socket_new(struct nl_sock **out_sk, + int protocol, + NLSocketFlags flags, + int bufsize_rx, + int bufsize_tx); void nl_socket_free(struct nl_sock *sk); @@ -507,9 +544,9 @@ int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf); int nl_socket_set_passcred(struct nl_sock *sk, int state); -int nl_socket_set_nonblocking(const struct nl_sock *sk); +int nl_socket_set_pktinfo(struct nl_sock *sk, int state); -void nl_socket_disable_msg_peek(struct nl_sock *sk); +int nl_socket_set_nonblocking(const struct nl_sock *sk); uint32_t nl_socket_get_local_port(const struct nl_sock *sk); @@ -523,7 +560,9 @@ int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred *out_creds, - gboolean *out_creds_has); + gboolean *out_creds_has, + uint32_t *out_pktinfo_group, + gboolean *out_pktinfo_has); int nl_send(struct nl_sock *sk, struct nl_msg *msg); @@ -568,28 +607,28 @@ int nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb); int nl_wait_for_ack(struct nl_sock *sk, const struct nl_cb *cb); -int nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable); - /*****************************************************************************/ -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); -void *genlmsg_data(const struct genlmsghdr *gnlh); -void *genlmsg_user_hdr(const struct genlmsghdr *gnlh); -struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *nlh); -void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen); -struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen); -int genlmsg_len(const struct genlmsghdr *gnlh); -int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen); -int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen); - -int genlmsg_parse(struct nlmsghdr *nlh, +extern const struct nla_policy genl_ctrl_policy[8]; + +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); +void *genlmsg_data(const struct genlmsghdr *gnlh); +void *genlmsg_user_hdr(const struct genlmsghdr *gnlh); +const struct genlmsghdr *genlmsg_hdr(const struct nlmsghdr *nlh); +void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen); +struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen); +int genlmsg_len(const struct genlmsghdr *gnlh); +int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen); +int genlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen); + +int genlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 9263a6e7d7..c351f014e1 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -70,8 +70,6 @@ test_use_symbols(void) (void (*)(void)) nl_socket_set_nonblocking, (void (*)(void)) nl_socket_set_buffer_size, (void (*)(void)) nl_socket_add_memberships, - (void (*)(void)) nl_socket_set_ext_ack, - (void (*)(void)) nl_socket_disable_msg_peek, (void (*)(void)) nl_wait_for_ack, (void (*)(void)) nl_recvmsgs, (void (*)(void)) nl_sendmsg, |