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 "wimax-internal.h"
81
82
83#define D_SUBMODULE op_msg
84#include "debug-levels.h"
85
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
119struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
120 const char *pipe_name,
121 const void *msg, size_t size,
122 gfp_t gfp_flags)
123{
124 int result;
125 struct device *dev = wimax_dev_to_dev(wimax_dev);
126 size_t msg_size;
127 void *genl_msg;
128 struct sk_buff *skb;
129
130 msg_size = nla_total_size(size)
131 + nla_total_size(sizeof(u32))
132 + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0);
133 result = -ENOMEM;
134 skb = genlmsg_new(msg_size, gfp_flags);
135 if (skb == NULL)
136 goto error_new;
137 genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family,
138 0, WIMAX_GNL_OP_MSG_TO_USER);
139 if (genl_msg == NULL) {
140 dev_err(dev, "no memory to create generic netlink message\n");
141 goto error_genlmsg_put;
142 }
143 result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX,
144 wimax_dev->net_dev->ifindex);
145 if (result < 0) {
146 dev_err(dev, "no memory to add ifindex attribute\n");
147 goto error_nla_put;
148 }
149 if (pipe_name) {
150 result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME,
151 pipe_name);
152 if (result < 0) {
153 dev_err(dev, "no memory to add pipe_name attribute\n");
154 goto error_nla_put;
155 }
156 }
157 result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg);
158 if (result < 0) {
159 dev_err(dev, "no memory to add payload (msg %p size %zu) in "
160 "attribute: %d\n", msg, size, result);
161 goto error_nla_put;
162 }
163 genlmsg_end(skb, genl_msg);
164 return skb;
165
166error_nla_put:
167error_genlmsg_put:
168error_new:
169 nlmsg_free(skb);
170 return ERR_PTR(result);
171}
172EXPORT_SYMBOL_GPL(wimax_msg_alloc);
173
174
175
176
177
178
179
180
181
182
183const void *wimax_msg_data_len(struct sk_buff *msg, size_t *size)
184{
185 struct nlmsghdr *nlh = (void *) msg->head;
186 struct nlattr *nla;
187
188 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
189 WIMAX_GNL_MSG_DATA);
190 if (nla == NULL) {
191 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
192 return NULL;
193 }
194 *size = nla_len(nla);
195 return nla_data(nla);
196}
197EXPORT_SYMBOL_GPL(wimax_msg_data_len);
198
199
200
201
202
203
204
205const void *wimax_msg_data(struct sk_buff *msg)
206{
207 struct nlmsghdr *nlh = (void *) msg->head;
208 struct nlattr *nla;
209
210 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
211 WIMAX_GNL_MSG_DATA);
212 if (nla == NULL) {
213 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
214 return NULL;
215 }
216 return nla_data(nla);
217}
218EXPORT_SYMBOL_GPL(wimax_msg_data);
219
220
221
222
223
224
225
226ssize_t wimax_msg_len(struct sk_buff *msg)
227{
228 struct nlmsghdr *nlh = (void *) msg->head;
229 struct nlattr *nla;
230
231 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
232 WIMAX_GNL_MSG_DATA);
233 if (nla == NULL) {
234 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
235 return -EINVAL;
236 }
237 return nla_len(nla);
238}
239EXPORT_SYMBOL_GPL(wimax_msg_len);
240
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
272int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
273{
274 struct device *dev = wimax_dev_to_dev(wimax_dev);
275 void *msg = skb->data;
276 size_t size = skb->len;
277 might_sleep();
278
279 d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
280 d_dump(2, dev, msg, size);
281 genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
282 d_printf(1, dev, "CTX: genl multicast done\n");
283 return 0;
284}
285EXPORT_SYMBOL_GPL(wimax_msg_send);
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name,
309 const void *buf, size_t size, gfp_t gfp_flags)
310{
311 int result = -ENOMEM;
312 struct sk_buff *skb;
313
314 skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags);
315 if (IS_ERR(skb))
316 result = PTR_ERR(skb);
317 else
318 result = wimax_msg_send(wimax_dev, skb);
319 return result;
320}
321EXPORT_SYMBOL_GPL(wimax_msg);
322
323
324static const struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = {
325 [WIMAX_GNL_MSG_IFIDX] = {
326 .type = NLA_U32,
327 },
328 [WIMAX_GNL_MSG_DATA] = {
329 .type = NLA_UNSPEC,
330 },
331};
332
333
334
335
336
337
338
339
340
341
342static
343int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
344{
345 int result, ifindex;
346 struct wimax_dev *wimax_dev;
347 struct device *dev;
348 struct nlmsghdr *nlh = info->nlhdr;
349 char *pipe_name;
350 void *msg_buf;
351 size_t msg_len;
352
353 might_sleep();
354 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
355 result = -ENODEV;
356 if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) {
357 printk(KERN_ERR "WIMAX_GNL_MSG_FROM_USER: can't find IFIDX "
358 "attribute\n");
359 goto error_no_wimax_dev;
360 }
361 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]);
362 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
363 if (wimax_dev == NULL)
364 goto error_no_wimax_dev;
365 dev = wimax_dev_to_dev(wimax_dev);
366
367
368 result = -EINVAL;
369 if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) {
370 dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA "
371 "attribute\n");
372 goto error_no_data;
373 }
374 msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]);
375 msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]);
376
377 if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL)
378 pipe_name = NULL;
379 else {
380 struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME];
381 size_t attr_len = nla_len(attr);
382
383 result = -ENOMEM;
384 pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL);
385 if (pipe_name == NULL)
386 goto error_alloc;
387 pipe_name[attr_len] = 0;
388 }
389 mutex_lock(&wimax_dev->mutex);
390 result = wimax_dev_is_ready(wimax_dev);
391 if (result == -ENOMEDIUM)
392 result = 0;
393 if (result < 0)
394 goto error_not_ready;
395 result = -ENOSYS;
396 if (wimax_dev->op_msg_from_user == NULL)
397 goto error_noop;
398
399 d_printf(1, dev,
400 "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
401 nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags,
402 nlh->nlmsg_seq, nlh->nlmsg_pid);
403 d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len);
404 d_dump(2, dev, msg_buf, msg_len);
405
406 result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name,
407 msg_buf, msg_len, info);
408error_noop:
409error_not_ready:
410 mutex_unlock(&wimax_dev->mutex);
411error_alloc:
412 kfree(pipe_name);
413error_no_data:
414 dev_put(wimax_dev->net_dev);
415error_no_wimax_dev:
416 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
417 return result;
418}
419
420
421
422
423
424
425struct genl_ops wimax_gnl_msg_from_user = {
426 .cmd = WIMAX_GNL_OP_MSG_FROM_USER,
427 .flags = GENL_ADMIN_PERM,
428 .policy = wimax_gnl_msg_policy,
429 .doit = wimax_gnl_doit_msg_from_user,
430 .dumpit = NULL,
431};
432
433