summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-02-16 17:05:32 +0100
committerThomas Haller <thaller@redhat.com>2018-02-21 12:08:46 +0100
commita7bda2ed12b958fd605e78a2512aa7246046983a (patch)
treeb25da10ed9139b2ca8a4f9bfaf30c1d1b427454b
parent9071e8cc050cef531420534f470347d2d9616143 (diff)
netlink: simplify netlink callback handling
With libnl3, each socket has it's own callback structure. One would often take that callback structure, clone it, modify it and invoke a receive operation with it. We don't need this complexity. We got rid of all default handlers, hence, by default all callbacks are unset. The only callbacks that are set, are those that we specify immediately before invoking the receive operation. Just pass the callback structure at that point. Also, no more ref-counting, and cloning of the callback structure. It is so simple, just stack allocate one if you need it.
-rw-r--r--src/platform/nm-netlink.c228
-rw-r--r--src/platform/nm-netlink.h49
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c89
3 files changed, 92 insertions, 274 deletions
diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c
index 0770e0be16..cf2e9eaff9 100644
--- a/src/platform/nm-netlink.c
+++ b/src/platform/nm-netlink.c
@@ -59,7 +59,6 @@ struct nl_sock {
unsigned int s_seq_next;
unsigned int s_seq_expect;
int s_flags;
- struct nl_cb * s_cb;
size_t s_bufsize;
};
@@ -804,134 +803,14 @@ genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
/*****************************************************************************/
-struct nl_cb {
- nl_recvmsg_msg_cb_t cb_set[NL_CB_TYPE_MAX+1];
- void * cb_args[NL_CB_TYPE_MAX+1];
-
- nl_recvmsg_err_cb_t cb_err;
- void * cb_err_arg;
-
- int cb_refcnt;
-};
-
-/*****************************************************************************/
-
-static int
-nl_cb_call (const struct nl_cb *cb, enum nl_cb_type type, struct nl_msg *msg)
-{
- return cb->cb_set[type](msg, cb->cb_args[type]);
-}
-
-struct nl_cb *
-nl_cb_alloc (enum nl_cb_kind kind)
-{
- int i;
- struct nl_cb *cb;
-
- if ((unsigned int) kind > NL_CB_KIND_MAX)
- return NULL;
-
- cb = calloc(1, sizeof(*cb));
- if (!cb)
- return NULL;
-
- cb->cb_refcnt = 1;
-
- for (i = 0; i <= NL_CB_TYPE_MAX; i++)
- nl_cb_set(cb, i, kind, NULL, NULL);
-
- nl_cb_err(cb, kind, NULL, NULL);
-
- return cb;
-}
-
-struct nl_cb *nl_cb_clone(struct nl_cb *orig)
-{
- struct nl_cb *cb;
-
- cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!cb)
- return NULL;
-
- memcpy(cb, orig, sizeof(*orig));
- cb->cb_refcnt = 1;
-
- return cb;
-}
-
-struct nl_cb *nl_cb_get(struct nl_cb *cb)
-{
- cb->cb_refcnt++;
-
- return cb;
-}
-
-void nl_cb_put(struct nl_cb *cb)
-{
- if (!cb)
- return;
-
- if (cb->cb_refcnt <= 0)
- g_return_if_reached ();
-
- cb->cb_refcnt--;
-
- if (cb->cb_refcnt <= 0)
- free(cb);
-}
-
-int
-nl_cb_err (struct nl_cb *cb, enum nl_cb_kind kind,
- nl_recvmsg_err_cb_t func, void *arg)
-{
- if ((unsigned int) kind > NL_CB_KIND_MAX)
- g_return_val_if_reached (-NLE_BUG);
-
- if (kind == NL_CB_CUSTOM) {
- cb->cb_err = func;
- cb->cb_err_arg = arg;
- } else {
- cb->cb_err = NULL;
- cb->cb_err_arg = arg;
- }
-
- return 0;
-}
-
-int
-nl_cb_set (struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
- nl_recvmsg_msg_cb_t func, void *arg)
-{
- if ((unsigned int) type > NL_CB_TYPE_MAX)
- g_return_val_if_reached (-NLE_BUG);
-
- if ((unsigned int) kind > NL_CB_KIND_MAX)
- g_return_val_if_reached (-NLE_BUG);
-
- if (kind == NL_CB_CUSTOM) {
- cb->cb_set[type] = func;
- cb->cb_args[type] = arg;
- } else {
- cb->cb_set[type] = NULL;
- cb->cb_args[type] = arg;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static struct nl_sock *
-_alloc_socket (struct nl_cb *cb)
+struct nl_sock *
+nl_socket_alloc (void)
{
struct nl_sock *sk;
- sk = calloc(1, sizeof(*sk));
- if (!sk)
- return NULL;
+ sk = g_slice_new0 (struct nl_sock);
sk->s_fd = -1;
- sk->s_cb = nl_cb_get(cb);
sk->s_local.nl_family = AF_NETLINK;
sk->s_peer.nl_family = AF_NETLINK;
sk->s_seq_expect = sk->s_seq_next = time(NULL);
@@ -939,24 +818,6 @@ _alloc_socket (struct nl_cb *cb)
return sk;
}
-struct nl_sock *
-nl_socket_alloc (void)
-{
- struct nl_cb *cb;
- struct nl_sock *sk;
-
- cb = nl_cb_alloc (NL_CB_DEFAULT);
- if (!cb)
- return NULL;
-
- /* will increment cb reference count on success */
- sk = _alloc_socket(cb);
-
- nl_cb_put(cb);
-
- return sk;
-}
-
void
nl_socket_free (struct nl_sock *sk)
{
@@ -964,16 +825,8 @@ nl_socket_free (struct nl_sock *sk)
return;
if (sk->s_fd >= 0)
- close(sk->s_fd);
-
- nl_cb_put(sk->s_cb);
- free(sk);
-}
-
-struct nl_cb *
-nl_socket_get_cb (const struct nl_sock *sk)
-{
- return nl_cb_get(sk->s_cb);
+ nm_close (sk->s_fd);
+ g_slice_free (struct nl_sock, sk);
}
int
@@ -1170,41 +1023,50 @@ errout:
/*****************************************************************************/
+static void
+_cb_init (struct nl_cb *dst, const struct nl_cb *src)
+{
+ nm_assert (dst);
+
+ if (src)
+ *dst = *src;
+ else
+ memset (dst, 0, sizeof (*dst));
+}
+
static int ack_wait_handler(struct nl_msg *msg, void *arg)
{
return NL_STOP;
}
int
-nl_wait_for_ack(struct nl_sock *sk)
+nl_wait_for_ack (struct nl_sock *sk,
+ const struct nl_cb *cb)
{
- int err;
- struct nl_cb *cb;
+ struct nl_cb cb2;
- cb = nl_cb_clone(sk->s_cb);
- if (cb == NULL)
- return -ENOMEM;
-
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
- err = nl_recvmsgs(sk, cb);
- nl_cb_put(cb);
-
- return err;
+ _cb_init (&cb2, cb);
+ cb2.ack_cb = ack_wait_handler;
+ return nl_recvmsgs (sk, &cb2);
}
#define NL_CB_CALL(cb, type, msg) \
do { \
- err = nl_cb_call(cb, type, msg); \
- switch (err) { \
- case NL_OK: \
- err = 0; \
- break; \
- case NL_SKIP: \
- goto skip; \
- case NL_STOP: \
- goto stop; \
- default: \
- goto out; \
+ const struct nl_cb *_cb = (cb); \
+ \
+ if (_cb->type##_cb) { \
+ err = _cb->type##_cb ((msg), _cb->type##_arg); \
+ switch (err) { \
+ case NL_OK: \
+ err = 0; \
+ break; \
+ case NL_SKIP: \
+ goto skip; \
+ case NL_STOP: \
+ goto stop; \
+ default: \
+ goto out; \
+ } \
} \
} while (0)
@@ -1280,8 +1142,7 @@ continue_reading:
* this action by skipping this packet. */
if (hdr->nlmsg_type == NLMSG_DONE) {
multipart = 0;
- if (cb->cb_set[NL_CB_FINISH])
- NL_CB_CALL(cb, NL_CB_FINISH, msg);
+ NL_CB_CALL(cb, finish, msg);
}
/* Message to be ignored, the default action is to
@@ -1313,9 +1174,9 @@ continue_reading:
}
if (e->error) {
/* Error message reported back from kernel. */
- if (cb->cb_err) {
- err = cb->cb_err(&nla, e,
- cb->cb_err_arg);
+ if (cb->err_cb) {
+ err = cb->err_cb (&nla, e,
+ cb->err_arg);
if (err < 0)
goto out;
else if (err == NL_SKIP)
@@ -1328,14 +1189,13 @@ continue_reading:
err = -e->error;
goto out;
}
- } else if (cb->cb_set[NL_CB_ACK])
- NL_CB_CALL(cb, NL_CB_ACK, msg);
+ } else
+ NL_CB_CALL(cb, ack, msg);
} else {
/* Valid message (not checking for MULTIPART bit to
* get along with broken kernels. NL_SKIP has no
* effect on this. */
- if (cb->cb_set[NL_CB_VALID])
- NL_CB_CALL(cb, NL_CB_VALID, msg);
+ NL_CB_CALL(cb, valid, msg);
}
skip:
err = 0;
diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h
index 2e0af4bc57..9c89748009 100644
--- a/src/platform/nm-netlink.h
+++ b/src/platform/nm-netlink.h
@@ -450,8 +450,6 @@ int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg);
/*****************************************************************************/
-struct nl_cb;
-
enum nl_cb_action {
/* Proceed with wathever would come next */
NL_OK,
@@ -461,48 +459,24 @@ enum nl_cb_action {
NL_STOP,
};
-enum nl_cb_kind {
- /* Default handlers (quiet) */
- NL_CB_DEFAULT,
- /* Customized handler specified by the user */
- NL_CB_CUSTOM,
- __NL_CB_KIND_MAX,
-};
-
-#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1)
-
-enum nl_cb_type {
- /* Message is valid */
- NL_CB_VALID,
- /* Last message in a series of multi part messages received */
- NL_CB_FINISH,
- /* Message is an acknowledge */
- NL_CB_ACK,
- __NL_CB_TYPE_MAX,
-};
-
-#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1)
-
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_cb_alloc (enum nl_cb_kind kind);
-
-struct nl_cb *nl_cb_clone (struct nl_cb *orig);
-
-struct nl_cb *nl_cb_get (struct nl_cb *cb);
+struct nl_cb {
+ nl_recvmsg_msg_cb_t valid_cb;
+ void * valid_arg;
-void nl_cb_put (struct nl_cb *cb);
+ nl_recvmsg_msg_cb_t finish_cb;
+ void * finish_arg;
-int nl_cb_set (struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
- nl_recvmsg_msg_cb_t func, void *arg);
+ nl_recvmsg_msg_cb_t ack_cb;
+ void * ack_arg;
-int nl_cb_err (struct nl_cb *cb, enum nl_cb_kind kind,
- nl_recvmsg_err_cb_t func, void *arg);
-
-struct nl_cb *nl_socket_get_cb (const struct nl_sock *sk);
+ nl_recvmsg_err_cb_t err_cb;
+ void * err_arg;
+};
int nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr);
@@ -512,7 +486,8 @@ 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);
+int nl_wait_for_ack (struct nl_sock *sk,
+ const struct nl_cb *cb);
/*****************************************************************************/
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index d90e99c49a..ed843bcea1 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -79,55 +79,43 @@ 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 = -ENOENT;
+ 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;
+ goto out;
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;
-
- rc = nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response, &response_data);
- if (rc < 0)
- goto out_msg_free;
+ goto out;
- rc = nl_send_auto (sk, msg);
- if (rc < 0)
- goto out_msg_free;
+ result = nl_send_auto (sk, msg);
+ if (result < 0)
+ goto out;
- 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);
@@ -206,33 +194,31 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock,
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_alloc (NL_CB_DEFAULT);
- if (!cb) {
- err = -ENOMEM;
- goto out;
- }
-
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);
+ 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
@@ -248,12 +234,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);
return err;
}