diff options
-rw-r--r-- | lib/internal.h | 4 | ||||
-rw-r--r-- | lib/op-msg.c | 17 | ||||
-rw-r--r-- | lib/op-open.c | 70 | ||||
-rw-r--r-- | lib/op-reset.c | 5 | ||||
-rw-r--r-- | lib/op-rfkill.c | 4 | ||||
-rw-r--r-- | lib/re-state-change.c | 20 | ||||
-rw-r--r-- | lib/wimax.c | 3 |
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) |