2 * This file is part of wl12xx
4 * Copyright (C) 2008 Nokia Corporation
6 * Contact: Kalle Valo <kalle.valo@nokia.com>
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.
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.
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
23 #include "wl1251_netlink.h"
25 #include <linux/mutex.h>
26 #include <linux/socket.h>
27 #include <net/net_namespace.h>
29 #include <net/genetlink.h>
30 #include <net/wireless.h>
31 #include <net/mac80211.h>
34 #include "wl1251_spi.h"
35 #include "wl1251_acx.h"
37 /* FIXME: this should be changed as soon as user space catches up */
38 #define WL12XX_NL_NAME "wl1251"
39 #define WL12XX_NL_VERSION 1
41 #define WL12XX_MAX_TEST_LENGTH 1024
42 #define WL12XX_MAX_NVS_LENGTH 1024
44 enum wl12xx_nl_commands {
47 WL12XX_NL_CMD_INTERROGATE,
48 WL12XX_NL_CMD_CONFIGURE,
49 WL12XX_NL_CMD_PHY_REG_READ,
50 WL12XX_NL_CMD_NVS_PUSH,
51 WL12XX_NL_CMD_REG_WRITE,
52 WL12XX_NL_CMD_REG_READ,
53 WL12XX_NL_CMD_SET_PLT_MODE,
55 __WL12XX_NL_CMD_AFTER_LAST
57 #define WL12XX_NL_CMD_MAX (__WL12XX_NL_CMD_AFTER_LAST - 1)
59 enum wl12xx_nl_attrs {
60 WL12XX_NL_ATTR_UNSPEC,
61 WL12XX_NL_ATTR_IFNAME,
62 WL12XX_NL_ATTR_CMD_TEST_PARAM,
63 WL12XX_NL_ATTR_CMD_TEST_ANSWER,
64 WL12XX_NL_ATTR_CMD_IE,
65 WL12XX_NL_ATTR_CMD_IE_LEN,
66 WL12XX_NL_ATTR_CMD_IE_BUFFER,
67 WL12XX_NL_ATTR_CMD_IE_ANSWER,
68 WL12XX_NL_ATTR_REG_ADDR,
69 WL12XX_NL_ATTR_REG_VAL,
70 WL12XX_NL_ATTR_NVS_BUFFER,
71 WL12XX_NL_ATTR_NVS_LEN,
72 WL12XX_NL_ATTR_PLT_MODE,
74 __WL12XX_NL_ATTR_AFTER_LAST
76 #define WL12XX_NL_ATTR_MAX (__WL12XX_NL_ATTR_AFTER_LAST - 1)
78 static struct genl_family wl12xx_nl_family = {
79 .id = GENL_ID_GENERATE,
80 .name = WL12XX_NL_NAME,
82 .version = WL12XX_NL_VERSION,
83 .maxattr = WL12XX_NL_ATTR_MAX,
86 static struct net_device *ifname_to_netdev(struct net *net,
87 struct genl_info *info)
91 if (!info->attrs[WL12XX_NL_ATTR_IFNAME])
94 ifname = nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]);
96 wl12xx_debug(DEBUG_NETLINK, "Looking for %s", ifname);
98 return dev_get_by_name(net, ifname);
101 static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info)
103 struct net_device *netdev;
104 struct wireless_dev *wdev;
106 struct ieee80211_hw *hw;
108 netdev = ifname_to_netdev(net, info);
109 if (netdev == NULL) {
110 wl12xx_error("Wrong interface");
114 wdev = netdev->ieee80211_ptr;
116 wl12xx_error("ieee80211_ptr is NULL");
122 wl12xx_error("wiphy is NULL");
126 hw = wiphy_priv(wiphy);
128 wl12xx_error("hw is NULL");
137 static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
140 struct wl12xx_command *cmd;
142 int buf_len, ret, cmd_len;
145 if (!info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM])
148 wl = ifname_to_wl12xx(&init_net, info);
150 wl12xx_error("wl12xx not found");
154 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
158 buf = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]);
159 buf_len = nla_len(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]);
160 answer = nla_get_u8(info->attrs[WL12XX_NL_ATTR_CMD_TEST_ANSWER]);
162 cmd->header.id = CMD_TEST;
163 memcpy(cmd->parameters, buf, buf_len);
164 cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len;
166 mutex_lock(&wl->mutex);
167 ret = wl12xx_cmd_test(wl, cmd, cmd_len, answer);
168 mutex_unlock(&wl->mutex);
171 wl12xx_error("%s() failed", __func__);
179 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
185 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
186 &wl12xx_nl_family, 0, WL12XX_NL_CMD_TEST);
189 goto nla_put_failure;
192 NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
193 nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
194 NLA_PUT(msg, WL12XX_NL_ATTR_CMD_TEST_ANSWER,
197 ret = genlmsg_end(msg, hdr);
199 wl12xx_error("%s() failed", __func__);
200 goto nla_put_failure;
203 wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
204 ret = genlmsg_reply(msg, info);
210 wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent");
217 static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
221 int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
222 struct wl12xx_command *cmd;
225 if (!info->attrs[WL12XX_NL_ATTR_CMD_IE])
228 if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN])
231 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
235 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
239 wl = ifname_to_wl12xx(&init_net, info);
241 wl12xx_error("wl12xx not found");
243 goto nla_put_failure;
247 cmd_ie = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE]);
249 /* maximum length of acx, including all headers */
250 cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]);
252 wl12xx_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
255 mutex_lock(&wl->mutex);
256 ret = wl12xx_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
257 mutex_unlock(&wl->mutex);
260 wl12xx_error("%s() failed", __func__);
261 goto nla_put_failure;
264 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
265 &wl12xx_nl_family, 0, WL12XX_NL_CMD_INTERROGATE);
268 goto nla_put_failure;
271 NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
272 nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
273 NLA_PUT(msg, WL12XX_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd);
275 ret = genlmsg_end(msg, hdr);
277 wl12xx_error("%s() failed", __func__);
278 goto nla_put_failure;
282 return genlmsg_reply(msg, info);
291 static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info)
293 int ret = 0, cmd_ie_len, acx_len;
294 struct acx_header *acx = NULL;
300 if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER])
303 if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN])
306 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
310 wl = ifname_to_wl12xx(&init_net, info);
312 wl12xx_error("wl12xx not found");
314 goto nla_put_failure;
317 /* contains the acx header but not the cmd header */
318 cmd_ie = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]);
320 cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]);
322 /* acx id is in the first two bytes */
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);
330 goto nla_put_failure;
333 /* copy the acx header and the payload */
334 memcpy(&acx->id, cmd_ie, cmd_ie_len);
336 mutex_lock(&wl->mutex);
337 ret = wl12xx_cmd_configure(wl, *id, acx, acx_len);
338 mutex_unlock(&wl->mutex);
341 wl12xx_error("%s() failed", __func__);
342 goto nla_put_failure;
345 wl12xx_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
354 static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
358 u32 reg_addr, *reg_value = NULL;
362 if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR])
365 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
369 wl = ifname_to_wl12xx(&init_net, info);
371 wl12xx_error("wl12xx not found");
373 goto nla_put_failure;
376 reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL);
379 goto nla_put_failure;
382 reg_addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]);
384 wl12xx_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
386 mutex_lock(&wl->mutex);
387 ret = wl12xx_cmd_read_memory(wl, reg_addr, reg_value,
389 mutex_unlock(&wl->mutex);
392 wl12xx_error("%s() failed", __func__);
393 goto nla_put_failure;
397 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
398 &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ);
401 goto nla_put_failure;
404 NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
405 nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
407 NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, *reg_value);
409 ret = genlmsg_end(msg, hdr);
411 wl12xx_error("%s() failed", __func__);
412 goto nla_put_failure;
417 return genlmsg_reply(msg, info);
426 static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
431 if (!info->attrs[WL12XX_NL_ATTR_NVS_BUFFER])
434 if (!info->attrs[WL12XX_NL_ATTR_NVS_LEN])
437 wl = ifname_to_wl12xx(&init_net, info);
439 wl12xx_error("wl12xx not found");
443 mutex_lock(&wl->mutex);
444 wl->nvs_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_NVS_LEN]);
445 if (wl->nvs_len % 4) {
446 wl12xx_error("NVS size is not multiple of 32: %d", wl->nvs_len);
451 /* If we already have an NVS, we should free it */
454 wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL);
455 if (wl->nvs == NULL) {
456 wl12xx_error("Can't allocate NVS");
462 nla_data(info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]),
465 wl12xx_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
469 mutex_unlock(&wl->mutex);
474 static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
482 if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR])
485 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
489 wl = ifname_to_wl12xx(&init_net, info);
491 wl12xx_error("wl12xx not found");
495 addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]);
497 mutex_lock(&wl->mutex);
498 val = wl12xx_reg_read32(wl, addr);
499 mutex_unlock(&wl->mutex);
501 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
502 &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ);
505 goto nla_put_failure;
508 NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
509 nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
511 NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, val);
513 ret = genlmsg_end(msg, hdr);
515 wl12xx_error("%s() failed", __func__);
516 goto nla_put_failure;
519 return genlmsg_reply(msg, info);
527 static int wl12xx_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
532 if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR])
535 if (!info->attrs[WL12XX_NL_ATTR_REG_VAL])
538 wl = ifname_to_wl12xx(&init_net, info);
540 wl12xx_error("wl12xx not found");
544 addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]);
545 val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_VAL]);
547 mutex_lock(&wl->mutex);
548 wl12xx_reg_write32(wl, addr, val);
549 mutex_unlock(&wl->mutex);
554 static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
560 if (!info->attrs[WL12XX_NL_ATTR_PLT_MODE])
563 wl = ifname_to_wl12xx(&init_net, info);
565 wl12xx_error("wl12xx not found");
569 val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_PLT_MODE]);
573 ret = wl12xx_plt_stop(wl);
576 ret = wl12xx_plt_start(wl);
586 static struct nla_policy wl12xx_nl_policy[WL12XX_NL_ATTR_MAX + 1] = {
587 [WL12XX_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
589 [WL12XX_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY,
590 .len = WL12XX_MAX_TEST_LENGTH },
591 [WL12XX_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 },
592 [WL12XX_NL_ATTR_CMD_IE] = { .type = NLA_U32 },
593 [WL12XX_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 },
594 [WL12XX_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY,
595 .len = WL12XX_MAX_TEST_LENGTH },
596 [WL12XX_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY,
597 .len = WL12XX_MAX_TEST_LENGTH },
598 [WL12XX_NL_ATTR_REG_ADDR] = { .type = NLA_U32 },
599 [WL12XX_NL_ATTR_REG_VAL] = { .type = NLA_U32 },
600 [WL12XX_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY,
601 .len = WL12XX_MAX_NVS_LENGTH },
602 [WL12XX_NL_ATTR_NVS_LEN] = { .type = NLA_U32 },
603 [WL12XX_NL_ATTR_PLT_MODE] = { .type = NLA_U32 },
606 static struct genl_ops wl12xx_nl_ops[] = {
608 .cmd = WL12XX_NL_CMD_TEST,
609 .doit = wl12xx_nl_test_cmd,
610 .policy = wl12xx_nl_policy,
611 .flags = GENL_ADMIN_PERM,
614 .cmd = WL12XX_NL_CMD_INTERROGATE,
615 .doit = wl12xx_nl_interrogate,
616 .policy = wl12xx_nl_policy,
617 .flags = GENL_ADMIN_PERM,
620 .cmd = WL12XX_NL_CMD_CONFIGURE,
621 .doit = wl12xx_nl_configure,
622 .policy = wl12xx_nl_policy,
623 .flags = GENL_ADMIN_PERM,
626 .cmd = WL12XX_NL_CMD_PHY_REG_READ,
627 .doit = wl12xx_nl_phy_reg_read,
628 .policy = wl12xx_nl_policy,
629 .flags = GENL_ADMIN_PERM,
632 .cmd = WL12XX_NL_CMD_NVS_PUSH,
633 .doit = wl12xx_nl_nvs_push,
634 .policy = wl12xx_nl_policy,
635 .flags = GENL_ADMIN_PERM,
638 .cmd = WL12XX_NL_CMD_REG_WRITE,
639 .doit = wl12xx_nl_reg_write,
640 .policy = wl12xx_nl_policy,
641 .flags = GENL_ADMIN_PERM,
644 .cmd = WL12XX_NL_CMD_REG_READ,
645 .doit = wl12xx_nl_reg_read,
646 .policy = wl12xx_nl_policy,
647 .flags = GENL_ADMIN_PERM,
650 .cmd = WL12XX_NL_CMD_SET_PLT_MODE,
651 .doit = wl12xx_nl_set_plt_mode,
652 .policy = wl12xx_nl_policy,
653 .flags = GENL_ADMIN_PERM,
657 int wl12xx_nl_register(void)
661 err = genl_register_family(&wl12xx_nl_family);
665 for (i = 0; i < ARRAY_SIZE(wl12xx_nl_ops); i++) {
666 err = genl_register_ops(&wl12xx_nl_family, &wl12xx_nl_ops[i]);
672 genl_unregister_family(&wl12xx_nl_family);
676 void wl12xx_nl_unregister(void)
678 genl_unregister_family(&wl12xx_nl_family);