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 pr_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 pr_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 pr_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(&wimax_gnl_family, skb, 0, 0, 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
325
326
327
328
329
330
331
332int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
333{
334 int result, ifindex;
335 struct wimax_dev *wimax_dev;
336 struct device *dev;
337 struct nlmsghdr *nlh = info->nlhdr;
338 char *pipe_name;
339 void *msg_buf;
340 size_t msg_len;
341
342 might_sleep();
343 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
344 result = -ENODEV;
345 if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) {
346 pr_err("WIMAX_GNL_MSG_FROM_USER: can't find IFIDX attribute\n");
347 goto error_no_wimax_dev;
348 }
349 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]);
350 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
351 if (wimax_dev == NULL)
352 goto error_no_wimax_dev;
353 dev = wimax_dev_to_dev(wimax_dev);
354
355
356 result = -EINVAL;
357 if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) {
358 dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA "
359 "attribute\n");
360 goto error_no_data;
361 }
362 msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]);
363 msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]);
364
365 if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL)
366 pipe_name = NULL;
367 else {
368 struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME];
369 size_t attr_len = nla_len(attr);
370
371 result = -ENOMEM;
372 pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL);
373 if (pipe_name == NULL)
374 goto error_alloc;
375 pipe_name[attr_len] = 0;
376 }
377 mutex_lock(&wimax_dev->mutex);
378 result = wimax_dev_is_ready(wimax_dev);
379 if (result == -ENOMEDIUM)
380 result = 0;
381 if (result < 0)
382 goto error_not_ready;
383 result = -ENOSYS;
384 if (wimax_dev->op_msg_from_user == NULL)
385 goto error_noop;
386
387 d_printf(1, dev,
388 "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
389 nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags,
390 nlh->nlmsg_seq, nlh->nlmsg_pid);
391 d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len);
392 d_dump(2, dev, msg_buf, msg_len);
393
394 result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name,
395 msg_buf, msg_len, info);
396error_noop:
397error_not_ready:
398 mutex_unlock(&wimax_dev->mutex);
399error_alloc:
400 kfree(pipe_name);
401error_no_data:
402 dev_put(wimax_dev->net_dev);
403error_no_wimax_dev:
404 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
405 return result;
406}
407
408