platform/netlink: merge branch 'th/netlink' (#67)

https://github.com/NetworkManager/NetworkManager/pull/67
This commit is contained in:
Thomas Haller 2018-02-21 12:12:36 +01:00
commit 3d987fe2db
12 changed files with 1882 additions and 376 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -30,7 +30,6 @@ yum install \
jansson-devel \
libcurl-devel \
libndp-devel \
libnl3-devel \
libpsl-devel \
libselinux-devel \
libtool \

View file

@ -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

View file

@ -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

View file

@ -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())

View file

@ -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
]

View file

@ -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

View file

@ -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);
/*****************************************************************************/

View file

@ -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);