aboutsummaryrefslogtreecommitdiffstats
path: root/net/wimax/op-msg.c
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/wimax/op-msg.c
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/wimax/op-msg.c')
-rw-r--r--net/wimax/op-msg.c421
1 files changed, 421 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