aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2009-07-21 07:25:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-24 15:05:29 -0400
commitf298c282a5233126ffe6385c02a9e79f695bed0f (patch)
treef4500c35caa1dffd355da6104e408c7f521f2b86 /drivers/net/wireless
parentf974cfdd8112a081fb1a402bf77835f28f37fcad (diff)
wl1251: remove accidentally added wl1251_netlink.c
Commit "wl1251: add wl1251 prefix to all 1251 files" accidentally added wl1251_netlink.c which contains a private netlink interface. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.c679
1 files changed, 0 insertions, 679 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c
deleted file mode 100644
index 67d3d5a3b519..000000000000
--- a/drivers/net/wireless/wl12xx/wl1251_netlink.c
+++ /dev/null
@@ -1,679 +0,0 @@
1/*
2 * This file is part of wl1251
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 *
6 * Contact: Kalle Valo <kalle.valo@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23#include "wl1251_netlink.h"
24
25#include <linux/mutex.h>
26#include <linux/socket.h>
27#include <net/net_namespace.h>
28#include <net/sock.h>
29#include <net/genetlink.h>
30#include <net/wireless.h>
31#include <net/mac80211.h>
32
33#include "wl1251.h"
34#include "wl1251_spi.h"
35#include "wl1251_acx.h"
36
37/* FIXME: this should be changed as soon as user space catches up */
38#define WL1251_NL_NAME "wl1251"
39#define WL1251_NL_VERSION 1
40
41#define WL1251_MAX_TEST_LENGTH 1024
42#define WL1251_MAX_NVS_LENGTH 1024
43
44enum wl1251_nl_commands {
45 WL1251_NL_CMD_UNSPEC,
46 WL1251_NL_CMD_TEST,
47 WL1251_NL_CMD_INTERROGATE,
48 WL1251_NL_CMD_CONFIGURE,
49 WL1251_NL_CMD_PHY_REG_READ,
50 WL1251_NL_CMD_NVS_PUSH,
51 WL1251_NL_CMD_REG_WRITE,
52 WL1251_NL_CMD_REG_READ,
53 WL1251_NL_CMD_SET_PLT_MODE,
54
55 __WL1251_NL_CMD_AFTER_LAST
56};
57#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1)
58
59enum wl1251_nl_attrs {
60 WL1251_NL_ATTR_UNSPEC,
61 WL1251_NL_ATTR_IFNAME,
62 WL1251_NL_ATTR_CMD_TEST_PARAM,
63 WL1251_NL_ATTR_CMD_TEST_ANSWER,
64 WL1251_NL_ATTR_CMD_IE,
65 WL1251_NL_ATTR_CMD_IE_LEN,
66 WL1251_NL_ATTR_CMD_IE_BUFFER,
67 WL1251_NL_ATTR_CMD_IE_ANSWER,
68 WL1251_NL_ATTR_REG_ADDR,
69 WL1251_NL_ATTR_REG_VAL,
70 WL1251_NL_ATTR_NVS_BUFFER,
71 WL1251_NL_ATTR_NVS_LEN,
72 WL1251_NL_ATTR_PLT_MODE,
73
74 __WL1251_NL_ATTR_AFTER_LAST
75};
76#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1)
77
78static struct genl_family wl1251_nl_family = {
79 .id = GENL_ID_GENERATE,
80 .name = WL1251_NL_NAME,
81 .hdrsize = 0,
82 .version = WL1251_NL_VERSION,
83 .maxattr = WL1251_NL_ATTR_MAX,
84};
85
86static struct net_device *ifname_to_netdev(struct net *net,
87 struct genl_info *info)
88{
89 char *ifname;
90
91 if (!info->attrs[WL1251_NL_ATTR_IFNAME])
92 return NULL;
93
94 ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]);
95
96 wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname);
97
98 return dev_get_by_name(net, ifname);
99}
100
101static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info)
102{
103 struct net_device *netdev;
104 struct wireless_dev *wdev;
105 struct wiphy *wiphy;
106 struct ieee80211_hw *hw;
107
108 netdev = ifname_to_netdev(net, info);
109 if (netdev == NULL) {
110 wl1251_error("Wrong interface");
111 return NULL;
112 }
113
114 wdev = netdev->ieee80211_ptr;
115 if (wdev == NULL) {
116 wl1251_error("ieee80211_ptr is NULL");
117 return NULL;
118 }
119
120 wiphy = wdev->wiphy;
121 if (wiphy == NULL) {
122 wl1251_error("wiphy is NULL");
123 return NULL;
124 }
125
126 hw = wiphy_priv(wiphy);
127 if (hw == NULL) {
128 wl1251_error("hw is NULL");
129 return NULL;
130 }
131
132 dev_put(netdev);
133
134 return hw->priv;
135}
136
137static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
138{
139 struct wl1251 *wl;
140 struct wl1251_command *cmd;
141 char *buf;
142 int buf_len, ret, cmd_len;
143 u8 answer;
144
145 if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM])
146 return -EINVAL;
147
148 wl = ifname_to_wl1251(&init_net, info);
149 if (wl == NULL) {
150 wl1251_error("wl1251 not found");
151 return -EINVAL;
152 }
153
154 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
155 if (!cmd)
156 return -ENOMEM;
157
158 buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
159 buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
160 answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]);
161
162 cmd->header.id = CMD_TEST;
163 memcpy(cmd->parameters, buf, buf_len);
164 cmd_len = sizeof(struct wl1251_cmd_header) + buf_len;
165
166 mutex_lock(&wl->mutex);
167 ret = wl1251_cmd_test(wl, cmd, cmd_len, answer);
168 mutex_unlock(&wl->mutex);
169
170 if (ret < 0) {
171 wl1251_error("%s() failed", __func__);
172 goto out;
173 }
174
175 if (answer) {
176 struct sk_buff *msg;
177 void *hdr;
178
179 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
180 if (!msg) {
181 ret = -ENOMEM;
182 goto out;
183 }
184
185 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
186 &wl1251_nl_family, 0, WL1251_NL_CMD_TEST);
187 if (IS_ERR(hdr)) {
188 ret = PTR_ERR(hdr);
189 goto nla_put_failure;
190 }
191
192 NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
193 nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
194 NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER,
195 sizeof(*cmd), cmd);
196
197 ret = genlmsg_end(msg, hdr);
198 if (ret < 0) {
199 wl1251_error("%s() failed", __func__);
200 goto nla_put_failure;
201 }
202
203 wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
204 ret = genlmsg_reply(msg, info);
205 goto out;
206
207 nla_put_failure:
208 nlmsg_free(msg);
209 } else
210 wl1251_debug(DEBUG_NETLINK, "TEST cmd sent");
211
212out:
213 kfree(cmd);
214 return ret;
215}
216
217static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
218{
219 struct wl1251 *wl;
220 struct sk_buff *msg;
221 int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
222 struct wl1251_command *cmd;
223 void *hdr;
224
225 if (!info->attrs[WL1251_NL_ATTR_CMD_IE])
226 return -EINVAL;
227
228 if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
229 return -EINVAL;
230
231 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
232 if (!cmd)
233 return -ENOMEM;
234
235 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
236 if (!msg)
237 return -ENOMEM;
238
239 wl = ifname_to_wl1251(&init_net, info);
240 if (wl == NULL) {
241 wl1251_error("wl1251 not found");
242 ret = -EINVAL;
243 goto nla_put_failure;
244 }
245
246 /* acx id */
247 cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]);
248
249 /* maximum length of acx, including all headers */
250 cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
251
252 wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
253 cmd_ie, cmd_ie_len);
254
255 mutex_lock(&wl->mutex);
256 ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
257 mutex_unlock(&wl->mutex);
258
259 if (ret < 0) {
260 wl1251_error("%s() failed", __func__);
261 goto nla_put_failure;
262 }
263
264 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
265 &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE);
266 if (IS_ERR(hdr)) {
267 ret = PTR_ERR(hdr);
268 goto nla_put_failure;
269 }
270
271 NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
272 nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
273 NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd);
274
275 ret = genlmsg_end(msg, hdr);
276 if (ret < 0) {
277 wl1251_error("%s() failed", __func__);
278 goto nla_put_failure;
279 }
280
281 kfree(cmd);
282 return genlmsg_reply(msg, info);
283
284 nla_put_failure:
285 kfree(cmd);
286 nlmsg_free(msg);
287
288 return ret;
289}
290
291static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info)
292{
293 int ret = 0, cmd_ie_len, acx_len;
294 struct acx_header *acx = NULL;
295 struct sk_buff *msg;
296 struct wl1251 *wl;
297 void *cmd_ie;
298 u16 *id;
299
300 if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER])
301 return -EINVAL;
302
303 if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
304 return -EINVAL;
305
306 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
307 if (!msg)
308 return -ENOMEM;
309
310 wl = ifname_to_wl1251(&init_net, info);
311 if (wl == NULL) {
312 wl1251_error("wl1251 not found");
313 ret = -EINVAL;
314 goto nla_put_failure;
315 }
316
317 /* contains the acx header but not the cmd header */
318 cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]);
319
320 cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
321
322 /* acx id is in the first two bytes */
323 id = cmd_ie;
324
325 /* need to add acx_header before cmd_ie, so create a new command */
326 acx_len = sizeof(struct acx_header) + cmd_ie_len;
327 acx = kzalloc(acx_len, GFP_KERNEL);
328 if (!acx) {
329 ret = -ENOMEM;
330 goto nla_put_failure;
331 }
332
333 /* copy the acx header and the payload */
334 memcpy(&acx->id, cmd_ie, cmd_ie_len);
335
336 mutex_lock(&wl->mutex);
337 ret = wl1251_cmd_configure(wl, *id, acx, acx_len);
338 mutex_unlock(&wl->mutex);
339
340 if (ret < 0) {
341 wl1251_error("%s() failed", __func__);
342 goto nla_put_failure;
343 }
344
345 wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
346
347 nla_put_failure:
348 kfree(acx);
349 nlmsg_free(msg);
350
351 return ret;
352}
353
354static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
355{
356 struct wl1251 *wl;
357 struct sk_buff *msg;
358 u32 reg_addr, *reg_value = NULL;
359 int ret = 0;
360 void *hdr;
361
362 if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
363 return -EINVAL;
364
365 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
366 if (!msg)
367 return -ENOMEM;
368
369 wl = ifname_to_wl1251(&init_net, info);
370 if (wl == NULL) {
371 wl1251_error("wl1251 not found");
372 ret = -EINVAL;
373 goto nla_put_failure;
374 }
375
376 reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL);
377 if (!reg_value) {
378 ret = -ENOMEM;
379 goto nla_put_failure;
380 }
381
382 reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
383
384 wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
385
386 mutex_lock(&wl->mutex);
387 ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value,
388 sizeof(*reg_value));
389 mutex_unlock(&wl->mutex);
390
391 if (ret < 0) {
392 wl1251_error("%s() failed", __func__);
393 goto nla_put_failure;
394 }
395
396
397 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
398 &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
399 if (IS_ERR(hdr)) {
400 ret = PTR_ERR(hdr);
401 goto nla_put_failure;
402 }
403
404 NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
405 nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
406
407 NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value);
408
409 ret = genlmsg_end(msg, hdr);
410 if (ret < 0) {
411 wl1251_error("%s() failed", __func__);
412 goto nla_put_failure;
413 }
414
415 kfree(reg_value);
416
417 return genlmsg_reply(msg, info);
418
419 nla_put_failure:
420 nlmsg_free(msg);
421 kfree(reg_value);
422
423 return ret;
424}
425
426static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
427{
428 struct wl1251 *wl;
429 int ret = 0;
430
431 if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER])
432 return -EINVAL;
433
434 if (!info->attrs[WL1251_NL_ATTR_NVS_LEN])
435 return -EINVAL;
436
437 wl = ifname_to_wl1251(&init_net, info);
438 if (wl == NULL) {
439 wl1251_error("wl1251 not found");
440 return -EINVAL;
441 }
442
443 mutex_lock(&wl->mutex);
444 wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]);
445 if (wl->nvs_len % 4) {
446 wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len);
447 ret = -EILSEQ;
448 goto out;
449 }
450
451 /* If we already have an NVS, we should free it */
452 kfree(wl->nvs);
453
454 wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL);
455 if (wl->nvs == NULL) {
456 wl1251_error("Can't allocate NVS");
457 ret = -ENOMEM;
458 goto out;
459 }
460
461 memcpy(wl->nvs,
462 nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]),
463 wl->nvs_len);
464
465 wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
466 wl->nvs_len);
467
468out:
469 mutex_unlock(&wl->mutex);
470
471 return ret;
472}
473
474static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
475{
476 struct wl1251 *wl;
477 u32 addr, val;
478 int ret = 0;
479 struct sk_buff *msg;
480 void *hdr;
481
482 if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
483 return -EINVAL;
484
485 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
486 if (!msg)
487 return -ENOMEM;
488
489 wl = ifname_to_wl1251(&init_net, info);
490 if (wl == NULL) {
491 wl1251_error("wl1251 not found");
492 return -EINVAL;
493 }
494
495 addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
496
497 mutex_lock(&wl->mutex);
498 val = wl1251_reg_read32(wl, addr);
499 mutex_unlock(&wl->mutex);
500
501 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
502 &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
503 if (IS_ERR(hdr)) {
504 ret = PTR_ERR(hdr);
505 goto nla_put_failure;
506 }
507
508 NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
509 nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
510
511 NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val);
512
513 ret = genlmsg_end(msg, hdr);
514 if (ret < 0) {
515 wl1251_error("%s() failed", __func__);
516 goto nla_put_failure;
517 }
518
519 return genlmsg_reply(msg, info);
520
521 nla_put_failure:
522 nlmsg_free(msg);
523
524 return ret;
525}
526
527static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
528{
529 struct wl1251 *wl;
530 u32 addr, val;
531
532 if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
533 return -EINVAL;
534
535 if (!info->attrs[WL1251_NL_ATTR_REG_VAL])
536 return -EINVAL;
537
538 wl = ifname_to_wl1251(&init_net, info);
539 if (wl == NULL) {
540 wl1251_error("wl1251 not found");
541 return -EINVAL;
542 }
543
544 addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
545 val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]);
546
547 mutex_lock(&wl->mutex);
548 wl1251_reg_write32(wl, addr, val);
549 mutex_unlock(&wl->mutex);
550
551 return 0;
552}
553
554static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
555{
556 struct wl1251 *wl;
557 u32 val;
558 int ret;
559
560 if (!info->attrs[WL1251_NL_ATTR_PLT_MODE])
561 return -EINVAL;
562
563 wl = ifname_to_wl1251(&init_net, info);
564 if (wl == NULL) {
565 wl1251_error("wl1251 not found");
566 return -EINVAL;
567 }
568
569 val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]);
570
571 switch (val) {
572 case 0:
573 ret = wl1251_plt_stop(wl);
574 break;
575 case 1:
576 ret = wl1251_plt_start(wl);
577 break;
578 default:
579 ret = -EINVAL;
580 break;
581 }
582
583 return ret;
584}
585
586static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = {
587 [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
588 .len = IFNAMSIZ-1 },
589 [WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY,
590 .len = WL1251_MAX_TEST_LENGTH },
591 [WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 },
592 [WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 },
593 [WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 },
594 [WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY,
595 .len = WL1251_MAX_TEST_LENGTH },
596 [WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY,
597 .len = WL1251_MAX_TEST_LENGTH },
598 [WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 },
599 [WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 },
600 [WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY,
601 .len = WL1251_MAX_NVS_LENGTH },
602 [WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 },
603 [WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 },
604};
605
606static struct genl_ops wl1251_nl_ops[] = {
607 {
608 .cmd = WL1251_NL_CMD_TEST,
609 .doit = wl1251_nl_test_cmd,
610 .policy = wl1251_nl_policy,
611 .flags = GENL_ADMIN_PERM,
612 },
613 {
614 .cmd = WL1251_NL_CMD_INTERROGATE,
615 .doit = wl1251_nl_interrogate,
616 .policy = wl1251_nl_policy,
617 .flags = GENL_ADMIN_PERM,
618 },
619 {
620 .cmd = WL1251_NL_CMD_CONFIGURE,
621 .doit = wl1251_nl_configure,
622 .policy = wl1251_nl_policy,
623 .flags = GENL_ADMIN_PERM,
624 },
625 {
626 .cmd = WL1251_NL_CMD_PHY_REG_READ,
627 .doit = wl1251_nl_phy_reg_read,
628 .policy = wl1251_nl_policy,
629 .flags = GENL_ADMIN_PERM,
630 },
631 {
632 .cmd = WL1251_NL_CMD_NVS_PUSH,
633 .doit = wl1251_nl_nvs_push,
634 .policy = wl1251_nl_policy,
635 .flags = GENL_ADMIN_PERM,
636 },
637 {
638 .cmd = WL1251_NL_CMD_REG_WRITE,
639 .doit = wl1251_nl_reg_write,
640 .policy = wl1251_nl_policy,
641 .flags = GENL_ADMIN_PERM,
642 },
643 {
644 .cmd = WL1251_NL_CMD_REG_READ,
645 .doit = wl1251_nl_reg_read,
646 .policy = wl1251_nl_policy,
647 .flags = GENL_ADMIN_PERM,
648 },
649 {
650 .cmd = WL1251_NL_CMD_SET_PLT_MODE,
651 .doit = wl1251_nl_set_plt_mode,
652 .policy = wl1251_nl_policy,
653 .flags = GENL_ADMIN_PERM,
654 },
655};
656
657int wl1251_nl_register(void)
658{
659 int err, i;
660
661 err = genl_register_family(&wl1251_nl_family);
662 if (err)
663 return err;
664
665 for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) {
666 err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]);
667 if (err)
668 goto err_out;
669 }
670 return 0;
671 err_out:
672 genl_unregister_family(&wl1251_nl_family);
673 return err;
674}
675
676void wl1251_nl_unregister(void)
677{
678 genl_unregister_family(&wl1251_nl_family);
679}