2 * Copyright (c) 2014 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/vmalloc.h>
18 #include <net/cfg80211.h>
19 #include <net/netlink.h>
21 #include <brcmu_wifi.h>
22 #include "fwil_types.h"
30 static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy
*wiphy
,
31 struct wireless_dev
*wdev
,
32 const void *data
, int len
)
34 struct brcmf_cfg80211_vif
*vif
;
36 const struct brcmf_vndr_dcmd_hdr
*cmdhdr
= data
;
37 struct sk_buff
*reply
;
38 unsigned int payload
, ret_len
;
39 void *dcmd_buf
= NULL
, *wr_pointer
;
40 u16 msglen
, maxmsglen
= PAGE_SIZE
- 0x100;
43 if (len
< sizeof(*cmdhdr
)) {
44 brcmf_err("vendor command too short: %d\n", len
);
48 vif
= container_of(wdev
, struct brcmf_cfg80211_vif
, wdev
);
51 brcmf_dbg(TRACE
, "ifidx=%d, cmd=%d\n", ifp
->ifidx
, cmdhdr
->cmd
);
53 if (cmdhdr
->offset
> len
) {
54 brcmf_err("bad buffer offset %d > %d\n", cmdhdr
->offset
, len
);
58 len
-= cmdhdr
->offset
;
59 ret_len
= cmdhdr
->len
;
60 if (ret_len
> 0 || len
> 0) {
61 if (len
> BRCMF_DCMD_MAXLEN
) {
62 brcmf_err("oversize input buffer %d\n", len
);
63 len
= BRCMF_DCMD_MAXLEN
;
65 if (ret_len
> BRCMF_DCMD_MAXLEN
) {
66 brcmf_err("oversize return buffer %d\n", ret_len
);
67 ret_len
= BRCMF_DCMD_MAXLEN
;
69 payload
= max_t(unsigned int, ret_len
, len
) + 1;
70 dcmd_buf
= vzalloc(payload
);
74 memcpy(dcmd_buf
, (void *)cmdhdr
+ cmdhdr
->offset
, len
);
75 *(char *)(dcmd_buf
+ len
) = '\0';
79 ret
= brcmf_fil_cmd_data_set(ifp
, cmdhdr
->cmd
, dcmd_buf
,
82 ret
= brcmf_fil_cmd_data_get(ifp
, cmdhdr
->cmd
, dcmd_buf
,
87 wr_pointer
= dcmd_buf
;
89 msglen
= ret_len
> maxmsglen
? maxmsglen
: ret_len
;
91 payload
= msglen
+ sizeof(msglen
);
92 reply
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, payload
);
98 if (nla_put(reply
, BRCMF_NLATTR_DATA
, msglen
, wr_pointer
) ||
99 nla_put_u16(reply
, BRCMF_NLATTR_LEN
, msglen
)) {
105 ret
= cfg80211_vendor_cmd_reply(reply
);
109 wr_pointer
+= msglen
;
118 const struct wiphy_vendor_command brcmf_vendor_cmds
[] = {
121 .vendor_id
= BROADCOM_OUI
,
122 .subcmd
= BRCMF_VNDR_CMDS_DCMD
124 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
|
125 WIPHY_VENDOR_CMD_NEED_NETDEV
,
126 .doit
= brcmf_cfg80211_vndr_cmds_dcmd_handler