platform: merge branch 'th/platform-genl-1'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1262
This commit is contained in:
@@ -415,11 +415,11 @@ typedef struct {
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
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;
|
guint32 nlh_seq_next;
|
||||||
#if NM_MORE_LOGGING
|
#if NM_MORE_LOGGING
|
||||||
@@ -570,8 +570,7 @@ static void cache_on_change(NMPlatform *platform,
|
|||||||
const NMPObject *obj_old,
|
const NMPObject *obj_old,
|
||||||
const NMPObject *obj_new);
|
const NMPObject *obj_new);
|
||||||
static void cache_prune_all(NMPlatform *platform);
|
static void cache_prune_all(NMPlatform *platform);
|
||||||
static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks);
|
static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks);
|
||||||
static struct nl_sock *_genl_sock(NMLinuxPlatform *platform);
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
@@ -2543,7 +2542,7 @@ _wireguard_get_family_id(NMPlatform *platform, int ifindex_try)
|
|||||||
wireguard_family_id = NMP_OBJECT_UP_CAST(plink)->_link.wireguard_family_id;
|
wireguard_family_id = NMP_OBJECT_UP_CAST(plink)->_link.wireguard_family_id;
|
||||||
}
|
}
|
||||||
if (wireguard_family_id < 0)
|
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;
|
return wireguard_family_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2573,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)
|
if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)
|
||||||
lnk_new = nmp_object_ref(plink->_link.netlink.lnk);
|
lnk_new = nmp_object_ref(plink->_link.netlink.lnk);
|
||||||
} else {
|
} 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 (!lnk_new) {
|
||||||
if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)
|
if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD)
|
||||||
lnk_new = nmp_object_ref(plink->_link.netlink.lnk);
|
lnk_new = nmp_object_ref(plink->_link.netlink.lnk);
|
||||||
@@ -2882,14 +2881,14 @@ link_wireguard_change(NMPlatform *platform,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < msgs->len; i++) {
|
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) {
|
if (r < 0) {
|
||||||
_LOGW("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror(r));
|
_LOGW("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = nl_recvmsgs(priv->genl, NULL);
|
r = nl_recvmsgs(priv->sk_genl_sync, NULL);
|
||||||
} while (r == -EAGAIN);
|
} while (r == -EAGAIN);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
_LOGW("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror(r));
|
_LOGW("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror(r));
|
||||||
@@ -3222,13 +3221,13 @@ _new_from_nl_link(NMPlatform *platform,
|
|||||||
case NM_LINK_TYPE_OLPC_MESH:
|
case NM_LINK_TYPE_OLPC_MESH:
|
||||||
obj->_link.ext_data =
|
obj->_link.ext_data =
|
||||||
(GObject *) nm_wifi_utils_new(ifi->ifi_index,
|
(GObject *) nm_wifi_utils_new(ifi->ifi_index,
|
||||||
_genl_sock(NM_LINUX_PLATFORM(platform)),
|
NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync,
|
||||||
TRUE);
|
TRUE);
|
||||||
break;
|
break;
|
||||||
case NM_LINK_TYPE_WPAN:
|
case NM_LINK_TYPE_WPAN:
|
||||||
obj->_link.ext_data =
|
obj->_link.ext_data =
|
||||||
(GObject *) nm_wpan_utils_new(ifi->ifi_index,
|
(GObject *) nm_wpan_utils_new(ifi->ifi_index,
|
||||||
_genl_sock(NM_LINUX_PLATFORM(platform)),
|
NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync,
|
||||||
TRUE);
|
TRUE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -3238,7 +3237,7 @@ _new_from_nl_link(NMPlatform *platform,
|
|||||||
|
|
||||||
if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
|
if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
|
||||||
const NMPObject *lnk_data_new = NULL;
|
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
|
/* The WireGuard kernel module does not yet send link update
|
||||||
* notifications, so we don't actually update the cache. For
|
* notifications, so we don't actually update the cache. For
|
||||||
@@ -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) \
|
#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
|
||||||
G_STMT_START \
|
G_STMT_START \
|
||||||
{ \
|
{ \
|
||||||
@@ -6689,12 +6680,12 @@ _nl_send_nlmsghdr(NMPlatform *platform,
|
|||||||
int try_count;
|
int try_count;
|
||||||
|
|
||||||
if (!nlhdr->nlmsg_pid)
|
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);
|
nlhdr->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK);
|
||||||
|
|
||||||
try_count = 0;
|
try_count = 0;
|
||||||
again:
|
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) {
|
if (errsv < 0) {
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (errsv == EINTR && try_count++ < 100)
|
if (errsv == EINTR && try_count++ < 100)
|
||||||
@@ -6742,7 +6733,7 @@ _nl_send_nlmsg(NMPlatform *platform,
|
|||||||
seq = _nlh_seq_next_get(priv);
|
seq = _nlh_seq_next_get(priv);
|
||||||
nlhdr->nlmsg_seq = seq;
|
nlhdr->nlmsg_seq = seq;
|
||||||
|
|
||||||
nle = nl_send_auto(priv->nlh, nlmsg);
|
nle = nl_send_auto(priv->sk_rtnl, nlmsg);
|
||||||
if (nle < 0) {
|
if (nle < 0) {
|
||||||
_LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle);
|
_LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle);
|
||||||
return nle;
|
return nle;
|
||||||
@@ -7062,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);
|
obj = nmp_object_new_from_nl(platform, cache, msg, is_del, &parse_nlmsg_iter);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
_LOGT("event-notification: %s: ignore",
|
_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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7080,7 +7071,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events
|
|||||||
}
|
}
|
||||||
|
|
||||||
_LOGT("event-notification: %s%s: %s",
|
_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" : "",
|
is_dump ? ", in-dump" : "",
|
||||||
nmp_object_to_string(obj,
|
nmp_object_to_string(obj,
|
||||||
is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC,
|
is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC,
|
||||||
@@ -9198,8 +9189,51 @@ 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
|
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);
|
delayed_action_handle_all(NM_PLATFORM(user_data), TRUE);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -9207,12 +9241,11 @@ event_handler(int fd, GIOCondition io_condition, gpointer user_data)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
/* copied from libnl3's recvmsgs() */
|
|
||||||
static int
|
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);
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
|
||||||
struct nl_sock *sk = priv->nlh;
|
struct nl_sock *sk;
|
||||||
int n;
|
int n;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
gboolean multipart = 0;
|
gboolean multipart = 0;
|
||||||
@@ -9222,39 +9255,31 @@ event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events)
|
|||||||
struct sockaddr_nl nla;
|
struct sockaddr_nl nla;
|
||||||
struct ucred creds;
|
struct ucred creds;
|
||||||
gboolean creds_has;
|
gboolean creds_has;
|
||||||
unsigned char *buf;
|
const char *log_prefix;
|
||||||
|
|
||||||
|
nm_assert(netlink_protocol == NETLINK_ROUTE);
|
||||||
|
sk = priv->sk_rtnl;
|
||||||
|
log_prefix = "rtnl";
|
||||||
|
|
||||||
continue_reading:
|
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, sk, &nla, &creds, &creds_has);
|
||||||
|
if (n < 0) {
|
||||||
|
if (n == -NME_NL_MSG_TRUNC && !handle_events)
|
||||||
|
goto continue_reading;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr = (struct nlmsghdr *) buf;
|
if (!creds_has || creds.pid) {
|
||||||
|
if (!creds_has)
|
||||||
|
_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)) {
|
while (nlmsg_ok(hdr, n)) {
|
||||||
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
||||||
gboolean abort_parsing = FALSE;
|
gboolean abort_parsing = FALSE;
|
||||||
@@ -9264,24 +9289,14 @@ continue_reading:
|
|||||||
const char *extack_msg = NULL;
|
const char *extack_msg = NULL;
|
||||||
|
|
||||||
msg = nlmsg_alloc_convert(hdr);
|
msg = nlmsg_alloc_convert(hdr);
|
||||||
|
nlmsg_set_proto(msg, netlink_protocol);
|
||||||
nlmsg_set_proto(msg, NETLINK_ROUTE);
|
|
||||||
nlmsg_set_src(msg, &nla);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_LOGt("netlink: recvmsg: new message %s",
|
|
||||||
nl_nlmsghdr_to_str(hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)));
|
|
||||||
|
|
||||||
nlmsg_set_creds(msg, &creds);
|
nlmsg_set_creds(msg, &creds);
|
||||||
|
|
||||||
|
_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)
|
if (hdr->nlmsg_flags & NLM_F_MULTI)
|
||||||
multipart = TRUE;
|
multipart = TRUE;
|
||||||
|
|
||||||
@@ -9299,95 +9314,104 @@ continue_reading:
|
|||||||
/* FIXME: implement */
|
/* 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) {
|
if (hdr->nlmsg_type == NLMSG_DONE) {
|
||||||
/* messages terminates a multipart message, this is
|
/* messages terminates a multipart message, this is
|
||||||
* usually the end of a message and therefore we slip
|
* usually the end of a message and therefore we slip
|
||||||
* out of the loop by default. the user may overrule
|
* out of the loop by default. the user may overrule
|
||||||
* this action by skipping this packet. */
|
* this action by skipping this packet. */
|
||||||
multipart = FALSE;
|
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
|
|
||||||
seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
|
seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
|
||||||
} else
|
} else if (hdr->nlmsg_type == NLMSG_NOOP) {
|
||||||
process_valid_msg = TRUE;
|
/* 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
|
if (NM_FLAGS_HAS(hdr->nlmsg_flags, NLM_F_ACK_TLVS)
|
||||||
* whether the previous number (@nlh_seq_last_seen) is a pending
|
&& hdr->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) {
|
||||||
* refresh-all request. In that case, the pending request is thereby
|
static const struct nla_policy policy[] = {
|
||||||
* completed.
|
[NLMSGERR_ATTR_MSG] = {.type = NLA_STRING},
|
||||||
*
|
[NLMSGERR_ATTR_OFFS] = {.type = NLA_U32},
|
||||||
* We must do that before processing the message with event_valid_msg(),
|
};
|
||||||
* because we must track the completion of the pending request before that. */
|
struct nlattr *tb[G_N_ELEMENTS(policy)];
|
||||||
event_seq_check_refresh_all(platform, seq_number);
|
struct nlattr *tlvs;
|
||||||
|
|
||||||
if (process_valid_msg) {
|
tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len
|
||||||
/* Valid message (not checking for MULTIPART bit to
|
- NLMSG_HDRLEN);
|
||||||
* get along with broken kernels. NL_SKIP has no
|
if (nla_parse_arr(tb,
|
||||||
* effect on this. */
|
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)
|
if (abort_parsing)
|
||||||
goto stop;
|
goto stop;
|
||||||
@@ -9440,7 +9464,7 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int nle;
|
int nle;
|
||||||
|
|
||||||
nle = event_handler_recvmsgs(platform, TRUE);
|
nle = _netlink_recv_handle(platform, NETLINK_ROUTE, TRUE);
|
||||||
|
|
||||||
if (nle < 0) {
|
if (nle < 0) {
|
||||||
switch (nle) {
|
switch (nle) {
|
||||||
@@ -9465,7 +9489,7 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks)
|
|||||||
}
|
}
|
||||||
_reason;
|
_reason;
|
||||||
}));
|
}));
|
||||||
event_handler_recvmsgs(platform, FALSE);
|
_netlink_recv_handle(platform, NETLINK_ROUTE, FALSE);
|
||||||
delayed_action_wait_for_nl_response_complete_all(
|
delayed_action_wait_for_nl_response_complete_all(
|
||||||
platform,
|
platform,
|
||||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
|
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
|
||||||
@@ -9521,7 +9545,7 @@ after_read:
|
|||||||
timeout_msec);
|
timeout_msec);
|
||||||
|
|
||||||
memset(&pfd, 0, sizeof(pfd));
|
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;
|
pfd.events = POLLIN;
|
||||||
r = poll(&pfd, 1, timeout_msec);
|
r = poll(&pfd, 1, timeout_msec);
|
||||||
|
|
||||||
@@ -9721,43 +9745,36 @@ constructed(GObject *_object)
|
|||||||
nm_platform_get_use_udev(platform) ? "use" : "no",
|
nm_platform_get_use_udev(platform) ? "use" : "no",
|
||||||
nm_platform_get_cache_tc(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);
|
nle = nl_socket_new(&priv->sk_genl_sync, 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);
|
|
||||||
g_assert(!nle);
|
|
||||||
nle = nl_socket_set_passcred(priv->nlh, 1);
|
|
||||||
g_assert(!nle);
|
g_assert(!nle);
|
||||||
|
|
||||||
/* No blocking for event socket, so that we can drain it safely. */
|
_LOGD("genl: generic netlink socket for sync operations created: port=%u, fd=%d",
|
||||||
nle = nl_socket_set_nonblocking(priv->nlh);
|
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);
|
g_assert(!nle);
|
||||||
|
|
||||||
/* use 8 MB for receive socket kernel queue. */
|
nle = nl_socket_set_passcred(priv->sk_rtnl, 1);
|
||||||
nle = nl_socket_set_buffer_size(priv->nlh, 8 * 1024 * 1024, 0);
|
|
||||||
g_assert(!nle);
|
g_assert(!nle);
|
||||||
|
|
||||||
nle = nl_socket_set_ext_ack(priv->nlh, TRUE);
|
nle = nl_socket_set_nonblocking(priv->sk_rtnl);
|
||||||
if (nle)
|
g_assert(!nle);
|
||||||
_LOGD("could not enable extended acks on netlink socket");
|
|
||||||
|
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.
|
/* explicitly set the msg buffer size and disable MSG_PEEK.
|
||||||
* We use our own receive buffer priv->netlink_recv_buf.
|
* We use our own receive buffer priv->netlink_recv_buf.
|
||||||
* If we encounter NME_NL_MSG_TRUNC, we will increase the buffer
|
* 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). */
|
* 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_IFADDR,
|
||||||
RTNLGRP_IPV4_ROUTE,
|
RTNLGRP_IPV4_ROUTE,
|
||||||
RTNLGRP_IPV4_RULE,
|
RTNLGRP_IPV4_RULE,
|
||||||
@@ -9769,22 +9786,24 @@ constructed(GObject *_object)
|
|||||||
g_assert(!nle);
|
g_assert(!nle);
|
||||||
|
|
||||||
if (nm_platform_get_cache_tc(platform)) {
|
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);
|
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",
|
_LOGD("rtnl: rtnetlink socket created: port=%u, fd=%d",
|
||||||
nl_socket_get_local_port(priv->nlh),
|
nl_socket_get_local_port(priv->sk_rtnl),
|
||||||
fd);
|
fd);
|
||||||
|
|
||||||
priv->event_source =
|
priv->rtnl_event_source =
|
||||||
nm_g_unix_fd_add_source(fd,
|
nm_g_unix_fd_add_source(fd,
|
||||||
G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP,
|
G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP,
|
||||||
event_handler,
|
rtnl_event_handler,
|
||||||
platform);
|
platform);
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
/* complete construction of the GObject instance before populating the cache. */
|
/* complete construction of the GObject instance before populating the cache. */
|
||||||
G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object);
|
G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object);
|
||||||
|
|
||||||
@@ -9899,11 +9918,11 @@ finalize(GObject *object)
|
|||||||
g_ptr_array_unref(priv->delayed_action.list_refresh_link);
|
g_ptr_array_unref(priv->delayed_action.list_refresh_link);
|
||||||
g_array_unref(priv->delayed_action.list_wait_for_nl_response);
|
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);
|
NM_G_MUTEX_LOCKED(&sysctl_clear_cache_lock);
|
||||||
|
@@ -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_SOCK_PASSCRED (1 << 1)
|
||||||
#define NL_MSG_PEEK (1 << 3)
|
#define NL_MSG_PEEK (1 << 3)
|
||||||
#define NL_MSG_PEEK_EXPLICIT (1 << 4)
|
#define NL_MSG_PEEK_EXPLICIT (1 << 4)
|
||||||
@@ -74,10 +84,10 @@ NM_UTILS_FLAGS2STR_DEFINE(nl_nlmsg_flags2str,
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
const char *
|
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 *b;
|
||||||
const char *s;
|
const char *s = NULL;
|
||||||
guint flags, flags_before;
|
guint flags, flags_before;
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
|
|
||||||
@@ -86,78 +96,81 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len)
|
|||||||
|
|
||||||
b = buf;
|
b = buf;
|
||||||
|
|
||||||
switch (hdr->nlmsg_type) {
|
switch (netlink_protocol) {
|
||||||
case RTM_GETLINK:
|
case NETLINK_ROUTE:
|
||||||
s = "RTM_GETLINK";
|
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;
|
break;
|
||||||
case RTM_NEWLINK:
|
case NETLINK_GENERIC:
|
||||||
s = "RTM_NEWLINK";
|
|
||||||
break;
|
|
||||||
case RTM_DELLINK:
|
|
||||||
s = "RTM_DELLINK";
|
|
||||||
break;
|
|
||||||
case RTM_SETLINK:
|
|
||||||
s = "RTM_SETLINK";
|
|
||||||
break;
|
|
||||||
case RTM_GETADDR:
|
|
||||||
s = "RTM_GETADDR";
|
|
||||||
break;
|
|
||||||
case RTM_NEWADDR:
|
|
||||||
s = "RTM_NEWADDR";
|
|
||||||
break;
|
|
||||||
case RTM_DELADDR:
|
|
||||||
s = "RTM_DELADDR";
|
|
||||||
break;
|
|
||||||
case RTM_GETROUTE:
|
|
||||||
s = "RTM_GETROUTE";
|
|
||||||
break;
|
|
||||||
case RTM_NEWROUTE:
|
|
||||||
s = "RTM_NEWROUTE";
|
|
||||||
break;
|
|
||||||
case RTM_DELROUTE:
|
|
||||||
s = "RTM_DELROUTE";
|
|
||||||
break;
|
|
||||||
case RTM_GETRULE:
|
|
||||||
s = "RTM_GETRULE";
|
|
||||||
break;
|
|
||||||
case RTM_NEWRULE:
|
|
||||||
s = "RTM_NEWRULE";
|
|
||||||
break;
|
|
||||||
case RTM_DELRULE:
|
|
||||||
s = "RTM_DELRULE";
|
|
||||||
break;
|
|
||||||
case RTM_GETQDISC:
|
|
||||||
s = "RTM_GETQDISC";
|
|
||||||
break;
|
|
||||||
case RTM_NEWQDISC:
|
|
||||||
s = "RTM_NEWQDISC";
|
|
||||||
break;
|
|
||||||
case RTM_DELQDISC:
|
|
||||||
s = "RTM_DELQDISC";
|
|
||||||
break;
|
|
||||||
case RTM_GETTFILTER:
|
|
||||||
s = "RTM_GETTFILTER";
|
|
||||||
break;
|
|
||||||
case RTM_NEWTFILTER:
|
|
||||||
s = "RTM_NEWTFILTER";
|
|
||||||
break;
|
|
||||||
case RTM_DELTFILTER:
|
|
||||||
s = "RTM_DELTFILTER";
|
|
||||||
break;
|
|
||||||
case NLMSG_NOOP:
|
|
||||||
s = "NLMSG_NOOP";
|
|
||||||
break;
|
|
||||||
case NLMSG_ERROR:
|
|
||||||
s = "NLMSG_ERROR";
|
|
||||||
break;
|
|
||||||
case NLMSG_DONE:
|
|
||||||
s = "NLMSG_DONE";
|
|
||||||
break;
|
|
||||||
case NLMSG_OVERRUN:
|
|
||||||
s = "NLMSG_OVERRUN";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
s = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,27 +211,30 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len)
|
|||||||
if (flags_before != flags)
|
if (flags_before != flags)
|
||||||
prefix = ";";
|
prefix = ";";
|
||||||
|
|
||||||
switch (hdr->nlmsg_type) {
|
switch (netlink_protocol) {
|
||||||
case RTM_NEWLINK:
|
case NETLINK_ROUTE:
|
||||||
case RTM_NEWADDR:
|
switch (hdr->nlmsg_type) {
|
||||||
case RTM_NEWROUTE:
|
case RTM_NEWLINK:
|
||||||
case RTM_NEWQDISC:
|
case RTM_NEWADDR:
|
||||||
case RTM_NEWTFILTER:
|
case RTM_NEWROUTE:
|
||||||
_F(NLM_F_REPLACE, "replace");
|
case RTM_NEWQDISC:
|
||||||
_F(NLM_F_EXCL, "excl");
|
case RTM_NEWTFILTER:
|
||||||
_F(NLM_F_CREATE, "create");
|
_F(NLM_F_REPLACE, "replace");
|
||||||
_F(NLM_F_APPEND, "append");
|
_F(NLM_F_EXCL, "excl");
|
||||||
break;
|
_F(NLM_F_CREATE, "create");
|
||||||
case RTM_GETLINK:
|
_F(NLM_F_APPEND, "append");
|
||||||
case RTM_GETADDR:
|
break;
|
||||||
case RTM_GETROUTE:
|
case RTM_GETLINK:
|
||||||
case RTM_DELQDISC:
|
case RTM_GETADDR:
|
||||||
case RTM_DELTFILTER:
|
case RTM_GETROUTE:
|
||||||
_F(NLM_F_DUMP, "dump");
|
case RTM_DELQDISC:
|
||||||
_F(NLM_F_ROOT, "root");
|
case RTM_DELTFILTER:
|
||||||
_F(NLM_F_MATCH, "match");
|
_F(NLM_F_DUMP, "dump");
|
||||||
_F(NLM_F_ATOMIC, "atomic");
|
_F(NLM_F_ROOT, "root");
|
||||||
break;
|
_F(NLM_F_MATCH, "match");
|
||||||
|
_F(NLM_F_ATOMIC, "atomic");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef _F
|
#undef _F
|
||||||
@@ -879,30 +895,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
|
void
|
||||||
nl_socket_free(struct nl_sock *sk)
|
nl_socket_free(struct nl_sock *sk)
|
||||||
{
|
{
|
||||||
if (!sk)
|
if (!sk)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sk->s_fd >= 0)
|
nm_close(sk->s_fd);
|
||||||
nm_close(sk->s_fd);
|
nm_g_slice_free(sk);
|
||||||
g_slice_free(struct nl_sock, sk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -928,8 +928,7 @@ nl_socket_set_passcred(struct nl_sock *sk, int state)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (sk->s_fd == -1)
|
nm_assert_sk(sk);
|
||||||
return -NME_NL_BAD_SOCK;
|
|
||||||
|
|
||||||
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state));
|
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -960,8 +959,7 @@ nlmsg_get_dst(struct nl_msg *msg)
|
|||||||
int
|
int
|
||||||
nl_socket_set_nonblocking(const struct nl_sock *sk)
|
nl_socket_set_nonblocking(const struct nl_sock *sk)
|
||||||
{
|
{
|
||||||
if (sk->s_fd == -1)
|
nm_assert_sk(sk);
|
||||||
return -NME_NL_BAD_SOCK;
|
|
||||||
|
|
||||||
if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
|
if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
|
||||||
return -nm_errno_from_native(errno);
|
return -nm_errno_from_native(errno);
|
||||||
@@ -974,15 +972,14 @@ nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
nm_assert_sk(sk);
|
||||||
|
|
||||||
if (rxbuf <= 0)
|
if (rxbuf <= 0)
|
||||||
rxbuf = 32768;
|
rxbuf = 32768;
|
||||||
|
|
||||||
if (txbuf <= 0)
|
if (txbuf <= 0)
|
||||||
txbuf = 32768;
|
txbuf = 32768;
|
||||||
|
|
||||||
if (sk->s_fd == -1)
|
|
||||||
return -NME_NL_BAD_SOCK;
|
|
||||||
|
|
||||||
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf));
|
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf));
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
return -nm_errno_from_native(errno);
|
return -nm_errno_from_native(errno);
|
||||||
@@ -1002,8 +999,7 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
|
|||||||
int err;
|
int err;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
if (sk->s_fd == -1)
|
nm_assert_sk(sk);
|
||||||
return -NME_NL_BAD_SOCK;
|
|
||||||
|
|
||||||
va_start(ap, group);
|
va_start(ap, group);
|
||||||
|
|
||||||
@@ -1032,10 +1028,10 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
|
|||||||
int
|
int
|
||||||
nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable)
|
nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable)
|
||||||
{
|
{
|
||||||
int err, val;
|
int err;
|
||||||
|
int val;
|
||||||
|
|
||||||
if (sk->s_fd == -1)
|
nm_assert_sk(sk);
|
||||||
return -NME_NL_BAD_SOCK;
|
|
||||||
|
|
||||||
val = !!enable;
|
val = !!enable;
|
||||||
err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val));
|
err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val));
|
||||||
@@ -1052,62 +1048,72 @@ nl_socket_disable_msg_peek(struct nl_sock *sk)
|
|||||||
sk->s_flags &= ~NL_MSG_PEEK;
|
sk->s_flags &= ~NL_MSG_PEEK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
int
|
int
|
||||||
nl_connect(struct nl_sock *sk, int protocol)
|
nl_socket_new(struct nl_sock **out_sk, int protocol)
|
||||||
{
|
{
|
||||||
int err, nmerr;
|
nm_auto_nlsock struct nl_sock *sk = NULL;
|
||||||
socklen_t addrlen;
|
nm_auto_close int fd = -1;
|
||||||
struct sockaddr_nl local = {0};
|
time_t t;
|
||||||
|
int err;
|
||||||
|
int nmerr;
|
||||||
|
socklen_t addrlen;
|
||||||
|
struct sockaddr_nl local = {0};
|
||||||
|
|
||||||
if (sk->s_fd != -1)
|
nm_assert(out_sk && !*out_sk);
|
||||||
return -NME_NL_BAD_SOCK;
|
|
||||||
|
|
||||||
sk->s_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
|
fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
|
||||||
if (sk->s_fd < 0) {
|
if (fd < 0)
|
||||||
nmerr = -nm_errno_from_native(errno);
|
return -nm_errno_from_native(errno);
|
||||||
goto errout;
|
|
||||||
}
|
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);
|
nmerr = nl_socket_set_buffer_size(sk, 0, 0);
|
||||||
if (nmerr < 0)
|
if (nmerr < 0)
|
||||||
goto errout;
|
return nmerr;
|
||||||
|
|
||||||
nm_assert(sk->s_local.nl_pid == 0);
|
|
||||||
|
|
||||||
err = bind(sk->s_fd, (struct sockaddr *) &sk->s_local, sizeof(sk->s_local));
|
err = bind(sk->s_fd, (struct sockaddr *) &sk->s_local, sizeof(sk->s_local));
|
||||||
if (err != 0) {
|
if (err != 0)
|
||||||
nmerr = -nm_errno_from_native(errno);
|
return -nm_errno_from_native(errno);
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
addrlen = sizeof(local);
|
addrlen = sizeof(local);
|
||||||
err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen);
|
err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
nmerr = -nm_errno_from_native(errno);
|
return -nm_errno_from_native(errno);
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addrlen != sizeof(local)) {
|
if (addrlen != sizeof(local))
|
||||||
nmerr = -NME_UNSPEC;
|
return -NME_UNSPEC;
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (local.nl_family != AF_NETLINK) {
|
if (local.nl_family != AF_NETLINK)
|
||||||
nmerr = -NME_UNSPEC;
|
return -NME_UNSPEC;
|
||||||
goto errout;
|
|
||||||
}
|
(void) nl_socket_set_ext_ack(sk, TRUE);
|
||||||
|
|
||||||
sk->s_local = local;
|
sk->s_local = local;
|
||||||
sk->s_proto = protocol;
|
sk->s_proto = protocol;
|
||||||
|
|
||||||
|
*out_sk = g_steal_pointer(&sk);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
errout:
|
|
||||||
if (sk->s_fd != -1) {
|
|
||||||
close(sk->s_fd);
|
|
||||||
sk->s_fd = -1;
|
|
||||||
}
|
|
||||||
return nmerr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@@ -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_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);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
@@ -413,11 +414,7 @@ void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr);
|
|||||||
struct ucred *nlmsg_get_creds(struct nl_msg *msg);
|
struct ucred *nlmsg_get_creds(struct nl_msg *msg);
|
||||||
void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds);
|
void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds);
|
||||||
|
|
||||||
static inline void
|
NM_AUTO_DEFINE_FCN0(struct nl_msg *, _nm_auto_nl_msg_cleanup, nlmsg_free);
|
||||||
_nm_auto_nl_msg_cleanup(struct nl_msg **ptr)
|
|
||||||
{
|
|
||||||
nlmsg_free(*ptr);
|
|
||||||
}
|
|
||||||
#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
|
#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
@@ -492,10 +489,13 @@ nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, i
|
|||||||
|
|
||||||
struct nl_sock;
|
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);
|
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);
|
int nl_socket_get_fd(const struct nl_sock *sk);
|
||||||
|
|
||||||
struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg);
|
struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg);
|
||||||
|
@@ -59,7 +59,7 @@ test_use_symbols(void)
|
|||||||
(void (*)(void)) genlmsg_valid_hdr,
|
(void (*)(void)) genlmsg_valid_hdr,
|
||||||
(void (*)(void)) genlmsg_parse,
|
(void (*)(void)) genlmsg_parse,
|
||||||
(void (*)(void)) genl_ctrl_resolve,
|
(void (*)(void)) genl_ctrl_resolve,
|
||||||
(void (*)(void)) nl_socket_alloc,
|
(void (*)(void)) nl_socket_new,
|
||||||
(void (*)(void)) nl_socket_free,
|
(void (*)(void)) nl_socket_free,
|
||||||
(void (*)(void)) nl_socket_get_fd,
|
(void (*)(void)) nl_socket_get_fd,
|
||||||
(void (*)(void)) nl_socket_get_local_port,
|
(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_add_memberships,
|
||||||
(void (*)(void)) nl_socket_set_ext_ack,
|
(void (*)(void)) nl_socket_set_ext_ack,
|
||||||
(void (*)(void)) nl_socket_disable_msg_peek,
|
(void (*)(void)) nl_socket_disable_msg_peek,
|
||||||
(void (*)(void)) nl_connect,
|
|
||||||
(void (*)(void)) nl_wait_for_ack,
|
(void (*)(void)) nl_wait_for_ack,
|
||||||
(void (*)(void)) nl_recvmsgs,
|
(void (*)(void)) nl_recvmsgs,
|
||||||
(void (*)(void)) nl_sendmsg,
|
(void (*)(void)) nl_sendmsg,
|
||||||
|
Reference in New Issue
Block a user