mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 07:10:07 +01:00
platform/netlink: merge branch 'th/netlink' (#67)
https://github.com/NetworkManager/NetworkManager/pull/67
This commit is contained in:
commit
3d987fe2db
12 changed files with 1882 additions and 376 deletions
|
|
@ -16,9 +16,6 @@ addons:
|
|||
- libdbus-1-dev
|
||||
- libiw-dev
|
||||
- libglib2.0-dev
|
||||
- libnl-3-dev
|
||||
- libnl-route-3-dev
|
||||
- libnl-genl-3-dev
|
||||
- libmm-glib-dev
|
||||
- ppp
|
||||
- ppp-dev
|
||||
|
|
@ -43,7 +40,6 @@ addons:
|
|||
- dbus-x11
|
||||
- libjansson4
|
||||
- libjansson-dev
|
||||
- libnl-3-dev
|
||||
- libndp-dev
|
||||
- automake
|
||||
- dnsmasq
|
||||
|
|
|
|||
|
|
@ -1185,7 +1185,6 @@ src_cppflags = \
|
|||
-DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \
|
||||
\
|
||||
$(LIBUDEV_CFLAGS) \
|
||||
$(LIBNL_CFLAGS) \
|
||||
$(LIBNDP_CFLAGS) \
|
||||
$(LIBPSL_CFLAGS) \
|
||||
$(LIBCURL_CFLAGS) \
|
||||
|
|
@ -1643,7 +1642,6 @@ src_libNetworkManager_la_LIBADD = \
|
|||
src/libsystemd-nm.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(LIBUDEV_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(SYSTEMD_LOGIN_LIBS) \
|
||||
$(LIBNDP_LIBS) \
|
||||
$(DL_LIBS) \
|
||||
|
|
@ -1684,8 +1682,7 @@ src_libNetworkManagerTest_la_LIBADD = \
|
|||
src/libNetworkManager.la \
|
||||
$(CODE_COVERAGE_LDFLAGS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(LIBUDEV_LIBS) \
|
||||
$(LIBNL_LIBS)
|
||||
$(LIBUDEV_LIBS)
|
||||
|
||||
$(src_libNetworkManagerTest_la_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
|
||||
|
||||
|
|
@ -1726,7 +1723,6 @@ src_nm_iface_helper_LDADD = \
|
|||
src/libsystemd-nm.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(LIBUDEV_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(LIBNDP_LIBS) \
|
||||
$(DL_LIBS)
|
||||
|
||||
|
|
@ -2898,8 +2894,7 @@ src_platform_tests_ldflags = \
|
|||
src_platform_tests_libadd = \
|
||||
src/libNetworkManagerTest.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(LIBUDEV_LIBS) \
|
||||
$(LIBNL_LIBS)
|
||||
$(LIBUDEV_LIBS)
|
||||
|
||||
check_programs_norun += \
|
||||
src/platform/tests/monitor
|
||||
|
|
|
|||
|
|
@ -559,9 +559,6 @@ else
|
|||
fi
|
||||
AC_SUBST(NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT)
|
||||
|
||||
# libnl support for the linux platform
|
||||
PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8)
|
||||
|
||||
# uuid library
|
||||
PKG_CHECK_MODULES(UUID, uuid)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ yum install \
|
|||
jansson-devel \
|
||||
libcurl-devel \
|
||||
libndp-devel \
|
||||
libnl3-devel \
|
||||
libpsl-devel \
|
||||
libselinux-devel \
|
||||
libtool \
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ BUILD_PACKAGES="qemu febootstrap mock rpmdevtools"
|
|||
ARCH=i386
|
||||
ROOT="${ROOT:-"fedora-20-$ARCH"}"
|
||||
TREE="/var/lib/mock/$ROOT/root"
|
||||
PACKAGES="kernel passwd git autoconf automake libtool intltool gtk-doc libnl3-devel
|
||||
PACKAGES="kernel passwd git autoconf automake libtool intltool gtk-doc
|
||||
dbus-glib-devel libuuid-devel nss-devel ppp-devel newt-devel libndp-devel
|
||||
readline-devel
|
||||
gobject-introspection-devel
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
%global dbus_glib_version 0.100
|
||||
|
||||
%global wireless_tools_version 1:28-0pre9
|
||||
%global libnl3_version 3.2.7
|
||||
|
||||
%global ppp_version %(sed -n 's/^#define\\s*VERSION\\s*"\\([^\\s]*\\)"$/\\1/p' %{_includedir}/pppd/patchlevel.h 2>/dev/null | grep . || echo bad)
|
||||
%global glib2_version %(pkg-config --modversion glib-2.0 2>/dev/null || echo bad)
|
||||
|
|
@ -130,7 +129,6 @@ BuildRequires: glib2-devel >= 2.40.0
|
|||
BuildRequires: gobject-introspection-devel >= 0.10.3
|
||||
BuildRequires: gettext-devel
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: libnl3-devel >= %{libnl3_version}
|
||||
BuildRequires: automake autoconf intltool libtool
|
||||
%if %{with ppp}
|
||||
BuildRequires: ppp-devel >= 2.4.5
|
||||
|
|
|
|||
|
|
@ -184,9 +184,6 @@ libudev_dep = dependency('libudev', version: '>= 175')
|
|||
dbus_dep = dependency('dbus-1', version: '>= 1.1')
|
||||
libndp_dep = dependency('libndp')
|
||||
|
||||
# libnl support for the linux platform
|
||||
libnl_dep = dependency('libnl-3.0', version: '>= 3.2.8', required: false)
|
||||
|
||||
jansson_dep = dependency('jansson', version: '>= 2.5', required: false)
|
||||
config_h.set10('WITH_JANSSON', jansson_dep.found())
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ sources = files(
|
|||
)
|
||||
|
||||
deps = [
|
||||
libnl_dep,
|
||||
libnmdbus_dep,
|
||||
libsystemd_dep,
|
||||
libudev_dep,
|
||||
|
|
@ -170,7 +169,6 @@ sources = files(
|
|||
deps = [
|
||||
dl_dep,
|
||||
libndp_dep,
|
||||
libnl_dep,
|
||||
# FIXME: Some files use introspection/dbus* headers, so
|
||||
# this dependency might be needed
|
||||
#libnmdbus_dep,
|
||||
|
|
@ -252,7 +250,6 @@ network_manager = executable(
|
|||
deps = [
|
||||
dl_dep,
|
||||
libndp_dep,
|
||||
libnl_dep,
|
||||
libudev_dep,
|
||||
nm_core_dep
|
||||
]
|
||||
|
|
@ -279,7 +276,6 @@ if enable_tests
|
|||
)
|
||||
|
||||
deps = [
|
||||
libnl_dep,
|
||||
libudev_dep,
|
||||
nm_core_dep
|
||||
]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "nm-linux-platform.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -79,10 +80,6 @@ enum {
|
|||
|
||||
#define VLAN_FLAG_MVRP 0x8
|
||||
|
||||
/* nm-internal error codes for libnl. Make sure they don't overlap. */
|
||||
#define _NLE_NM_NOBUFS 500
|
||||
#define _NLE_MSG_TRUNC 501
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define IFQDISCSIZ 32
|
||||
|
|
@ -297,6 +294,7 @@ typedef enum {
|
|||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS,
|
||||
} WaitForNlResponseResult;
|
||||
|
||||
typedef void (*WaitForNlResponseCallback) (NMPlatform *platform,
|
||||
|
|
@ -951,106 +949,6 @@ _nl_addattr_l (struct nlmsghdr *n,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len)
|
||||
{
|
||||
const char *b;
|
||||
const char *s;
|
||||
guint flags, flags_before;
|
||||
const char *prefix;
|
||||
|
||||
nm_utils_to_string_buffer_init (&buf, &len);
|
||||
b = buf;
|
||||
|
||||
switch (hdr->nlmsg_type) {
|
||||
case RTM_NEWLINK: s = "RTM_NEWLINK"; break;
|
||||
case RTM_DELLINK: s = "RTM_DELLINK"; break;
|
||||
case RTM_NEWADDR: s = "RTM_NEWADDR"; break;
|
||||
case RTM_DELADDR: s = "RTM_DELADDR"; break;
|
||||
case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break;
|
||||
case RTM_DELROUTE: s = "RTM_DELROUTE"; break;
|
||||
case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break;
|
||||
case RTM_DELQDISC: s = "RTM_DELQDISC"; break;
|
||||
case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break;
|
||||
case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break;
|
||||
case NLMSG_NOOP: s = "NLMSG_NOOP"; break;
|
||||
case NLMSG_ERROR: s = "NLMSG_ERROR"; break;
|
||||
case NLMSG_DONE: s = "NLMSG_DONE"; break;
|
||||
case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break;
|
||||
default: s = NULL; break;
|
||||
}
|
||||
|
||||
if (s)
|
||||
nm_utils_strbuf_append_str (&buf, &len, s);
|
||||
else
|
||||
nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type);
|
||||
|
||||
flags = hdr->nlmsg_flags;
|
||||
|
||||
if (!flags) {
|
||||
nm_utils_strbuf_append_str (&buf, &len, ", flags 0");
|
||||
goto flags_done;
|
||||
}
|
||||
|
||||
#define _F(f, n) \
|
||||
G_STMT_START { \
|
||||
if (NM_FLAGS_ALL (flags, f)) { \
|
||||
flags &= ~(f); \
|
||||
nm_utils_strbuf_append (&buf, &len, "%s%s", prefix, n); \
|
||||
if (!flags) \
|
||||
goto flags_done; \
|
||||
prefix = ","; \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
prefix = ", flags ";
|
||||
flags_before = flags;
|
||||
_F (NLM_F_REQUEST, "request");
|
||||
_F (NLM_F_MULTI, "multi");
|
||||
_F (NLM_F_ACK, "ack");
|
||||
_F (NLM_F_ECHO, "echo");
|
||||
_F (NLM_F_DUMP_INTR, "dump_intr");
|
||||
_F (0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered");
|
||||
|
||||
if (flags_before != flags)
|
||||
prefix = ";";
|
||||
|
||||
switch (hdr->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
case RTM_NEWADDR:
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_NEWQDISC:
|
||||
case RTM_NEWTFILTER:
|
||||
_F (NLM_F_REPLACE, "replace");
|
||||
_F (NLM_F_EXCL, "excl");
|
||||
_F (NLM_F_CREATE, "create");
|
||||
_F (NLM_F_APPEND, "append");
|
||||
break;
|
||||
case RTM_GETLINK:
|
||||
case RTM_GETADDR:
|
||||
case RTM_GETROUTE:
|
||||
case RTM_DELQDISC:
|
||||
case RTM_DELTFILTER:
|
||||
_F (NLM_F_DUMP, "dump");
|
||||
_F (NLM_F_ROOT, "root");
|
||||
_F (NLM_F_MATCH, "match");
|
||||
_F (NLM_F_ATOMIC, "atomic");
|
||||
break;
|
||||
}
|
||||
|
||||
#undef _F
|
||||
|
||||
if (flags_before != flags)
|
||||
prefix = ";";
|
||||
nm_utils_strbuf_append (&buf, &len, "%s0x%04x", prefix, flags);
|
||||
|
||||
flags_done:
|
||||
|
||||
nm_utils_strbuf_append (&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* NMPObject/netlink functions
|
||||
******************************************************************/
|
||||
|
|
@ -2637,8 +2535,7 @@ _nl_msg_new_link (int nlmsg_type,
|
|||
|
||||
nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK));
|
||||
|
||||
if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags)))
|
||||
g_return_val_if_reached (NULL);
|
||||
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
|
||||
|
||||
if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0)
|
||||
goto nla_put_failure;
|
||||
|
|
@ -2680,8 +2577,6 @@ _nl_msg_new_address (int nlmsg_type,
|
|||
nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR));
|
||||
|
||||
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
|
||||
if (!msg)
|
||||
g_return_val_if_reached (NULL);
|
||||
|
||||
if (scope == -1) {
|
||||
/* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */
|
||||
|
|
@ -2794,8 +2689,6 @@ _nl_msg_new_route (int nlmsg_type,
|
|||
nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE));
|
||||
|
||||
msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags);
|
||||
if (!msg)
|
||||
g_return_val_if_reached (NULL);
|
||||
|
||||
if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0)
|
||||
goto nla_put_failure;
|
||||
|
|
@ -2893,8 +2786,6 @@ _nl_msg_new_qdisc (int nlmsg_type,
|
|||
};
|
||||
|
||||
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0)
|
||||
goto nla_put_failure;
|
||||
|
|
@ -2969,8 +2860,6 @@ _nl_msg_new_tfilter (int nlmsg_type,
|
|||
};
|
||||
|
||||
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0)
|
||||
goto nla_put_failure;
|
||||
|
|
@ -3553,28 +3442,59 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
|
|||
g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx);
|
||||
}
|
||||
|
||||
static void
|
||||
delayed_action_wait_for_nl_response_complete_check (NMPlatform *platform,
|
||||
WaitForNlResponseResult force_result,
|
||||
guint32 *out_next_seq_number,
|
||||
gint64 *out_next_timeout_abs_ns,
|
||||
gint64 *p_now_ns)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
guint i;
|
||||
guint32 next_seq_number = 0;
|
||||
gint64 next_timeout_abs_ns = 0;
|
||||
gint now_ns = 0;
|
||||
|
||||
for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) {
|
||||
const DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
|
||||
|
||||
if (data->seq_result)
|
||||
delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result);
|
||||
else if ( p_now_ns
|
||||
&& ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) >= data->timeout_abs_ns)) {
|
||||
/* the caller can optionally check for timeout by providing a p_now_ns argument. */
|
||||
delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT);
|
||||
} else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN)
|
||||
delayed_action_wait_for_nl_response_complete (platform, i, force_result);
|
||||
else {
|
||||
if ( next_seq_number == 0
|
||||
|| next_timeout_abs_ns > data->timeout_abs_ns) {
|
||||
next_seq_number = data->seq_number;
|
||||
next_timeout_abs_ns = data->timeout_abs_ns;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) {
|
||||
nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
|
||||
nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0);
|
||||
}
|
||||
|
||||
NM_SET_OUT (out_next_seq_number, next_seq_number);
|
||||
NM_SET_OUT (out_next_timeout_abs_ns, next_timeout_abs_ns);
|
||||
NM_SET_OUT (p_now_ns, now_ns);
|
||||
}
|
||||
|
||||
static void
|
||||
delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform,
|
||||
WaitForNlResponseResult fallback_result)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
|
||||
if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
|
||||
while (priv->delayed_action.list_wait_for_nl_response->len > 0) {
|
||||
const DelayedActionWaitForNlResponseData *data;
|
||||
guint idx = priv->delayed_action.list_wait_for_nl_response->len - 1;
|
||||
WaitForNlResponseResult r;
|
||||
|
||||
data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx);
|
||||
|
||||
/* prefer the result that we already have. */
|
||||
r = data->seq_result ? : fallback_result;
|
||||
|
||||
delayed_action_wait_for_nl_response_complete (platform, idx, r);
|
||||
}
|
||||
}
|
||||
nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
|
||||
nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0);
|
||||
delayed_action_wait_for_nl_response_complete_check (platform,
|
||||
fallback_result,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -4051,7 +3971,7 @@ _nlh_seq_next_get (NMLinuxPlatformPrivate *priv)
|
|||
* @response_type:
|
||||
* @response_out_data:
|
||||
*
|
||||
* Returns: 0 on success or a negative errno. Beware, it's an errno, not nlerror.
|
||||
* Returns: 0 on success or a negative errno.
|
||||
*/
|
||||
static int
|
||||
_nl_send_nlmsghdr (NMPlatform *platform,
|
||||
|
|
@ -4235,8 +4155,6 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
|
|||
* because we need the sequence number.
|
||||
*/
|
||||
nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP);
|
||||
if (!nlmsg)
|
||||
continue;
|
||||
|
||||
if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC
|
||||
|| klass->obj_type == NMP_OBJECT_TYPE_TFILTER) {
|
||||
|
|
@ -4363,7 +4281,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
|||
obj = nmp_object_new_from_nl (platform, cache, msg, id_only);
|
||||
if (!obj) {
|
||||
_LOGT ("event-notification: %s: ignore",
|
||||
_nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)));
|
||||
nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4381,7 +4299,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
|||
}
|
||||
|
||||
_LOGT ("event-notification: %s%s: %s",
|
||||
_nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)),
|
||||
nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)),
|
||||
is_dump ? ", in-dump" : "",
|
||||
nmp_object_to_string (obj,
|
||||
id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
|
|
@ -6561,15 +6479,12 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events)
|
|||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
struct nl_sock *sk = priv->nlh;
|
||||
int n, err = 0, multipart = 0, interrupted = 0;
|
||||
int n;
|
||||
int err = 0;
|
||||
gboolean multipart = 0;
|
||||
gboolean interrupted = FALSE;
|
||||
struct nlmsghdr *hdr;
|
||||
WaitForNlResponseResult seq_result;
|
||||
|
||||
/*
|
||||
nla is passed on to not only to nl_recv() but may also be passed
|
||||
to a function pointer provided by the caller which may or may not
|
||||
initialize the variable. Thomas Graf.
|
||||
*/
|
||||
struct sockaddr_nl nla = {0};
|
||||
nm_auto_free struct ucred *creds = NULL;
|
||||
nm_auto_free unsigned char *buf = NULL;
|
||||
|
|
@ -6577,56 +6492,28 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events)
|
|||
continue_reading:
|
||||
g_clear_pointer (&buf, free);
|
||||
g_clear_pointer (&creds, free);
|
||||
errno = 0;
|
||||
n = nl_recv (sk, &nla, &buf, &creds);
|
||||
|
||||
if (n <= 0) {
|
||||
/* workaround libnl3 <= 3.2.15 returning danling pointers in case nl_recv()
|
||||
* fails. Fixed by libnl3 69468517d0de1675d80f24661ff57a5dbac7275c. */
|
||||
buf = NULL;
|
||||
creds = NULL;
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 0:
|
||||
/* Work around a libnl bug fixed in 3.2.22 (375a6294) */
|
||||
if (errno == EAGAIN) {
|
||||
/* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to
|
||||
* workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */
|
||||
G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK);
|
||||
n = -NLE_AGAIN;
|
||||
}
|
||||
break;
|
||||
case -NLE_MSG_TRUNC: {
|
||||
int buf_size;
|
||||
if (n == -NLE_MSG_TRUNC) {
|
||||
int buf_size;
|
||||
|
||||
/* the message receive buffer was too small. We lost one message, which
|
||||
* is unfortunate. Try to double the buffer size for the next time. */
|
||||
buf_size = nl_socket_get_msg_buf_size (sk);
|
||||
if (buf_size < 512*1024) {
|
||||
buf_size *= 2;
|
||||
_LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size);
|
||||
if (nl_socket_set_msg_buf_size (sk, buf_size) < 0)
|
||||
nm_assert_not_reached ();
|
||||
if (!handle_events)
|
||||
goto continue_reading;
|
||||
/* the message receive buffer was too small. We lost one message, which
|
||||
* is unfortunate. Try to double the buffer size for the next time. */
|
||||
buf_size = nl_socket_get_msg_buf_size (sk);
|
||||
if (buf_size < 512*1024) {
|
||||
buf_size *= 2;
|
||||
_LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size);
|
||||
if (nl_socket_set_msg_buf_size (sk, buf_size) < 0)
|
||||
nm_assert_not_reached ();
|
||||
if (!handle_events)
|
||||
goto continue_reading;
|
||||
}
|
||||
}
|
||||
n = -_NLE_MSG_TRUNC;
|
||||
break;
|
||||
}
|
||||
case -NLE_NOMEM:
|
||||
if (errno == ENOBUFS) {
|
||||
/* we are very much interested in a overrun of the receive buffer.
|
||||
* nl_recv() maps all kinds of errors to NLE_NOMEM, so check also
|
||||
* for errno explicitly. And if so, hack our own return code to signal
|
||||
* the overrun. */
|
||||
n = -_NLE_NM_NOBUFS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (n <= 0)
|
||||
return n;
|
||||
}
|
||||
|
||||
hdr = (struct nlmsghdr *) buf;
|
||||
while (nlmsg_ok (hdr, n)) {
|
||||
|
|
@ -6636,11 +6523,7 @@ continue_reading:
|
|||
guint32 seq_number;
|
||||
char buf_nlmsghdr[400];
|
||||
|
||||
msg = nlmsg_convert (hdr);
|
||||
if (!msg) {
|
||||
err = -NLE_NOMEM;
|
||||
goto out;
|
||||
}
|
||||
msg = nlmsg_alloc_convert (hdr);
|
||||
|
||||
nlmsg_set_proto (msg, NETLINK_ROUTE);
|
||||
nlmsg_set_src (msg, &nla);
|
||||
|
|
@ -6655,13 +6538,13 @@ continue_reading:
|
|||
}
|
||||
|
||||
_LOGt ("netlink: recvmsg: new message %s",
|
||||
_nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)));
|
||||
nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)));
|
||||
|
||||
if (creds)
|
||||
nlmsg_set_creds (msg, creds);
|
||||
|
||||
if (hdr->nlmsg_flags & NLM_F_MULTI)
|
||||
multipart = 1;
|
||||
multipart = TRUE;
|
||||
|
||||
if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
|
||||
/*
|
||||
|
|
@ -6669,7 +6552,7 @@ continue_reading:
|
|||
* all messages until a NLMSG_DONE is
|
||||
* received and report the inconsistency.
|
||||
*/
|
||||
interrupted = 1;
|
||||
interrupted = TRUE;
|
||||
}
|
||||
|
||||
/* Other side wishes to see an ack for this message */
|
||||
|
|
@ -6684,7 +6567,7 @@ continue_reading:
|
|||
* 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 = 0;
|
||||
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
|
||||
|
|
@ -6763,9 +6646,9 @@ stop:
|
|||
* Repeat reading. */
|
||||
goto continue_reading;
|
||||
}
|
||||
out:
|
||||
|
||||
if (interrupted)
|
||||
err = -NLE_DUMP_INTR;
|
||||
return -NLE_DUMP_INTR;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -6776,46 +6659,50 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
|
|||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
int r, nle;
|
||||
int r;
|
||||
struct pollfd pfd;
|
||||
gboolean any = FALSE;
|
||||
gint64 now_ns;
|
||||
int timeout_ms;
|
||||
guint i;
|
||||
struct {
|
||||
guint32 seq_number;
|
||||
gint64 timeout_abs_ns;
|
||||
} data_next;
|
||||
gint64 now_ns;
|
||||
} next;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
if (!nm_platform_netns_push (platform, &netns)) {
|
||||
delayed_action_wait_for_nl_response_complete_all (platform,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
while (TRUE) {
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
int nle;
|
||||
|
||||
nle = event_handler_recvmsgs (platform, TRUE);
|
||||
|
||||
if (nle < 0) {
|
||||
switch (nle) {
|
||||
case -NLE_AGAIN:
|
||||
case -EAGAIN:
|
||||
goto after_read;
|
||||
case -NLE_DUMP_INTR:
|
||||
_LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
|
||||
break;
|
||||
case -_NLE_MSG_TRUNC:
|
||||
case -_NLE_NM_NOBUFS:
|
||||
case -NLE_MSG_TRUNC:
|
||||
case -ENOBUFS:
|
||||
_LOGI ("netlink: read: %s. Need to resynchronize platform cache",
|
||||
({
|
||||
const char *_reason = "unknown";
|
||||
switch (nle) {
|
||||
case -_NLE_MSG_TRUNC: _reason = "message truncated"; break;
|
||||
case -_NLE_NM_NOBUFS: _reason = "too many netlink events"; break;
|
||||
case -NLE_MSG_TRUNC: _reason = "message truncated"; break;
|
||||
case -ENOBUFS: _reason = "too many netlink events"; break;
|
||||
}
|
||||
_reason;
|
||||
}));
|
||||
event_handler_recvmsgs (platform, FALSE);
|
||||
delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
|
||||
delayed_action_wait_for_nl_response_complete_all (platform,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
|
||||
|
||||
delayed_action_schedule (platform,
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
|
||||
|
|
@ -6839,39 +6726,23 @@ after_read:
|
|||
if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
|
||||
return any;
|
||||
|
||||
now_ns = 0;
|
||||
data_next.seq_number = 0;
|
||||
data_next.timeout_abs_ns = 0;
|
||||
|
||||
for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) {
|
||||
DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
|
||||
|
||||
if (data->seq_result)
|
||||
delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result);
|
||||
else if ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) > data->timeout_abs_ns)
|
||||
delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT);
|
||||
else {
|
||||
i++;
|
||||
|
||||
if ( data_next.seq_number == 0
|
||||
|| data_next.timeout_abs_ns > data->timeout_abs_ns) {
|
||||
data_next.seq_number = data->seq_number;
|
||||
data_next.timeout_abs_ns = data->timeout_abs_ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
delayed_action_wait_for_nl_response_complete_check (platform,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN,
|
||||
&next.seq_number,
|
||||
&next.timeout_abs_ns,
|
||||
&next.now_ns);
|
||||
|
||||
if ( !wait_for_acks
|
||||
|| !NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
|
||||
return any;
|
||||
|
||||
nm_assert (data_next.seq_number);
|
||||
nm_assert (data_next.timeout_abs_ns > 0);
|
||||
nm_assert (now_ns > 0);
|
||||
nm_assert (next.seq_number);
|
||||
nm_assert (next.now_ns > 0);
|
||||
nm_assert (next.timeout_abs_ns > next.now_ns);
|
||||
|
||||
_LOGT ("netlink: read: wait for ACK for sequence number %u...", data_next.seq_number);
|
||||
_LOGT ("netlink: read: wait for ACK for sequence number %u...", next.seq_number);
|
||||
|
||||
timeout_ms = (data_next.timeout_abs_ns - now_ns) / (NM_UTILS_NS_PER_SECOND / 1000);
|
||||
timeout_ms = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NS_PER_SECOND / 1000);
|
||||
|
||||
memset (&pfd, 0, sizeof (pfd));
|
||||
pfd.fd = nl_socket_get_fd (priv->nlh);
|
||||
|
|
@ -6882,6 +6753,7 @@ after_read:
|
|||
/* timeout and there is nothing to read. */
|
||||
goto after_read;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
int errsv = errno;
|
||||
|
||||
|
|
@ -7152,7 +7024,8 @@ dispose (GObject *object)
|
|||
|
||||
_LOGD ("dispose");
|
||||
|
||||
delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING);
|
||||
delayed_action_wait_for_nl_response_complete_all (platform,
|
||||
WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING);
|
||||
|
||||
priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE;
|
||||
g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -21,40 +21,375 @@
|
|||
#ifndef __NM_NETLINK_H__
|
||||
#define __NM_NETLINK_H__
|
||||
|
||||
#include <netlink/msg.h>
|
||||
#include <netlink/attr.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* libnl3 compat code
|
||||
*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#define _NLE_BASE 100000
|
||||
#define NLE_UNSPEC (_NLE_BASE + 0)
|
||||
#define NLE_BUG (_NLE_BASE + 1)
|
||||
#define NLE_NATIVE_ERRNO (_NLE_BASE + 2)
|
||||
#define NLE_SEQ_MISMATCH (_NLE_BASE + 3)
|
||||
#define NLE_MSG_TRUNC (_NLE_BASE + 4)
|
||||
#define NLE_MSG_TOOSHORT (_NLE_BASE + 5)
|
||||
#define NLE_DUMP_INTR (_NLE_BASE + 6)
|
||||
#define NLE_ATTRSIZE (_NLE_BASE + 7)
|
||||
#define NLE_BAD_SOCK (_NLE_BASE + 8)
|
||||
#define NLE_NOADDR (_NLE_BASE + 9)
|
||||
#define NLE_MSG_OVERFLOW (_NLE_BASE + 10)
|
||||
|
||||
#define _NLE_BASE_END (_NLE_BASE + 11)
|
||||
|
||||
static inline int
|
||||
_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
|
||||
const struct nla_policy *policy)
|
||||
nl_errno (int err)
|
||||
{
|
||||
return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy);
|
||||
/* the error codes from our netlink implementation are plain errno
|
||||
* extended with our own error in a particular range starting from
|
||||
* _NLE_BASE.
|
||||
*
|
||||
* However, often we encode errors as negative values. This function
|
||||
* normalizes the error and returns it's positive value. */
|
||||
return err >= 0
|
||||
? err
|
||||
: ((err == G_MININT) ? NLE_BUG : -errno);
|
||||
}
|
||||
#define nla_parse(...) _nl_nla_parse(__VA_ARGS__)
|
||||
|
||||
static inline int
|
||||
_nl_nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy)
|
||||
nl_syserr2nlerr (int err)
|
||||
{
|
||||
return nlmsg_parse (nlh, hdrlen, tb, maxtype, (struct nla_policy *) policy);
|
||||
if (err == G_MININT)
|
||||
return NLE_NATIVE_ERRNO;
|
||||
if (err < 0)
|
||||
err = -err;
|
||||
return (err >= _NLE_BASE && err < _NLE_BASE_END)
|
||||
? NLE_NATIVE_ERRNO
|
||||
: err;
|
||||
}
|
||||
#define nlmsg_parse(...) _nl_nlmsg_parse(__VA_ARGS__)
|
||||
|
||||
const char *nl_geterror (int err);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Basic attribute data types */
|
||||
enum {
|
||||
NLA_UNSPEC, /* Unspecified type, binary data chunk */
|
||||
NLA_U8, /* 8 bit integer */
|
||||
NLA_U16, /* 16 bit integer */
|
||||
NLA_U32, /* 32 bit integer */
|
||||
NLA_U64, /* 64 bit integer */
|
||||
NLA_STRING, /* NUL terminated character string */
|
||||
NLA_FLAG, /* Flag */
|
||||
NLA_MSECS, /* Micro seconds (64bit) */
|
||||
NLA_NESTED, /* Nested attributes */
|
||||
NLA_NESTED_COMPAT,
|
||||
NLA_NUL_STRING,
|
||||
NLA_BINARY,
|
||||
NLA_S8,
|
||||
NLA_S16,
|
||||
NLA_S32,
|
||||
NLA_S64,
|
||||
__NLA_TYPE_MAX,
|
||||
};
|
||||
|
||||
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
|
||||
|
||||
struct nl_msg;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const char *nl_nlmsgtype2str (int type, char *buf, size_t size);
|
||||
|
||||
const char *nl_nlmsg_flags2str (int flags, char *buf, size_t len);
|
||||
|
||||
const char *nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct nla_policy {
|
||||
/* Type of attribute or NLA_UNSPEC */
|
||||
uint16_t type;
|
||||
|
||||
/* Minimal length of payload required */
|
||||
uint16_t minlen;
|
||||
|
||||
/* Maximal length of payload allowed */
|
||||
uint16_t maxlen;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline int
|
||||
_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
||||
const struct nla_policy *policy)
|
||||
nla_attr_size(int payload)
|
||||
{
|
||||
return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__)
|
||||
nm_assert (payload >= 0);
|
||||
|
||||
/*****************************************************************************
|
||||
* Reimplementations/copied from libnl3/genl
|
||||
*****************************************************************************/
|
||||
return NLA_HDRLEN + payload;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nla_total_size (int payload)
|
||||
{
|
||||
return NLA_ALIGN (nla_attr_size (payload));
|
||||
}
|
||||
|
||||
static inline int
|
||||
nla_padlen (int payload)
|
||||
{
|
||||
return nla_total_size(payload) - nla_attr_size(payload);
|
||||
}
|
||||
|
||||
struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen);
|
||||
|
||||
static inline int
|
||||
nla_len (const struct nlattr *nla)
|
||||
{
|
||||
return nla->nla_len - NLA_HDRLEN;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nla_type (const struct nlattr *nla)
|
||||
{
|
||||
return nla->nla_type & NLA_TYPE_MASK;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
nla_data (const struct nlattr *nla)
|
||||
{
|
||||
nm_assert (nla);
|
||||
return (char *) nla + NLA_HDRLEN;
|
||||
}
|
||||
|
||||
static inline uint8_t
|
||||
nla_get_u8 (const struct nlattr *nla)
|
||||
{
|
||||
return *(const uint8_t *) nla_data (nla);
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
nla_get_u16 (const struct nlattr *nla)
|
||||
{
|
||||
return *(const uint16_t *) nla_data (nla);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nla_get_u32(const struct nlattr *nla)
|
||||
{
|
||||
return *(const uint32_t *) nla_data (nla);
|
||||
}
|
||||
|
||||
uint64_t nla_get_u64 (const struct nlattr *nla);
|
||||
|
||||
static inline char *
|
||||
nla_get_string (const struct nlattr *nla)
|
||||
{
|
||||
return (char *) nla_data (nla);
|
||||
}
|
||||
|
||||
size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize);
|
||||
|
||||
int nla_memcpy (void *dest, const struct nlattr *src, int count);
|
||||
|
||||
int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data);
|
||||
|
||||
static inline int
|
||||
nla_put_string (struct nl_msg *msg, int attrtype, const char *str)
|
||||
{
|
||||
return nla_put(msg, attrtype, strlen(str) + 1, str);
|
||||
}
|
||||
|
||||
#define NLA_PUT(msg, attrtype, attrlen, data) \
|
||||
do { \
|
||||
if (nla_put(msg, attrtype, attrlen, data) < 0) \
|
||||
goto nla_put_failure; \
|
||||
} while(0)
|
||||
|
||||
#define NLA_PUT_TYPE(msg, type, attrtype, value) \
|
||||
do { \
|
||||
type __tmp = value; \
|
||||
NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \
|
||||
} while(0)
|
||||
|
||||
#define NLA_PUT_U8(msg, attrtype, value) \
|
||||
NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
|
||||
|
||||
#define NLA_PUT_U16(msg, attrtype, value) \
|
||||
NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
|
||||
|
||||
#define NLA_PUT_U32(msg, attrtype, value) \
|
||||
NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
|
||||
|
||||
#define NLA_PUT_U64(msg, attrtype, value) \
|
||||
NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
|
||||
|
||||
#define NLA_PUT_STRING(msg, attrtype, value) \
|
||||
NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value)
|
||||
|
||||
struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype);
|
||||
|
||||
static inline int
|
||||
nla_ok (const struct nlattr *nla, int remaining)
|
||||
{
|
||||
return remaining >= sizeof(*nla) &&
|
||||
nla->nla_len >= sizeof(*nla) &&
|
||||
nla->nla_len <= remaining;
|
||||
}
|
||||
|
||||
static inline struct nlattr *
|
||||
nla_next(const struct nlattr *nla, int *remaining)
|
||||
{
|
||||
int totlen = NLA_ALIGN(nla->nla_len);
|
||||
|
||||
*remaining -= totlen;
|
||||
return (struct nlattr *) ((char *) nla + totlen);
|
||||
}
|
||||
|
||||
#define nla_for_each_attr(pos, head, len, rem) \
|
||||
for (pos = head, rem = len; \
|
||||
nla_ok(pos, rem); \
|
||||
pos = nla_next(pos, &(rem)))
|
||||
|
||||
#define nla_for_each_nested(pos, nla, rem) \
|
||||
for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \
|
||||
nla_ok(pos, rem); \
|
||||
pos = nla_next(pos, &(rem)))
|
||||
|
||||
void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr);
|
||||
struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype);
|
||||
int nla_nest_end (struct nl_msg *msg, struct nlattr *start);
|
||||
|
||||
int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
|
||||
const struct nla_policy *policy);
|
||||
|
||||
static inline int
|
||||
nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct nl_msg *nlmsg_alloc (void);
|
||||
|
||||
struct nl_msg *nlmsg_alloc_size (size_t max);
|
||||
|
||||
struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr);
|
||||
|
||||
struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr);
|
||||
|
||||
struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags);
|
||||
|
||||
void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad);
|
||||
|
||||
int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad);
|
||||
|
||||
void nlmsg_free (struct nl_msg *msg);
|
||||
|
||||
static inline int
|
||||
nlmsg_size (int payload)
|
||||
{
|
||||
nm_assert (payload >= 0 && payload < G_MAXINT - NLMSG_HDRLEN - 4);
|
||||
return NLMSG_HDRLEN + payload;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nlmsg_total_size (int payload)
|
||||
{
|
||||
return NLMSG_ALIGN (nlmsg_size (payload));
|
||||
}
|
||||
|
||||
static inline int
|
||||
nlmsg_ok (const struct nlmsghdr *nlh, int remaining)
|
||||
{
|
||||
return (remaining >= (int)sizeof(struct nlmsghdr) &&
|
||||
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
|
||||
nlh->nlmsg_len <= remaining);
|
||||
}
|
||||
|
||||
static inline struct nlmsghdr *
|
||||
nlmsg_next (struct nlmsghdr *nlh, int *remaining)
|
||||
{
|
||||
int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
|
||||
|
||||
*remaining -= totlen;
|
||||
|
||||
return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
|
||||
}
|
||||
|
||||
int nlmsg_get_proto (struct nl_msg *msg);
|
||||
void nlmsg_set_proto (struct nl_msg *msg, int protocol);
|
||||
|
||||
void nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr);
|
||||
|
||||
struct ucred *nlmsg_get_creds (struct nl_msg *msg);
|
||||
void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds);
|
||||
|
||||
static inline void
|
||||
_nm_auto_nl_msg_cleanup (struct nl_msg **ptr)
|
||||
{
|
||||
nlmsg_free (*ptr);
|
||||
}
|
||||
#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
|
||||
|
||||
static inline void *
|
||||
nlmsg_data (const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (unsigned char *) nlh + NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
nlmsg_tail (const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
|
||||
}
|
||||
|
||||
struct nlmsghdr *nlmsg_hdr (struct nl_msg *n);
|
||||
|
||||
static inline int
|
||||
nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
|
||||
{
|
||||
if (nlh->nlmsg_len < nlmsg_size (hdrlen))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nlmsg_datalen (const struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlh->nlmsg_len - NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen)
|
||||
{
|
||||
return NM_MAX ((int) (nlmsg_datalen (nlh) - NLMSG_ALIGN (hdrlen)), 0);
|
||||
}
|
||||
|
||||
static inline struct nlattr *
|
||||
nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen)
|
||||
{
|
||||
unsigned char *data = nlmsg_data(nlh);
|
||||
return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
|
||||
}
|
||||
|
||||
static inline struct nlattr *
|
||||
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 hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy);
|
||||
|
||||
struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq,
|
||||
int type, int payload, int flags);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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);
|
||||
|
|
@ -69,16 +404,85 @@ int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen);
|
|||
int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy);
|
||||
|
||||
/*****************************************************************************
|
||||
* helpers
|
||||
*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline void
|
||||
_nm_auto_nl_msg_cleanup (struct nl_msg **ptr)
|
||||
{
|
||||
nlmsg_free (*ptr);
|
||||
}
|
||||
#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
|
||||
#define NL_AUTO_PORT 0
|
||||
#define NL_AUTO_SEQ 0
|
||||
|
||||
struct nl_sock;
|
||||
|
||||
struct nl_sock *nl_socket_alloc (void);
|
||||
|
||||
void nl_socket_free (struct nl_sock *sk);
|
||||
|
||||
int nl_socket_get_fd (const struct nl_sock *sk);
|
||||
|
||||
struct sockaddr_nl *nlmsg_get_dst (struct nl_msg *msg);
|
||||
|
||||
size_t nl_socket_get_msg_buf_size (struct nl_sock *sk);
|
||||
int nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize);
|
||||
|
||||
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);
|
||||
|
||||
void nl_socket_disable_msg_peek (struct nl_sock *sk);
|
||||
|
||||
uint32_t nl_socket_get_local_port (const struct nl_sock *sk);
|
||||
|
||||
int nl_socket_add_memberships (struct nl_sock *sk, int group, ...);
|
||||
|
||||
int nl_connect (struct nl_sock *sk, int protocol);
|
||||
|
||||
int nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
|
||||
unsigned char **buf, struct ucred **creds);
|
||||
|
||||
int nl_send (struct nl_sock *sk, struct nl_msg *msg);
|
||||
|
||||
int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum nl_cb_action {
|
||||
/* Proceed with wathever would come next */
|
||||
NL_OK,
|
||||
/* Skip this message */
|
||||
NL_SKIP,
|
||||
/* Stop parsing altogether and discard remaining messages */
|
||||
NL_STOP,
|
||||
};
|
||||
|
||||
typedef int (*nl_recvmsg_msg_cb_t) (struct nl_msg *msg, void *arg);
|
||||
|
||||
typedef int (*nl_recvmsg_err_cb_t) (struct sockaddr_nl *nla,
|
||||
struct nlmsgerr *nlerr, void *arg);
|
||||
|
||||
struct nl_cb {
|
||||
nl_recvmsg_msg_cb_t valid_cb;
|
||||
void * valid_arg;
|
||||
|
||||
nl_recvmsg_msg_cb_t finish_cb;
|
||||
void * finish_arg;
|
||||
|
||||
nl_recvmsg_msg_cb_t ack_cb;
|
||||
void * ack_arg;
|
||||
|
||||
nl_recvmsg_err_cb_t err_cb;
|
||||
void * err_arg;
|
||||
};
|
||||
|
||||
int nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr);
|
||||
|
||||
int nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen);
|
||||
|
||||
void nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg);
|
||||
|
||||
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);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -79,55 +79,41 @@ probe_response (struct nl_msg *msg, void *arg)
|
|||
static int
|
||||
genl_ctrl_resolve (struct nl_sock *sk, const char *name)
|
||||
{
|
||||
struct nl_msg *msg;
|
||||
struct nl_cb *cb, *orig;
|
||||
int rc;
|
||||
int result = -NLE_OBJ_NOTFOUND;
|
||||
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
||||
int result = -ENOMEM;
|
||||
gint32 response_data = -1;
|
||||
|
||||
if (!(orig = nl_socket_get_cb (sk)))
|
||||
goto out;
|
||||
|
||||
cb = nl_cb_clone (orig);
|
||||
nl_cb_put (orig);
|
||||
if (!cb)
|
||||
goto out;
|
||||
const struct nl_cb cb = {
|
||||
.valid_cb = probe_response,
|
||||
.valid_arg = &response_data,
|
||||
};
|
||||
|
||||
msg = nlmsg_alloc ();
|
||||
if (!msg)
|
||||
goto out_cb_free;
|
||||
|
||||
if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
|
||||
0, 0, CTRL_CMD_GETFAMILY, 1))
|
||||
goto out_msg_free;
|
||||
goto out;
|
||||
|
||||
if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
|
||||
goto out_msg_free;
|
||||
goto out;
|
||||
|
||||
rc = nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response, &response_data);
|
||||
if (rc < 0)
|
||||
goto out_msg_free;
|
||||
result = nl_send_auto (sk, msg);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
|
||||
rc = nl_send_auto_complete (sk, msg);
|
||||
if (rc < 0)
|
||||
goto out_msg_free;
|
||||
|
||||
rc = nl_recvmsgs (sk, cb);
|
||||
if (rc < 0)
|
||||
goto out_msg_free;
|
||||
result = nl_recvmsgs (sk, &cb);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
|
||||
/* If search was successful, request may be ACKed after data */
|
||||
rc = nl_wait_for_ack (sk);
|
||||
if (rc < 0)
|
||||
goto out_msg_free;
|
||||
result = nl_wait_for_ack (sk, NULL);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
|
||||
if (response_data > 0)
|
||||
result = response_data;
|
||||
else
|
||||
result = -ENOENT;
|
||||
|
||||
out_msg_free:
|
||||
nlmsg_free (msg);
|
||||
out_cb_free:
|
||||
nl_cb_put (cb);
|
||||
out:
|
||||
if (result >= 0)
|
||||
_LOGD (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result);
|
||||
|
|
@ -143,7 +129,6 @@ out:
|
|||
typedef struct {
|
||||
WifiData parent;
|
||||
struct nl_sock *nl_sock;
|
||||
struct nl_cb *nl_cb;
|
||||
guint32 *freqs;
|
||||
int id;
|
||||
int num_freqs;
|
||||
|
|
@ -178,19 +163,16 @@ error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
|
|||
static struct nl_msg *
|
||||
_nl80211_alloc_msg (int id, int ifindex, int phy, guint32 cmd, guint32 flags)
|
||||
{
|
||||
struct nl_msg *msg;
|
||||
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
||||
|
||||
msg = nlmsg_alloc ();
|
||||
if (msg) {
|
||||
genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0);
|
||||
NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex);
|
||||
if (phy != -1)
|
||||
NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy);
|
||||
}
|
||||
return msg;
|
||||
genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0);
|
||||
NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex);
|
||||
if (phy != -1)
|
||||
NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy);
|
||||
return g_steal_pointer (&msg);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free (msg);
|
||||
nla_put_failure:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -203,39 +185,36 @@ nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags)
|
|||
/* NOTE: this function consumes 'msg' */
|
||||
static int
|
||||
_nl80211_send_and_recv (struct nl_sock *nl_sock,
|
||||
struct nl_cb *nl_cb,
|
||||
struct nl_msg *msg,
|
||||
int (*valid_handler) (struct nl_msg *, void *),
|
||||
void *valid_data)
|
||||
{
|
||||
struct nl_cb *cb;
|
||||
int err, done;
|
||||
nm_auto_nlmsg struct nl_msg *msg_free = msg;
|
||||
int err;
|
||||
int done = 0;
|
||||
const struct nl_cb cb = {
|
||||
.err_cb = error_handler,
|
||||
.err_arg = &done,
|
||||
.finish_cb = finish_handler,
|
||||
.finish_arg = &done,
|
||||
.ack_cb = ack_handler,
|
||||
.ack_arg = &done,
|
||||
.valid_cb = valid_handler,
|
||||
.valid_arg = valid_data,
|
||||
};
|
||||
|
||||
g_return_val_if_fail (msg != NULL, -ENOMEM);
|
||||
|
||||
cb = nl_cb_clone (nl_cb);
|
||||
if (!cb) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nl_send_auto_complete (nl_sock, msg);
|
||||
err = nl_send_auto (nl_sock, msg);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
done = 0;
|
||||
nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done);
|
||||
nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done);
|
||||
nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done);
|
||||
if (valid_handler)
|
||||
nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data);
|
||||
return err;
|
||||
|
||||
/* Loop until one of our NL callbacks says we're done; on success
|
||||
* done will be 1, on error it will be < 0.
|
||||
*/
|
||||
while (!done) {
|
||||
err = nl_recvmsgs (nl_sock, cb);
|
||||
if (err && err != -NLE_AGAIN) {
|
||||
err = nl_recvmsgs (nl_sock, &cb);
|
||||
if (err < 0 && err != -EAGAIN) {
|
||||
/* Kernel scan list can change while we are dumping it, as new scan
|
||||
* results from H/W can arrive. BSS info is assured to be consistent
|
||||
* and we don't need consistent view of whole scan list. Hence do
|
||||
|
|
@ -250,12 +229,9 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (err == 0 && done < 0)
|
||||
err = done;
|
||||
|
||||
out:
|
||||
nl_cb_put (cb);
|
||||
nlmsg_free (msg);
|
||||
if (err >= 0 && done < 0)
|
||||
err = done;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +241,7 @@ nl80211_send_and_recv (WifiDataNl80211 *nl80211,
|
|||
int (*valid_handler) (struct nl_msg *, void *),
|
||||
void *valid_data)
|
||||
{
|
||||
return _nl80211_send_and_recv (nl80211->nl_sock, nl80211->nl_cb, msg,
|
||||
return _nl80211_send_and_recv (nl80211->nl_sock, msg,
|
||||
valid_handler, valid_data);
|
||||
}
|
||||
|
||||
|
|
@ -276,8 +252,6 @@ wifi_nl80211_deinit (WifiData *parent)
|
|||
|
||||
if (nl80211->nl_sock)
|
||||
nl_socket_free (nl80211->nl_sock);
|
||||
if (nl80211->nl_cb)
|
||||
nl_cb_put (nl80211->nl_cb);
|
||||
g_free (nl80211->freqs);
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +300,7 @@ wifi_nl80211_get_mode (WifiData *data)
|
|||
msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_INTERFACE, 0);
|
||||
|
||||
if (nl80211_send_and_recv (nl80211, msg, nl80211_iface_info_handler,
|
||||
&iface_info) < 0)
|
||||
&iface_info) < 0)
|
||||
return NM_802_11_MODE_UNKNOWN;
|
||||
|
||||
return iface_info.mode;
|
||||
|
|
@ -356,7 +330,7 @@ wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode)
|
|||
}
|
||||
|
||||
err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
|
||||
return err ? FALSE : TRUE;
|
||||
return err >= 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free (msg);
|
||||
|
|
@ -374,7 +348,7 @@ wifi_nl80211_set_powersave (WifiData *data, guint32 powersave)
|
|||
NLA_PUT_U32 (msg, NL80211_ATTR_PS_STATE,
|
||||
powersave == 1 ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
|
||||
err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
|
||||
return err ? FALSE : TRUE;
|
||||
return err >= 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free (msg);
|
||||
|
|
@ -702,7 +676,7 @@ wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running)
|
|||
}
|
||||
|
||||
err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
|
||||
return err ? FALSE : TRUE;
|
||||
return err >= 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free (msg);
|
||||
|
|
@ -991,10 +965,6 @@ wifi_nl80211_init (int ifindex)
|
|||
if (nl80211->id < 0)
|
||||
goto error;
|
||||
|
||||
nl80211->nl_cb = nl_cb_alloc (NL_CB_DEFAULT);
|
||||
if (nl80211->nl_cb == NULL)
|
||||
goto error;
|
||||
|
||||
nl80211->phy = -1;
|
||||
|
||||
msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WIPHY, 0);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue