aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2008-12-20 19:57:38 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:17 -0500
commit3e65646bb12be03b14dff53907391095a52d5f49 (patch)
tree5ab2961f02a2d078990e69584af81b1197fb2392 /net
parent3efb40c2c6eea315abcf19239c15d088e2498299 (diff)
wimax: basic API: kernel/user messaging, rfkill and reset
Implements the three basic operations provided by the stack's control interface to WiMAX devices: - Messaging channel between user space and driver/device This implements a direct communication channel between user space and the driver/device, by which free form messages can be sent back and forth. This is intended for device-specific features, vendor quirks, etc. - RF-kill framework integration Provide most of the RF-Kill integration for WiMAX drivers so that all device drivers have to do is after wimax_dev_add() is call wimax_report_rfkill_{hw,sw}() to update initial state and then every time it changes. Provides wimax_rfkill() for the kernel to call to set software RF-Kill status and/or query current hardware and software switch status. Exports wimax_rfkill() over generic netlink to user space. - Reset a WiMAX device Provides wimax_reset() for the kernel to reset a wimax device as needed and exports it over generic netlink to user space. This API is clearly limited, as it still provides no way to do the basic scan, connect and disconnect in a hardware independent way. The WiMAX case is more complex than WiFi due to the way networks are discovered and provisioned. The next developments are to add the basic operations so they can be offerent by different drivers. However, we'd like to get more vendors to jump in and provide feedback of how the user/kernel API/abstraction layer should be. The user space code for the i2400m, as of now, uses the messaging channel, but that will change as the API evolves. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'net')
-rw-r--r--net/wimax/op-msg.c421
-rw-r--r--net/wimax/op-reset.c143
-rw-r--r--net/wimax/op-rfkill.c532
3 files changed, 1096 insertions, 0 deletions
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c
new file mode 100644
index 000000000000..cb3b4ad53683
--- /dev/null
+++ b/net/wimax/op-msg.c
@@ -0,0 +1,421 @@
1/*
2 * Linux WiMAX
3 * Generic messaging interface between userspace and driver/device
4 *
5 *
6 * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This implements a direct communication channel between user space and
25 * the driver/device, by which free form messages can be sent back and
26 * forth.
27 *
28 * This is intended for device-specific features, vendor quirks, etc.
29 *
30 * See include/net/wimax.h
31 *
32 * GENERIC NETLINK ENCODING AND CAPACITY
33 *
34 * A destination "pipe name" is added to each message; it is up to the
35 * drivers to assign or use those names (if using them at all).
36 *
37 * Messages are encoded as a binary netlink attribute using nla_put()
38 * using type NLA_UNSPEC (as some versions of libnl still in
39 * deployment don't yet understand NLA_BINARY).
40 *
41 * The maximum capacity of this transport is PAGESIZE per message (so
42 * the actual payload will be bit smaller depending on the
43 * netlink/generic netlink attributes and headers).
44 *
45 * RECEPTION OF MESSAGES
46 *
47 * When a message is received from user space, it is passed verbatim
48 * to the driver calling wimax_dev->op_msg_from_user(). The return
49 * value from this function is passed back to user space as an ack
50 * over the generic netlink protocol.
51 *
52 * The stack doesn't do any processing or interpretation of these
53 * messages.
54 *
55 * SENDING MESSAGES
56 *
57 * Messages can be sent with wimax_msg().
58 *
59 * If the message delivery needs to happen on a different context to
60 * that of its creation, wimax_msg_alloc() can be used to get a
61 * pointer to the message that can be delivered later on with
62 * wimax_msg_send().
63 *
64 * ROADMAP
65 *
66 * wimax_gnl_doit_msg_from_user() Process a message from user space
67 * wimax_dev_get_by_genl_info()
68 * wimax_dev->op_msg_from_user() Delivery of message to the driver
69 *
70 * wimax_msg() Send a message to user space
71 * wimax_msg_alloc()
72 * wimax_msg_send()
73 */
74#include <linux/device.h>
75#include <net/genetlink.h>
76#include <linux/netdevice.h>
77#include <linux/wimax.h>
78#include <linux/security.h>
79#include "wimax-internal.h"
80
81
82#define D_SUBMODULE op_msg
83#include "debug-levels.h"
84
85
86/**
87 * wimax_msg_alloc - Create a new skb for sending a message to userspace
88 *
89 * @wimax_dev: WiMAX device descriptor
90 * @pipe_name: "named pipe" the message will be sent to
91 * @msg: pointer to the message data to send
92 * @size: size of the message to send (in bytes), including the header.
93 * @gfp_flags: flags for memory allocation.
94 *
95 * Returns: %0 if ok, negative errno code on error
96 *
97 * Description:
98 *
99 * Allocates an skb that will contain the message to send to user
100 * space over the messaging pipe and initializes it, copying the
101 * payload.
102 *
103 * Once this call is done, you can deliver it with
104 * wimax_msg_send().
105 *
106 * IMPORTANT:
107 *
108 * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
109 * wimax_msg_send() depends on skb->data being placed at the
110 * beginning of the user message.
111 */
112struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
113 const char *pipe_name,
114 const void *msg, size_t size,
115 gfp_t gfp_flags)
116{
117 int result;
118 struct device *dev = wimax_dev->net_dev->dev.parent;
119 size_t msg_size;
120 void *genl_msg;
121 struct sk_buff *skb;
122
123 msg_size = nla_total_size(size)
124 + nla_total_size(sizeof(u32))
125 + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0);
126 result = -ENOMEM;
127 skb = genlmsg_new(msg_size, gfp_flags);
128 if (skb == NULL)
129 goto error_new;
130 genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family,
131 0, WIMAX_GNL_OP_MSG_TO_USER);
132 if (genl_msg == NULL) {
133 dev_err(dev, "no memory to create generic netlink message\n");
134 goto error_genlmsg_put;
135 }
136 result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX,
137 wimax_dev->net_dev->ifindex);
138 if (result < 0) {
139 dev_err(dev, "no memory to add ifindex attribute\n");
140 goto error_nla_put;
141 }
142 if (pipe_name) {
143 result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME,
144 pipe_name);
145 if (result < 0) {
146 dev_err(dev, "no memory to add pipe_name attribute\n");
147 goto error_nla_put;
148 }
149 }
150 result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg);
151 if (result < 0) {
152 dev_err(dev, "no memory to add payload in attribute\n");
153 goto error_nla_put;
154 }
155 genlmsg_end(skb, genl_msg);
156 return skb;
157
158error_nla_put:
159error_genlmsg_put:
160error_new:
161 nlmsg_free(skb);
162 return ERR_PTR(result);
163
164}
165EXPORT_SYMBOL_GPL(wimax_msg_alloc);
166
167
168/**
169 * wimax_msg_data_len - Return a pointer and size of a message's payload
170 *
171 * @msg: Pointer to a message created with wimax_msg_alloc()
172 * @size: Pointer to where to store the message's size
173 *
174 * Returns the pointer to the message data.
175 */
176const void *wimax_msg_data_len(struct sk_buff *msg, size_t *size)
177{
178 struct nlmsghdr *nlh = (void *) msg->head;
179 struct nlattr *nla;
180
181 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
182 WIMAX_GNL_MSG_DATA);
183 if (nla == NULL) {
184 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
185 return NULL;
186 }
187 *size = nla_len(nla);
188 return nla_data(nla);
189}
190EXPORT_SYMBOL_GPL(wimax_msg_data_len);
191
192
193/**
194 * wimax_msg_data - Return a pointer to a message's payload
195 *
196 * @msg: Pointer to a message created with wimax_msg_alloc()
197 */
198const void *wimax_msg_data(struct sk_buff *msg)
199{
200 struct nlmsghdr *nlh = (void *) msg->head;
201 struct nlattr *nla;
202
203 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
204 WIMAX_GNL_MSG_DATA);
205 if (nla == NULL) {
206 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
207 return NULL;
208 }
209 return nla_data(nla);
210}
211EXPORT_SYMBOL_GPL(wimax_msg_data);
212
213
214/**
215 * wimax_msg_len - Return a message's payload length
216 *
217 * @msg: Pointer to a message created with wimax_msg_alloc()
218 */
219ssize_t wimax_msg_len(struct sk_buff *msg)
220{
221 struct nlmsghdr *nlh = (void *) msg->head;
222 struct nlattr *nla;
223
224 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
225 WIMAX_GNL_MSG_DATA);
226 if (nla == NULL) {
227 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
228 return -EINVAL;
229 }
230 return nla_len(nla);
231}
232EXPORT_SYMBOL_GPL(wimax_msg_len);
233
234
235/**
236 * wimax_msg_send - Send a pre-allocated message to user space
237 *
238 * @wimax_dev: WiMAX device descriptor
239 *
240 * @skb: &struct sk_buff returned by wimax_msg_alloc(). Note the
241 * ownership of @skb is transferred to this function.
242 *
243 * Returns: 0 if ok, < 0 errno code on error
244 *
245 * Description:
246 *
247 * Sends a free-form message that was preallocated with
248 * wimax_msg_alloc() and filled up.
249 *
250 * Assumes that once you pass an skb to this function for sending, it
251 * owns it and will release it when done (on success).
252 *
253 * IMPORTANT:
254 *
255 * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
256 * wimax_msg_send() depends on skb->data being placed at the
257 * beginning of the user message.
258 */
259int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
260{
261 int result;
262 struct device *dev = wimax_dev->net_dev->dev.parent;
263 void *msg = skb->data;
264 size_t size = skb->len;
265 might_sleep();
266
267 d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
268 d_dump(2, dev, msg, size);
269 result = genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
270 d_printf(1, dev, "CTX: genl multicast result %d\n", result);
271 if (result == -ESRCH) /* Nobody connected, ignore it */
272 result = 0; /* btw, the skb is freed already */
273 return result;
274}
275EXPORT_SYMBOL_GPL(wimax_msg_send);
276
277
278/**
279 * wimax_msg - Send a message to user space
280 *
281 * @wimax_dev: WiMAX device descriptor (properly referenced)
282 * @pipe_name: "named pipe" the message will be sent to
283 * @buf: pointer to the message to send.
284 * @size: size of the buffer pointed to by @buf (in bytes).
285 * @gfp_flags: flags for memory allocation.
286 *
287 * Returns: %0 if ok, negative errno code on error.
288 *
289 * Description:
290 *
291 * Sends a free-form message to user space on the device @wimax_dev.
292 *
293 * NOTES:
294 *
295 * Once the @skb is given to this function, who will own it and will
296 * release it when done (unless it returns error).
297 */
298int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name,
299 const void *buf, size_t size, gfp_t gfp_flags)
300{
301 int result = -ENOMEM;
302 struct sk_buff *skb;
303
304 skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags);
305 if (skb == NULL)
306 goto error_msg_new;
307 result = wimax_msg_send(wimax_dev, skb);
308error_msg_new:
309 return result;
310}
311EXPORT_SYMBOL_GPL(wimax_msg);
312
313
314static const
315struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = {
316 [WIMAX_GNL_MSG_IFIDX] = {
317 .type = NLA_U32,
318 },
319 [WIMAX_GNL_MSG_DATA] = {
320 .type = NLA_UNSPEC, /* libnl doesn't grok BINARY yet */
321 },
322};
323
324
325/*
326 * Relays a message from user space to the driver
327 *
328 * The skb is passed to the driver-specific function with the netlink
329 * and generic netlink headers already stripped.
330 *
331 * This call will block while handling/relaying the message.
332 */
333static
334int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
335{
336 int result, ifindex;
337 struct wimax_dev *wimax_dev;
338 struct device *dev;
339 struct nlmsghdr *nlh = info->nlhdr;
340 char *pipe_name;
341 void *msg_buf;
342 size_t msg_len;
343
344 might_sleep();
345 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
346 result = -ENODEV;
347 if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) {
348 printk(KERN_ERR "WIMAX_GNL_MSG_FROM_USER: can't find IFIDX "
349 "attribute\n");
350 goto error_no_wimax_dev;
351 }
352 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]);
353 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
354 if (wimax_dev == NULL)
355 goto error_no_wimax_dev;
356 dev = wimax_dev_to_dev(wimax_dev);
357
358 /* Unpack arguments */
359 result = -EINVAL;
360 if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) {
361 dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA "
362 "attribute\n");
363 goto error_no_data;
364 }
365 msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]);
366 msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]);
367
368 if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL)
369 pipe_name = NULL;
370 else {
371 struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME];
372 size_t attr_len = nla_len(attr);
373 /* libnl-1.1 does not yet support NLA_NUL_STRING */
374 result = -ENOMEM;
375 pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL);
376 if (pipe_name == NULL)
377 goto error_alloc;
378 pipe_name[attr_len] = 0;
379 }
380 mutex_lock(&wimax_dev->mutex);
381 result = wimax_dev_is_ready(wimax_dev);
382 if (result < 0)
383 goto error_not_ready;
384 result = -ENOSYS;
385 if (wimax_dev->op_msg_from_user == NULL)
386 goto error_noop;
387
388 d_printf(1, dev,
389 "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
390 nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags,
391 nlh->nlmsg_seq, nlh->nlmsg_pid);
392 d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len);
393 d_dump(2, dev, msg_buf, msg_len);
394
395 result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name,
396 msg_buf, msg_len, info);
397error_noop:
398error_not_ready:
399 mutex_unlock(&wimax_dev->mutex);
400error_alloc:
401 kfree(pipe_name);
402error_no_data:
403 dev_put(wimax_dev->net_dev);
404error_no_wimax_dev:
405 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
406 return result;
407}
408
409
410/*
411 * Generic Netlink glue
412 */
413
414struct genl_ops wimax_gnl_msg_from_user = {
415 .cmd = WIMAX_GNL_OP_MSG_FROM_USER,
416 .flags = GENL_ADMIN_PERM,
417 .policy = wimax_gnl_msg_policy,
418 .doit = wimax_gnl_doit_msg_from_user,
419 .dumpit = NULL,
420};
421
diff --git a/net/wimax/op-reset.c b/net/wimax/op-reset.c
new file mode 100644
index 000000000000..ca269178c4d4
--- /dev/null
+++ b/net/wimax/op-reset.c
@@ -0,0 +1,143 @@
1/*
2 * Linux WiMAX
3 * Implement and export a method for resetting a WiMAX device
4 *
5 *
6 * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This implements a simple synchronous call to reset a WiMAX device.
25 *
26 * Resets aim at being warm, keeping the device handles active;
27 * however, when that fails, it falls back to a cold reset (that will
28 * disconnect and reconnect the device).
29 */
30
31#include <net/wimax.h>
32#include <net/genetlink.h>
33#include <linux/wimax.h>
34#include <linux/security.h>
35#include "wimax-internal.h"
36
37#define D_SUBMODULE op_reset
38#include "debug-levels.h"
39
40
41/**
42 * wimax_reset - Reset a WiMAX device
43 *
44 * @wimax_dev: WiMAX device descriptor
45 *
46 * Returns:
47 *
48 * %0 if ok and a warm reset was done (the device still exists in
49 * the system).
50 *
51 * -%ENODEV if a cold/bus reset had to be done (device has
52 * disconnected and reconnected, so current handle is not valid
53 * any more).
54 *
55 * -%EINVAL if the device is not even registered.
56 *
57 * Any other negative error code shall be considered as
58 * non-recoverable.
59 *
60 * Description:
61 *
62 * Called when wanting to reset the device for any reason. Device is
63 * taken back to power on status.
64 *
65 * This call blocks; on succesful return, the device has completed the
66 * reset process and is ready to operate.
67 */
68int wimax_reset(struct wimax_dev *wimax_dev)
69{
70 int result = -EINVAL;
71 struct device *dev = wimax_dev_to_dev(wimax_dev);
72 enum wimax_st state;
73
74 might_sleep();
75 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
76 mutex_lock(&wimax_dev->mutex);
77 dev_hold(wimax_dev->net_dev);
78 state = wimax_dev->state;
79 mutex_unlock(&wimax_dev->mutex);
80
81 if (state >= WIMAX_ST_DOWN) {
82 mutex_lock(&wimax_dev->mutex_reset);
83 result = wimax_dev->op_reset(wimax_dev);
84 mutex_unlock(&wimax_dev->mutex_reset);
85 }
86 dev_put(wimax_dev->net_dev);
87
88 d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
89 return result;
90}
91EXPORT_SYMBOL(wimax_reset);
92
93
94static const
95struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = {
96 [WIMAX_GNL_RESET_IFIDX] = {
97 .type = NLA_U32,
98 },
99};
100
101
102/*
103 * Exporting to user space over generic netlink
104 *
105 * Parse the reset command from user space, return error code.
106 *
107 * No attributes.
108 */
109static
110int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
111{
112 int result, ifindex;
113 struct wimax_dev *wimax_dev;
114 struct device *dev;
115
116 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
117 result = -ENODEV;
118 if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) {
119 printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX "
120 "attribute\n");
121 goto error_no_wimax_dev;
122 }
123 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]);
124 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
125 if (wimax_dev == NULL)
126 goto error_no_wimax_dev;
127 dev = wimax_dev_to_dev(wimax_dev);
128 /* Execute the operation and send the result back to user space */
129 result = wimax_reset(wimax_dev);
130 dev_put(wimax_dev->net_dev);
131error_no_wimax_dev:
132 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
133 return result;
134}
135
136
137struct genl_ops wimax_gnl_reset = {
138 .cmd = WIMAX_GNL_OP_RESET,
139 .flags = GENL_ADMIN_PERM,
140 .policy = wimax_gnl_reset_policy,
141 .doit = wimax_gnl_doit_reset,
142 .dumpit = NULL,
143};
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c
new file mode 100644
index 000000000000..8745bac173f1
--- /dev/null
+++ b/net/wimax/op-rfkill.c
@@ -0,0 +1,532 @@
1/*
2 * Linux WiMAX
3 * RF-kill framework integration
4 *
5 *
6 * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This integrates into the Linux Kernel rfkill susbystem so that the
25 * drivers just have to do the bare minimal work, which is providing a
26 * method to set the software RF-Kill switch and to report changes in
27 * the software and hardware switch status.
28 *
29 * A non-polled generic rfkill device is embedded into the WiMAX
30 * subsystem's representation of a device.
31 *
32 * FIXME: Need polled support? use a timer or add the implementation
33 * to the stack.
34 *
35 * All device drivers have to do is after wimax_dev_init(), call
36 * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update
37 * initial state and then every time it changes. See wimax.h:struct
38 * wimax_dev for more information.
39 *
40 * ROADMAP
41 *
42 * wimax_gnl_doit_rfkill() User space calling wimax_rfkill()
43 * wimax_rfkill() Kernel calling wimax_rfkill()
44 * __wimax_rf_toggle_radio()
45 *
46 * wimax_rfkill_toggle_radio() RF-Kill subsytem calling
47 * __wimax_rf_toggle_radio()
48 *
49 * __wimax_rf_toggle_radio()
50 * wimax_dev->op_rfkill_sw_toggle() Driver backend
51 * __wimax_state_change()
52 *
53 * wimax_report_rfkill_sw() Driver reports state change
54 * __wimax_state_change()
55 *
56 * wimax_report_rfkill_hw() Driver reports state change
57 * __wimax_state_change()
58 *
59 * wimax_rfkill_add() Initialize/shutdown rfkill support
60 * wimax_rfkill_rm() [called by wimax_dev_add/rm()]
61 */
62
63#include <net/wimax.h>
64#include <net/genetlink.h>
65#include <linux/wimax.h>
66#include <linux/security.h>
67#include <linux/rfkill.h>
68#include <linux/input.h>
69#include "wimax-internal.h"
70
71#define D_SUBMODULE op_rfkill
72#include "debug-levels.h"
73
74#ifdef CONFIG_RFKILL
75
76
77/**
78 * wimax_report_rfkill_hw - Reports changes in the hardware RF switch
79 *
80 * @wimax_dev: WiMAX device descriptor
81 *
82 * @state: New state of the RF Kill switch. %WIMAX_RF_ON radio on,
83 * %WIMAX_RF_OFF radio off.
84 *
85 * When the device detects a change in the state of thehardware RF
86 * switch, it must call this function to let the WiMAX kernel stack
87 * know that the state has changed so it can be properly propagated.
88 *
89 * The WiMAX stack caches the state (the driver doesn't need to). As
90 * well, as the change is propagated it will come back as a request to
91 * change the software state to mirror the hardware state.
92 *
93 * If the device doesn't have a hardware kill switch, just report
94 * it on initialization as always on (%WIMAX_RF_ON, radio on).
95 */
96void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
97 enum wimax_rf_state state)
98{
99 int result;
100 struct device *dev = wimax_dev_to_dev(wimax_dev);
101 enum wimax_st wimax_state;
102 enum rfkill_state rfkill_state;
103
104 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
105 BUG_ON(state == WIMAX_RF_QUERY);
106 BUG_ON(state != WIMAX_RF_ON && state != WIMAX_RF_OFF);
107
108 mutex_lock(&wimax_dev->mutex);
109 result = wimax_dev_is_ready(wimax_dev);
110 if (result < 0)
111 goto error_not_ready;
112
113 if (state != wimax_dev->rf_hw) {
114 wimax_dev->rf_hw = state;
115 rfkill_state = state == WIMAX_RF_ON ?
116 RFKILL_STATE_OFF : RFKILL_STATE_ON;
117 if (wimax_dev->rf_hw == WIMAX_RF_ON
118 && wimax_dev->rf_sw == WIMAX_RF_ON)
119 wimax_state = WIMAX_ST_READY;
120 else
121 wimax_state = WIMAX_ST_RADIO_OFF;
122 __wimax_state_change(wimax_dev, wimax_state);
123 input_report_key(wimax_dev->rfkill_input, KEY_WIMAX,
124 rfkill_state);
125 }
126error_not_ready:
127 mutex_unlock(&wimax_dev->mutex);
128 d_fnend(3, dev, "(wimax_dev %p state %u) = void [%d]\n",
129 wimax_dev, state, result);
130}
131EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
132
133
134/**
135 * wimax_report_rfkill_sw - Reports changes in the software RF switch
136 *
137 * @wimax_dev: WiMAX device descriptor
138 *
139 * @state: New state of the RF kill switch. %WIMAX_RF_ON radio on,
140 * %WIMAX_RF_OFF radio off.
141 *
142 * Reports changes in the software RF switch state to the the WiMAX
143 * stack.
144 *
145 * The main use is during initialization, so the driver can query the
146 * device for its current software radio kill switch state and feed it
147 * to the system.
148 *
149 * On the side, the device does not change the software state by
150 * itself. In practice, this can happen, as the device might decide to
151 * switch (in software) the radio off for different reasons.
152 */
153void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
154 enum wimax_rf_state state)
155{
156 int result;
157 struct device *dev = wimax_dev_to_dev(wimax_dev);
158 enum wimax_st wimax_state;
159
160 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
161 BUG_ON(state == WIMAX_RF_QUERY);
162 BUG_ON(state != WIMAX_RF_ON && state != WIMAX_RF_OFF);
163
164 mutex_lock(&wimax_dev->mutex);
165 result = wimax_dev_is_ready(wimax_dev);
166 if (result < 0)
167 goto error_not_ready;
168
169 if (state != wimax_dev->rf_sw) {
170 wimax_dev->rf_sw = state;
171 if (wimax_dev->rf_hw == WIMAX_RF_ON
172 && wimax_dev->rf_sw == WIMAX_RF_ON)
173 wimax_state = WIMAX_ST_READY;
174 else
175 wimax_state = WIMAX_ST_RADIO_OFF;
176 __wimax_state_change(wimax_dev, wimax_state);
177 }
178error_not_ready:
179 mutex_unlock(&wimax_dev->mutex);
180 d_fnend(3, dev, "(wimax_dev %p state %u) = void [%d]\n",
181 wimax_dev, state, result);
182}
183EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
184
185
186/*
187 * Callback for the RF Kill toggle operation
188 *
189 * This function is called by:
190 *
191 * - The rfkill subsystem when the RF-Kill key is pressed in the
192 * hardware and the driver notifies through
193 * wimax_report_rfkill_hw(). The rfkill subsystem ends up calling back
194 * here so the software RF Kill switch state is changed to reflect
195 * the hardware switch state.
196 *
197 * - When the user sets the state through sysfs' rfkill/state file
198 *
199 * - When the user calls wimax_rfkill().
200 *
201 * This call blocks!
202 *
203 * WARNING! When we call rfkill_unregister(), this will be called with
204 * state 0!
205 *
206 * WARNING: wimax_dev must be locked
207 */
208static
209int __wimax_rf_toggle_radio(struct wimax_dev *wimax_dev,
210 enum wimax_rf_state state)
211{
212 int result = 0;
213 struct device *dev = wimax_dev_to_dev(wimax_dev);
214 enum wimax_st wimax_state;
215
216 might_sleep();
217 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
218 if (wimax_dev->rf_sw == state)
219 goto out_no_change;
220 if (wimax_dev->op_rfkill_sw_toggle != NULL)
221 result = wimax_dev->op_rfkill_sw_toggle(wimax_dev, state);
222 else if (state == WIMAX_RF_OFF) /* No op? can't turn off */
223 result = -ENXIO;
224 else /* No op? can turn on */
225 result = 0; /* should never happen tho */
226 if (result >= 0) {
227 result = 0;
228 wimax_dev->rf_sw = state;
229 wimax_state = state == WIMAX_RF_ON ?
230 WIMAX_ST_READY : WIMAX_ST_RADIO_OFF;
231 __wimax_state_change(wimax_dev, wimax_state);
232 }
233out_no_change:
234 d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
235 wimax_dev, state, result);
236 return result;
237}
238
239
240/*
241 * Translate from rfkill state to wimax state
242 *
243 * NOTE: Special state handling rules here
244 *
245 * Just pretend the call didn't happen if we are in a state where
246 * we know for sure it cannot be handled (WIMAX_ST_DOWN or
247 * __WIMAX_ST_QUIESCING). rfkill() needs it to register and
248 * unregister, as it will run this path.
249 *
250 * NOTE: This call will block until the operation is completed.
251 */
252static
253int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
254{
255 int result;
256 struct wimax_dev *wimax_dev = data;
257 struct device *dev = wimax_dev_to_dev(wimax_dev);
258 enum wimax_rf_state rf_state;
259
260 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
261 switch (state) {
262 case RFKILL_STATE_ON:
263 rf_state = WIMAX_RF_OFF;
264 break;
265 case RFKILL_STATE_OFF:
266 rf_state = WIMAX_RF_ON;
267 break;
268 default:
269 BUG();
270 }
271 mutex_lock(&wimax_dev->mutex);
272 if (wimax_dev->state <= __WIMAX_ST_QUIESCING)
273 result = 0; /* just pretend it didn't happen */
274 else
275 result = __wimax_rf_toggle_radio(wimax_dev, rf_state);
276 mutex_unlock(&wimax_dev->mutex);
277 d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
278 wimax_dev, state, result);
279 return result;
280}
281
282
283/**
284 * wimax_rfkill - Set the software RF switch state for a WiMAX device
285 *
286 * @wimax_dev: WiMAX device descriptor
287 *
288 * @state: New RF state.
289 *
290 * Returns:
291 *
292 * >= 0 toggle state if ok, < 0 errno code on error. The toggle state
293 * is returned as a bitmap, bit 0 being the hardware RF state, bit 1
294 * the software RF state.
295 *
296 * 0 means disabled (%WIMAX_RF_ON, radio on), 1 means enabled radio
297 * off (%WIMAX_RF_OFF).
298 *
299 * Description:
300 *
301 * Called by the user when he wants to request the WiMAX radio to be
302 * switched on (%WIMAX_RF_ON) or off (%WIMAX_RF_OFF). With
303 * %WIMAX_RF_QUERY, just the current state is returned.
304 *
305 * NOTE:
306 *
307 * This call will block until the operation is complete.
308 */
309int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state)
310{
311 int result;
312 struct device *dev = wimax_dev_to_dev(wimax_dev);
313
314 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
315 mutex_lock(&wimax_dev->mutex);
316 result = wimax_dev_is_ready(wimax_dev);
317 if (result < 0)
318 goto error_not_ready;
319 switch (state) {
320 case WIMAX_RF_ON:
321 case WIMAX_RF_OFF:
322 result = __wimax_rf_toggle_radio(wimax_dev, state);
323 if (result < 0)
324 goto error;
325 break;
326 case WIMAX_RF_QUERY:
327 break;
328 default:
329 result = -EINVAL;
330 goto error;
331 }
332 result = wimax_dev->rf_sw << 1 | wimax_dev->rf_hw;
333error:
334error_not_ready:
335 mutex_unlock(&wimax_dev->mutex);
336 d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
337 wimax_dev, state, result);
338 return result;
339}
340EXPORT_SYMBOL(wimax_rfkill);
341
342
343/*
344 * Register a new WiMAX device's RF Kill support
345 *
346 * WARNING: wimax_dev->mutex must be unlocked
347 */
348int wimax_rfkill_add(struct wimax_dev *wimax_dev)
349{
350 int result;
351 struct rfkill *rfkill;
352 struct input_dev *input_dev;
353 struct device *dev = wimax_dev_to_dev(wimax_dev);
354
355 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
356 /* Initialize RF Kill */
357 result = -ENOMEM;
358 rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX);
359 if (rfkill == NULL)
360 goto error_rfkill_allocate;
361 wimax_dev->rfkill = rfkill;
362
363 rfkill->name = wimax_dev->name;
364 rfkill->state = RFKILL_STATE_OFF;
365 rfkill->data = wimax_dev;
366 rfkill->toggle_radio = wimax_rfkill_toggle_radio;
367 rfkill->user_claim_unsupported = 1;
368
369 /* Initialize the input device for the hw key */
370 input_dev = input_allocate_device();
371 if (input_dev == NULL)
372 goto error_input_allocate;
373 wimax_dev->rfkill_input = input_dev;
374 d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev);
375
376 input_dev->name = wimax_dev->name;
377 /* FIXME: get a real device bus ID and stuff? do we care? */
378 input_dev->id.bustype = BUS_HOST;
379 input_dev->id.vendor = 0xffff;
380 input_dev->evbit[0] = BIT(EV_KEY);
381 set_bit(KEY_WIMAX, input_dev->keybit);
382
383 /* Register both */
384 result = input_register_device(wimax_dev->rfkill_input);
385 if (result < 0)
386 goto error_input_register;
387 result = rfkill_register(wimax_dev->rfkill);
388 if (result < 0)
389 goto error_rfkill_register;
390
391 /* If there is no SW toggle op, SW RFKill is always on */
392 if (wimax_dev->op_rfkill_sw_toggle == NULL)
393 wimax_dev->rf_sw = WIMAX_RF_ON;
394
395 d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev);
396 return 0;
397
398 /* if rfkill_register() suceeds, can't use rfkill_free() any
399 * more, only rfkill_unregister() [it owns the refcount]; with
400 * the input device we have the same issue--hence the if. */
401error_rfkill_register:
402 input_unregister_device(wimax_dev->rfkill_input);
403 wimax_dev->rfkill_input = NULL;
404error_input_register:
405 if (wimax_dev->rfkill_input)
406 input_free_device(wimax_dev->rfkill_input);
407error_input_allocate:
408 rfkill_free(wimax_dev->rfkill);
409error_rfkill_allocate:
410 d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
411 return result;
412}
413
414
415/*
416 * Deregister a WiMAX device's RF Kill support
417 *
418 * Ick, we can't call rfkill_free() after rfkill_unregister()...oh
419 * well.
420 *
421 * WARNING: wimax_dev->mutex must be unlocked
422 */
423void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
424{
425 struct device *dev = wimax_dev_to_dev(wimax_dev);
426 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
427 rfkill_unregister(wimax_dev->rfkill); /* frees */
428 input_unregister_device(wimax_dev->rfkill_input);
429 d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev);
430}
431
432
433#else /* #ifdef CONFIG_RFKILL */
434
435void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
436 enum wimax_rf_state state)
437{
438}
439EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
440
441void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
442 enum wimax_rf_state state)
443{
444}
445EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
446
447int wimax_rfkill(struct wimax_dev *wimax_dev,
448 enum wimax_rf_state state)
449{
450 return WIMAX_RF_ON << 1 | WIMAX_RF_ON;
451}
452EXPORT_SYMBOL_GPL(wimax_rfkill);
453
454int wimax_rfkill_add(struct wimax_dev *wimax_dev)
455{
456 return 0;
457}
458
459void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
460{
461}
462
463#endif /* #ifdef CONFIG_RFKILL */
464
465
466/*
467 * Exporting to user space over generic netlink
468 *
469 * Parse the rfkill command from user space, return a combination
470 * value that describe the states of the different toggles.
471 *
472 * Only one attribute: the new state requested (on, off or no change,
473 * just query).
474 */
475
476static const
477struct nla_policy wimax_gnl_rfkill_policy[WIMAX_GNL_ATTR_MAX + 1] = {
478 [WIMAX_GNL_RFKILL_IFIDX] = {
479 .type = NLA_U32,
480 },
481 [WIMAX_GNL_RFKILL_STATE] = {
482 .type = NLA_U32 /* enum wimax_rf_state */
483 },
484};
485
486
487static
488int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info)
489{
490 int result, ifindex;
491 struct wimax_dev *wimax_dev;
492 struct device *dev;
493 enum wimax_rf_state new_state;
494
495 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
496 result = -ENODEV;
497 if (info->attrs[WIMAX_GNL_RFKILL_IFIDX] == NULL) {
498 printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX "
499 "attribute\n");
500 goto error_no_wimax_dev;
501 }
502 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RFKILL_IFIDX]);
503 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
504 if (wimax_dev == NULL)
505 goto error_no_wimax_dev;
506 dev = wimax_dev_to_dev(wimax_dev);
507 result = -EINVAL;
508 if (info->attrs[WIMAX_GNL_RFKILL_STATE] == NULL) {
509 dev_err(dev, "WIMAX_GNL_RFKILL: can't find RFKILL_STATE "
510 "attribute\n");
511 goto error_no_pid;
512 }
513 new_state = nla_get_u32(info->attrs[WIMAX_GNL_RFKILL_STATE]);
514
515 /* Execute the operation and send the result back to user space */
516 result = wimax_rfkill(wimax_dev, new_state);
517error_no_pid:
518 dev_put(wimax_dev->net_dev);
519error_no_wimax_dev:
520 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
521 return result;
522}
523
524
525struct genl_ops wimax_gnl_rfkill = {
526 .cmd = WIMAX_GNL_OP_RFKILL,
527 .flags = GENL_ADMIN_PERM,
528 .policy = wimax_gnl_rfkill_policy,
529 .doit = wimax_gnl_doit_rfkill,
530 .dumpit = NULL,
531};
532