diff options
author | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-04-20 17:11:28 -0700 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-04-21 15:01:25 -0700 |
commit | fdf913c4e26d8b25861f95152e3308c38cbbda7a (patch) | |
tree | 8b8c3f11b800d029ef9b902526684dae19a4bad7 | |
parent | 822eb164a15ae746c5a8c514f581fb47200fe463 (diff) |
libwimaxll: introduce 'any' handles to receive callbacks from any device
An 'any' handle is a handle opened with NULL as device name. No
commands can be executed with it, but it will emit callbacks for any
WiMAX device that would otherwise generate them for a handle opened
for it exclusively.
When the callback is executed, the handle is temporarily modified to
contain the interface index for whom the callback is emitted, which
can be recovered with wimaxll_ifidx().
The code modifications are quite minimal, mainly dealing with not
allowing command execution and updating the handle's interface index
before executing a callback.
This code also adds a path in wimaxll_open() to allow opening an
interface by interface index, by specifying "#NUMBER" (where NUMBER is
the interface index).
Errors to in some calls to libnl are better reported now.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
-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) |