mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-01 09:08:05 +02:00
platform: merge branch 'th/platform-genl-2'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1270
This commit is contained in:
commit
eb90ebc530
4 changed files with 384 additions and 336 deletions
|
|
@ -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;
|
||||
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;
|
||||
|
||||
msg = nlmsg_alloc_convert(hdr);
|
||||
nlmsg_set_proto(msg, netlink_protocol);
|
||||
nlmsg_set_src(msg, &nla);
|
||||
nlmsg_set_creds(msg, &creds);
|
||||
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;
|
||||
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 (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 (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 (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(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 (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,
|
||||
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]);
|
||||
}
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
case NETLINK_GENERIC:
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
extern const struct nla_policy genl_ctrl_policy[8];
|
||||
|
||||
int genlmsg_parse(struct nlmsghdr *nlh,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue