summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky.perez-gonzalez>2008-12-05 10:36:28 -0800
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2008-12-05 10:36:28 -0800
commitb3125da65abf030482901104f74578ac49010d47 (patch)
tree2c7e1ec3caed3f69a964a3ccee6bf20ac124dddf /lib
parent3740ecc83b38a2395c4d107f2b842976a1edb7a4 (diff)
libwimaxll: (fb Johannes Berg) fix handling of ack/nlerr in op-open
We were not handling the thing properly and thus it was working only by chance. We were missing the nlerr as reponses to messages. The callbacks need to be setup to listen for the message we are waiting for, ack and nlerr. And then we need to call nl_recvmsgs() until the ack / or nlerr handler have been seen. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/op-open.c84
1 files changed, 74 insertions, 10 deletions
diff --git a/lib/op-open.c b/lib/op-open.c
index 53fcec9..2674d8a 100644
--- a/lib/op-open.c
+++ b/lib/op-open.c
@@ -240,8 +240,64 @@ int wimaxll_gnl_rp_ifinfo_error_cb(struct sockaddr_nl *nla,
nla, nlerr, nlerr->error, _ctx);
if (ctx->gnl.result == -EINPROGRESS)
ctx->gnl.result = nlerr->error;
- d_fnend(7, wmx, "(nla %p nlnerr %p [%d] ctx %p) = %d\n",
- nla, nlerr, nlerr->error, _ctx, NL_STOP);
+ ctx->gnl.msg_done = 1;
+ d_fnend(7, wmx, "(nla %p nlnerr %p [%d] ctx %p) = NL_STOP\n",
+ nla, nlerr, nlerr->error, _ctx);
+ return NL_STOP;
+}
+
+
+static
+int wimaxll_gnl_rp_ifinfo_ack_cb(struct nl_msg *msg, void *_ctx)
+{
+ int result;
+ struct nlmsghdr *nl_hdr;
+ struct nlmsgerr *nl_err;
+ size_t size = nlmsg_len(nlmsg_hdr(msg));
+ struct wimaxll_ifinfo_context *ctx = _ctx;
+
+ d_fnstart(7, NULL, "(msg %p ctx %p)\n", msg, ctx);
+ nl_hdr = nlmsg_hdr(msg);
+ size = nlmsg_len(nl_hdr);
+ nl_err = nlmsg_data(nl_hdr);
+
+ if (size < sizeof(*nl_err)) {
+ wimaxll_msg(NULL, "E: netlink ack: buffer too small "
+ "(%zu vs %zu expected)\n",
+ size, sizeof(*nl_hdr) + sizeof(*nl_err));
+ result = -EIO;
+ goto error_ack_short;
+ }
+ d_printf(4, NULL, "netlink ack: nlmsghdr len %u type %u flags 0x%04x "
+ "seq 0x%x pid %u\n", nl_hdr->nlmsg_len, nl_hdr->nlmsg_type,
+ nl_hdr->nlmsg_flags, nl_hdr->nlmsg_seq, nl_hdr->nlmsg_pid);
+ if (nl_hdr->nlmsg_type != NLMSG_ERROR) {
+ wimaxll_msg(NULL, "E: netlink ack: message is not an ack but "
+ "type %u\n", nl_hdr->nlmsg_type);
+ result = -EBADE;
+ goto error_bad_type;
+ }
+ d_printf(4, NULL, "netlink ack: nlmsgerr error %d for "
+ "nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
+ nl_err->error,
+ nl_err->msg.nlmsg_len, nl_err->msg.nlmsg_type,
+ nl_err->msg.nlmsg_flags, nl_err->msg.nlmsg_seq,
+ nl_err->msg.nlmsg_pid);
+ if (ctx->gnl.result == -EINPROGRESS) {
+ ctx->gnl.result = nl_err->error;
+ d_printf(4, NULL, "netlink ack: updating gnl.result\n");
+ }
+ else
+ d_printf(4, NULL, "netlink ack: Not updating gnl.result (%d)\n",
+ ctx->gnl.result);
+
+ if (nl_err->error < 0)
+ d_printf(2, NULL, "D: netlink ack: received netlink error %d\n",
+ nl_err->error);
+ ctx->gnl.msg_done = 1;
+error_ack_short:
+error_bad_type:
+ d_fnend(7, NULL, "(msg %p ctx %p) = NL_STOP\n", msg, ctx);
return NL_STOP;
}
@@ -368,22 +424,30 @@ int __wimaxll_cmd_open(struct wimaxll_handle *wmx)
*/
ctx.gnl.wmx = wmx;
ctx.gnl.result = -EINPROGRESS;
+ ctx.gnl.msg_done = 0;
cb = nl_socket_get_cb(wmx->nlh_tx);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
wimaxll_gnl_rp_ifinfo_cb, &ctx);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
+ wimaxll_gnl_rp_ifinfo_ack_cb, &ctx);
nl_cb_err(cb, NL_CB_CUSTOM, wimaxll_gnl_rp_ifinfo_error_cb, &ctx.gnl);
- nl_recvmsgs_default(wmx->nlh_tx);
- nl_cb_put(cb);
+ do
+ result = nl_recvmsgs(wmx->nlh_tx, cb);
+ while (ctx.gnl.msg_done == 0 && result >= 0);
result = ctx.gnl.result;
- if (result >= 0)
- nl_wait_for_ack(wmx->nlh_tx);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
+ nl_cb_put(cb);
if (result == -EINPROGRESS)
wimaxll_msg(wmx, "E: %s: the kernel didn't reply with a "
"WIMAX_GNL_RP_IFINFO message\n", __func__);
- d_printf(1, wmx, "D: processing result is %d\n", result);
-
- /* All fine and dandy, commit the data */
- memcpy(wmx->gnl_mc, ctx.gnl_mc, sizeof(ctx.gnl_mc));
+ else if (result >= 0) {
+ d_printf(1, wmx, "D: processing result is %d\n", result);
+ /* All fine and dandy, commit the data */
+ memcpy(wmx->gnl_mc, ctx.gnl_mc, sizeof(ctx.gnl_mc));
+ } else
+ d_printf(1, wmx, "E: rp_ifinfo failed %d\n", result);
error_msg_prep:
error_msg_send:
nlmsg_free(msg);