1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74#include <linux/device.h>
75#include <linux/slab.h>
76#include <net/genetlink.h>
77#include <linux/netdevice.h>
78#include <linux/wimax.h>
79#include <linux/security.h>
80#include <linux/export.h>
81#include "wimax-internal.h"
82
83
84#define D_SUBMODULE op_msg
85#include "debug-levels.h"
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
121 const char *pipe_name,
122 const void *msg, size_t size,
123 gfp_t gfp_flags)
124{
125 int result;
126 struct device *dev = wimax_dev_to_dev(wimax_dev);
127 size_t msg_size;
128 void *genl_msg;
129 struct sk_buff *skb;
130
131 msg_size = nla_total_size(size)
132 + nla_total_size(sizeof(u32))
133 + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0);
134 result = -ENOMEM;
135 skb = genlmsg_new(msg_size, gfp_flags);
136 if (skb == NULL)
137 goto error_new;
138 genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family,
139 0, WIMAX_GNL_OP_MSG_TO_USER);
140 if (genl_msg == NULL) {
141 dev_err(dev, "no memory to create generic netlink message\n");
142 goto error_genlmsg_put;
143 }
144 result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX,
145 wimax_dev->net_dev->ifindex);
146 if (result < 0) {
147 dev_err(dev, "no memory to add ifindex attribute\n");
148 goto error_nla_put;
149 }
150 if (pipe_name) {
151 result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME,
152 pipe_name);
153 if (result < 0) {
154 dev_err(dev, "no memory to add pipe_name attribute\n");
155 goto error_nla_put;
156 }
157 }
158 result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg);
159 if (result < 0) {
160 dev_err(dev, "no memory to add payload (msg %p size %zu) in "
161 "attribute: %d\n", msg, size, result);
162 goto error_nla_put;
163 }
164 genlmsg_end(skb, genl_msg);
165 return skb;
166
167error_nla_put:
168error_genlmsg_put:
169error_new:
170 nlmsg_free(skb);
171 return ERR_PTR(result);
172}
173EXPORT_SYMBOL_GPL(wimax_msg_alloc);
174
175
176
177
178
179
180
181
182
183
184const void *wimax_msg_data_len(struct sk_buff *msg, size_t *size)
185{
186 struct nlmsghdr *nlh = (void *) msg->head;
187 struct nlattr *nla;
188
189 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
190 WIMAX_GNL_MSG_DATA);
191 if (nla == NULL) {
192 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
193 return NULL;
194 }
195 *size = nla_len(nla);
196 return nla_data(nla);
197}
198EXPORT_SYMBOL_GPL(wimax_msg_data_len);
199
200
201
202
203
204
205
206const void *wimax_msg_data(struct sk_buff *msg)
207{
208 struct nlmsghdr *nlh = (void *) msg->head;
209 struct nlattr *nla;
210
211 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
212 WIMAX_GNL_MSG_DATA);
213 if (nla == NULL) {
214 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
215 return NULL;
216 }
217 return nla_data(nla);
218}
219EXPORT_SYMBOL_GPL(wimax_msg_data);
220
221
222
223
224
225
226
227ssize_t wimax_msg_len(struct sk_buff *msg)
228{
229 struct nlmsghdr *nlh = (void *) msg->head;
230 struct nlattr *nla;
231
232 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
233 WIMAX_GNL_MSG_DATA);
234 if (nla == NULL) {
235 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
236 return -EINVAL;
237 }
238 return nla_len(nla);
239}
240EXPORT_SYMBOL_GPL(wimax_msg_len);
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
274{
275 struct device *dev = wimax_dev_to_dev(wimax_dev);
276 void *msg = skb->data;
277 size_t size = skb->len;
278 might_sleep();
279
280 d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
281 d_dump(2, dev, msg, size);
282 genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
283 d_printf(1, dev, "CTX: genl multicast done\n");
284 return 0;
285}
286EXPORT_SYMBOL_GPL(wimax_msg_send);
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name,
310 const void *buf, size_t size, gfp_t gfp_flags)
311{
312 int result = -ENOMEM;
313 struct sk_buff *skb;
314
315 skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags);
316 if (IS_ERR(skb))
317 result = PTR_ERR(skb);
318 else
319 result = wimax_msg_send(wimax_dev, skb);
320 return result;
321}
322EXPORT_SYMBOL_GPL(wimax_msg);
323
324
325static const struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = {
326 [WIMAX_GNL_MSG_IFIDX] = {
327 .type = NLA_U32,
328 },
329 [WIMAX_GNL_MSG_DATA] = {
330 .type = NLA_UNSPEC,
331 },
332};
333
334
335
336
337
338
339
340
341
342
343static
344int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
345{
346 int result, ifindex;
347 struct wimax_dev *wimax_dev;
348 struct device *dev;
349 struct nlmsghdr *nlh = info->nlhdr;
350 char *pipe_name;
351 void *msg_buf;
352 size_t msg_len;
353
354 might_sleep();
355 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
356 result = -ENODEV;
357 if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) {
358 printk(KERN_ERR "WIMAX_GNL_MSG_FROM_USER: can't find IFIDX "
359 "attribute\n");
360 goto error_no_wimax_dev;
361 }
362 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]);
363 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
364 if (wimax_dev == NULL)
365 goto error_no_wimax_dev;
366 dev = wimax_dev_to_dev(wimax_dev);
367
368
369 result = -EINVAL;
370 if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) {
371 dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA "
372 "attribute\n");
373 goto error_no_data;
374 }
375 msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]);
376 msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]);
377
378 if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL)
379 pipe_name = NULL;
380 else {
381 struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME];
382 size_t attr_len = nla_len(attr);
383
384 result = -ENOMEM;
385 pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL);
386 if (pipe_name == NULL)
387 goto error_alloc;
388 pipe_name[attr_len] = 0;
389 }
390 mutex_lock(&wimax_dev->mutex);
391 result = wimax_dev_is_ready(wimax_dev);
392 if (result == -ENOMEDIUM)
393 result = 0;
394 if (result < 0)
395 goto error_not_ready;
396 result = -ENOSYS;
397 if (wimax_dev->op_msg_from_user == NULL)
398 goto error_noop;
399
400 d_printf(1, dev,
401 "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
402 nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags,
403 nlh->nlmsg_seq, nlh->nlmsg_pid);
404 d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len);
405 d_dump(2, dev, msg_buf, msg_len);
406
407 result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name,
408 msg_buf, msg_len, info);
409error_noop:
410error_not_ready:
411 mutex_unlock(&wimax_dev->mutex);
412error_alloc:
413 kfree(pipe_name);
414error_no_data:
415 dev_put(wimax_dev->net_dev);
416error_no_wimax_dev:
417 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
418 return result;
419}
420
421
422
423
424
425
426struct genl_ops wimax_gnl_msg_from_user = {
427 .cmd = WIMAX_GNL_OP_MSG_FROM_USER,
428 .flags = GENL_ADMIN_PERM,
429 .policy = wimax_gnl_msg_policy,
430 .doit = wimax_gnl_doit_msg_from_user,
431 .dumpit = NULL,
432};
433
434