summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/internal.h4
-rw-r--r--lib/op-msg.c17
-rw-r--r--lib/op-open.c70
-rw-r--r--lib/op-reset.c5
-rw-r--r--lib/op-rfkill.c4
-rw-r--r--lib/re-state-change.c20
-rw-r--r--lib/wimax.c3
7 files changed, 90 insertions, 33 deletions
diff --git a/lib/internal.h b/lib/internal.h
index 392737f..a5cd272 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -192,7 +192,9 @@ void wimaxll_cb_maybe_set_result(struct wimaxll_cb_ctx *ctx, int val)
* wimaxll_msg_write() and \c wimaxll_msg_read() at the same time in a
* multithreaded environment, for example.
*
- * \param ifidx Interface Index (of the network interface)
+ * \param ifidx Interface Index (of the network interface); if 0, the
+ * interface name will be \c "any" and this means that this handle
+ * works for \e any WiMAX interface.
* \param gnl_family_id Generic Netlink Family ID assigned to the
* device; we maintain it here (for each interface) because we
* want to discover it every time we open. This solves the case of
diff --git a/lib/op-msg.c b/lib/op-msg.c
index 1b15b75..c3c9426 100644
--- a/lib/op-msg.c
+++ b/lib/op-msg.c
@@ -162,6 +162,7 @@ int wimaxll_gnl_handle_msg_to_user(struct wimaxll_handle *wmx,
struct genlmsghdr *gnl_hdr;
struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
const char *pipe_name;
+ unsigned dest_ifidx;
void *data;
d_fnstart(7, wmx, "(wmx %p msg %p)\n", wmx, msg);
@@ -185,7 +186,8 @@ int wimaxll_gnl_handle_msg_to_user(struct wimaxll_handle *wmx,
result = -EINVAL;
goto error_no_attrs;
}
- if (wmx->ifidx != nla_get_u32(tb[WIMAX_GNL_MSG_IFIDX])) {
+ dest_ifidx = nla_get_u32(tb[WIMAX_GNL_MSG_IFIDX]);
+ if (wmx->ifidx > 0 && wmx->ifidx != dest_ifidx) {
result = -ENODEV;
goto error_no_attrs;
}
@@ -211,9 +213,18 @@ int wimaxll_gnl_handle_msg_to_user(struct wimaxll_handle *wmx,
size, pipe_name);
d_dump(2, wmx, data, size);
+ /* If this is an "any" handle, set the wmx->ifidx to the
+ * received one so the callback can now where did the thing
+ * come from. Will be restored.
+ */
+ if (wmx->ifidx == 0) {
+ wmx->ifidx = dest_ifidx;
+ dest_ifidx = 0;
+ }
/* Now execute the callback for handling msg-to-user */
result = wmx->msg_to_user_cb(wmx, wmx->msg_to_user_priv,
pipe_name, data, size);
+ wmx->ifidx = dest_ifidx;
error_no_attrs:
error_parse:
d_fnend(7, wmx, "(wmx %p msg %p) = %d\n", wmx, msg, result);
@@ -400,6 +411,9 @@ ssize_t wimaxll_msg_write(struct wimaxll_handle *wmx,
void *msg;
d_fnstart(3, wmx, "(wmx %p buf %p size %zu)\n", wmx, buf, size);
+ result = -EBADF;
+ if (wmx->ifidx == 0)
+ goto error_not_any;
nl_msg = nlmsg_new();
if (nl_msg == NULL) {
result = nl_get_errno();
@@ -442,6 +456,7 @@ error_msg_send:
error_msg_prep:
nlmsg_free(nl_msg);
error_msg_alloc:
+error_not_any:
d_fnend(3, wmx, "(wmx %p buf %p size %zu) = %zd\n",
wmx, buf, size, result);
return result;
diff --git a/lib/op-open.c b/lib/op-open.c
index a222c5c..4696a15 100644
--- a/lib/op-open.c
+++ b/lib/op-open.c
@@ -280,12 +280,6 @@ int wimaxll_gnl_resolve(struct wimaxll_handle *wmx)
d_fnstart(5, wmx, "(wmx %p)\n", wmx);
/* Lookup the generic netlink family */
- wmx->ifidx = if_nametoindex(wmx->name);
- if (wmx->ifidx == 0) {
- wimaxll_msg(wmx, "E: device %s does not exist\n", wmx->name);
- result = -ENODEV;
- goto error_no_dev;
- }
result = genl_ctrl_resolve(wmx->nlh_tx, "WiMAX");
if (result < 0) {
wimaxll_msg(wmx, "E: device %s presents no WiMAX interface; "
@@ -327,7 +321,6 @@ int wimaxll_gnl_resolve(struct wimaxll_handle *wmx)
error_bad_major:
error_mcg_resolve:
error_ctrl_resolve:
-error_no_dev:
d_fnend(5, wmx, "(wmx %p) = %d\n", wmx, result);
return result;
}
@@ -343,7 +336,11 @@ void wimaxll_free(struct wimaxll_handle *wmx)
/**
* Open a handle to the WiMAX control interface in the kernel
*
- * \param device device name of the WiMAX network interface
+ * \param device device name of the WiMAX network interface; to
+ * specify an interface by index, use the name "#IFNAME". To open
+ * a handle that will receive data for any device (but not allow
+ * sending commands to devices), set %NULL.
+ *
* \return WiMAX device handle on success; on error, %NULL is returned
* and the \a errno variable is updated with a corresponding
* negative value.
@@ -381,19 +378,41 @@ struct wimaxll_handle *wimaxll_open(const char *device)
goto error_gnl_handle_alloc;
}
memset(wmx, 0, sizeof(*wmx));
- strncpy(wmx->name, device, sizeof(wmx->name));
+ if (device != NULL && sscanf(device, "#%u", &wmx->ifidx) == 1) {
+ /* Open by interface index "#IFINDEX" */
+ if (if_indextoname(wmx->ifidx, wmx->name) == NULL) {
+ wimaxll_msg(wmx, "E: device index #%u does not exist\n",
+ wmx->ifidx);
+ result = -ENODEV;
+ goto error_no_dev;
+ }
+ } else if (device != NULL) {
+ /* Open by interface name */
+ strncpy(wmx->name, device, sizeof(wmx->name));
+ wmx->ifidx = if_nametoindex(wmx->name);
+ if (wmx->ifidx == 0) {
+ wimaxll_msg(wmx, "E: device %s does not exist\n", wmx->name);
+ result = -ENODEV;
+ goto error_no_dev;
+ }
+ } else {
+ /* "Any" device (just for receiving callbacks) */
+ wmx->name[0] = 0;
+ wmx->ifidx = 0;
+ }
/* Setup the TX side */
wmx->nlh_tx = nl_handle_alloc();
if (wmx->nlh_tx == NULL) {
result = nl_get_errno();
- wimaxll_msg(wmx, "E: cannot open TX netlink handle: %d\n",
- result);
+ wimaxll_msg(wmx, "E: TX: cannot allocate handle: %d (%s)\n",
+ result, nl_geterror());
goto error_nl_handle_alloc_tx;
}
result = nl_connect(wmx->nlh_tx, NETLINK_GENERIC);
if (result < 0) {
- wimaxll_msg(wmx, "E: cannot connect TX netlink: %d\n", result);
+ wimaxll_msg(wmx, "E: TX: cannot connect netlink: %d (%s)\n",
+ result, nl_geterror());
goto error_nl_connect_tx;
}
@@ -401,13 +420,14 @@ struct wimaxll_handle *wimaxll_open(const char *device)
wmx->nlh_rx = nl_handle_alloc();
if (wmx->nlh_rx == NULL) {
result = nl_get_errno();
- wimaxll_msg(wmx, "E: RX: cannot allocate netlink handle: %d\n",
- result);
+ wimaxll_msg(wmx, "E: RX: cannot allocate handle: %d (%s)\n",
+ result, nl_geterror());
goto error_nl_handle_alloc_rx;
}
result = nl_connect(wmx->nlh_rx, NETLINK_GENERIC);
if (result < 0) {
- wimaxll_msg(wmx, "E: RX: cannot connect netlink: %d\n", result);
+ wimaxll_msg(wmx, "E: RX: cannot connect netlink: %d (%s)\n",
+ result, nl_geterror());
goto error_nl_connect_rx;
}
@@ -417,19 +437,21 @@ struct wimaxll_handle *wimaxll_open(const char *device)
result = nl_socket_add_membership(wmx->nlh_rx, wmx->mcg_id);
if (result < 0) {
- wimaxll_msg(wmx, "E: RX: cannot join multicast group %u: %d\n",
- wmx->mcg_id, result);
+ wimaxll_msg(wmx, "E: RX: cannot join multicast group %u: %d (%s)\n",
+ wmx->mcg_id, result, nl_geterror());
goto error_nl_add_membership;
}
/* Now we check if the device is a WiMAX supported device, by
* just querying for the RFKILL status. If this is not a WiMAX
* device, it will fail with -ENODEV. */
- result = wimaxll_rfkill(wmx, WIMAX_RF_QUERY);
- if (result == -ENODEV) {
- wimaxll_msg(wmx, "E: device %s is not a WiMAX device; or "
- "supports an interface unknown to libwimaxll: %d\n",
- wmx->name, result);
- goto error_rfkill;
+ if (wmx->ifidx > 0) { /* if this handle is for any, don't check */
+ result = wimaxll_rfkill(wmx, WIMAX_RF_QUERY);
+ if (result == -ENODEV) {
+ wimaxll_msg(wmx, "E: device %s is not a WiMAX device; "
+ "or supports an interface unknown to "
+ "libwimaxll: %d\n", wmx->name, result);
+ goto error_rfkill;
+ }
}
d_fnend(3, wmx, "(device %s) = %p\n", device, wmx);
return wmx;
@@ -445,6 +467,7 @@ error_nl_handle_alloc_rx:
error_nl_connect_tx:
nl_handle_destroy(wmx->nlh_tx);
error_nl_handle_alloc_tx:
+error_no_dev:
wimaxll_free(wmx);
error_gnl_handle_alloc:
errno = -result;
@@ -452,7 +475,6 @@ error_gnl_handle_alloc:
return NULL;
}
-
/**
* Close a device handle opened with wimaxll_open()
*
diff --git a/lib/op-reset.c b/lib/op-reset.c
index 434d235..0b842b6 100644
--- a/lib/op-reset.c
+++ b/lib/op-reset.c
@@ -89,6 +89,10 @@ int wimaxll_reset(struct wimaxll_handle *wmx)
struct nl_msg *msg;
d_fnstart(3, wmx, "(wmx %p)\n", wmx);
+ result = -EBADF;
+ if (wmx->ifidx == 0)
+ goto error_not_any;
+
msg = nlmsg_new();
if (msg == NULL) {
result = errno;
@@ -119,6 +123,7 @@ error_msg_prep:
error_msg_send:
nlmsg_free(msg);
error_msg_alloc:
+error_not_any:
d_fnend(3, wmx, "(wmx %p) = %d\n", wmx, result);
return result;
}
diff --git a/lib/op-rfkill.c b/lib/op-rfkill.c
index 5cdf738..08cf4e5 100644
--- a/lib/op-rfkill.c
+++ b/lib/op-rfkill.c
@@ -95,6 +95,9 @@ int wimaxll_rfkill(struct wimaxll_handle *wmx, enum wimax_rf_state state)
struct nl_msg *msg;
d_fnstart(3, wmx, "(wmx %p state %u)\n", wmx, state);
+ result = -EBADF;
+ if (wmx->ifidx == 0)
+ goto error_not_any;
msg = nlmsg_new();
if (msg == NULL) {
result = errno;
@@ -126,6 +129,7 @@ error_msg_prep:
error_msg_send:
nlmsg_free(msg);
error_msg_alloc:
+error_not_any:
d_fnend(3, wmx, "(wmx %p state %u) = %d\n", wmx, state, result);
return result;
}
diff --git a/lib/re-state-change.c b/lib/re-state-change.c
index ae2a08d..cbbcd55 100644
--- a/lib/re-state-change.c
+++ b/lib/re-state-change.c
@@ -125,7 +125,8 @@ int wimaxll_gnl_handle_state_change(struct wimaxll_handle *wmx,
struct genlmsghdr *gnl_hdr;
struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
enum wimax_st old_state, new_state;
-
+ unsigned dest_ifidx;
+
d_fnstart(7, wmx, "(wmx %p msg %p)\n", wmx, msg);
nl_hdr = nlmsg_hdr(msg);
gnl_hdr = nlmsg_data(nl_hdr);
@@ -141,14 +142,10 @@ int wimaxll_gnl_handle_state_change(struct wimaxll_handle *wmx,
goto error_parse;
}
/* Find if the message is for the interface wmx represents */
- if (tb[WIMAX_GNL_STCH_IFIDX] == NULL) {
+ dest_ifidx = nla_get_u32(tb[WIMAX_GNL_STCH_IFIDX]);
+ if (wmx->ifidx > 0 && wmx->ifidx != dest_ifidx) {
wimaxll_msg(wmx, "E: %s: cannot find IFIDX attribute\n",
__func__);
- result = -EINVAL;
- goto error_no_attrs;
-
- }
- if (wmx->ifidx != nla_get_u32(tb[WIMAX_GNL_STCH_IFIDX])) {
result = -ENODEV;
goto error_no_attrs;
}
@@ -174,10 +171,19 @@ int wimaxll_gnl_handle_state_change(struct wimaxll_handle *wmx,
d_printf(1, wmx, "D: CRX re_state_change old %u new %u\n",
old_state, new_state);
+ /* If this is an "any" handle, set the wmx->ifidx to the
+ * received one so the callback can now where did the thing
+ * come from. Will be restored.
+ */
+ if (wmx->ifidx == 0) {
+ wmx->ifidx = dest_ifidx;
+ dest_ifidx = 0;
+ }
/* Now execute the callback for handling re-state-change; if
* it doesn't update the context's result code, we'll do. */
result = wmx->state_change_cb(wmx, wmx->state_change_priv,
old_state, new_state);
+ wmx->ifidx = dest_ifidx;
error_no_attrs:
error_parse:
d_fnend(7, wmx, "(wmx %p msg %p) = %zd\n", wmx, msg, result);
diff --git a/lib/wimax.c b/lib/wimax.c
index 83bc16e..f56fff0 100644
--- a/lib/wimax.c
+++ b/lib/wimax.c
@@ -263,6 +263,9 @@ void (*wimaxll_vmsg)(const char *fmt, va_list vargs) = NULL;
* \param wmx WiMAX device handle
* \return Interface name (only valid while the handle is open)
*
+ * Note that if this is an \e any interface (open for all devices),
+ * this will be empty.
+ *
* \ingroup device_management
*/
const char *wimaxll_ifname(const struct wimaxll_handle *wmx)