1daeccac2SArend van Spriel // SPDX-License-Identifier: ISC
205491d2cSKalle Valo /*
305491d2cSKalle Valo * Copyright (c) 2012 Broadcom Corporation
405491d2cSKalle Valo */
505491d2cSKalle Valo
605491d2cSKalle Valo /* FWIL is the Firmware Interface Layer. In this module the support functions
705491d2cSKalle Valo * are located to set and get variables to and from the firmware.
805491d2cSKalle Valo */
905491d2cSKalle Valo
1005491d2cSKalle Valo #include <linux/kernel.h>
1105491d2cSKalle Valo #include <linux/netdevice.h>
1205491d2cSKalle Valo #include <brcmu_utils.h>
1305491d2cSKalle Valo #include <brcmu_wifi.h>
1405491d2cSKalle Valo #include "core.h"
1505491d2cSKalle Valo #include "bus.h"
1605491d2cSKalle Valo #include "debug.h"
1705491d2cSKalle Valo #include "tracepoint.h"
18a7dd0ac9SArend van Spriel #include "xtlv.h"
1905491d2cSKalle Valo #include "fwil.h"
2005491d2cSKalle Valo #include "proto.h"
2105491d2cSKalle Valo
2205491d2cSKalle Valo
2305491d2cSKalle Valo #define MAX_HEX_DUMP_LEN 64
2405491d2cSKalle Valo
2505491d2cSKalle Valo #ifdef DEBUG
2605491d2cSKalle Valo static const char * const brcmf_fil_errstr[] = {
2705491d2cSKalle Valo "BCME_OK",
2805491d2cSKalle Valo "BCME_ERROR",
2905491d2cSKalle Valo "BCME_BADARG",
3005491d2cSKalle Valo "BCME_BADOPTION",
3105491d2cSKalle Valo "BCME_NOTUP",
3205491d2cSKalle Valo "BCME_NOTDOWN",
3305491d2cSKalle Valo "BCME_NOTAP",
3405491d2cSKalle Valo "BCME_NOTSTA",
3505491d2cSKalle Valo "BCME_BADKEYIDX",
3605491d2cSKalle Valo "BCME_RADIOOFF",
3705491d2cSKalle Valo "BCME_NOTBANDLOCKED",
3805491d2cSKalle Valo "BCME_NOCLK",
3905491d2cSKalle Valo "BCME_BADRATESET",
4005491d2cSKalle Valo "BCME_BADBAND",
4105491d2cSKalle Valo "BCME_BUFTOOSHORT",
4205491d2cSKalle Valo "BCME_BUFTOOLONG",
4305491d2cSKalle Valo "BCME_BUSY",
4405491d2cSKalle Valo "BCME_NOTASSOCIATED",
4505491d2cSKalle Valo "BCME_BADSSIDLEN",
4605491d2cSKalle Valo "BCME_OUTOFRANGECHAN",
4705491d2cSKalle Valo "BCME_BADCHAN",
4805491d2cSKalle Valo "BCME_BADADDR",
4905491d2cSKalle Valo "BCME_NORESOURCE",
5005491d2cSKalle Valo "BCME_UNSUPPORTED",
5105491d2cSKalle Valo "BCME_BADLEN",
5205491d2cSKalle Valo "BCME_NOTREADY",
5305491d2cSKalle Valo "BCME_EPERM",
5405491d2cSKalle Valo "BCME_NOMEM",
5505491d2cSKalle Valo "BCME_ASSOCIATED",
5605491d2cSKalle Valo "BCME_RANGE",
5705491d2cSKalle Valo "BCME_NOTFOUND",
5805491d2cSKalle Valo "BCME_WME_NOT_ENABLED",
5905491d2cSKalle Valo "BCME_TSPEC_NOTFOUND",
6005491d2cSKalle Valo "BCME_ACM_NOTSUPPORTED",
6105491d2cSKalle Valo "BCME_NOT_WME_ASSOCIATION",
6205491d2cSKalle Valo "BCME_SDIO_ERROR",
6305491d2cSKalle Valo "BCME_DONGLE_DOWN",
6405491d2cSKalle Valo "BCME_VERSION",
6505491d2cSKalle Valo "BCME_TXFAIL",
6605491d2cSKalle Valo "BCME_RXFAIL",
6705491d2cSKalle Valo "BCME_NODEVICE",
6805491d2cSKalle Valo "BCME_NMODE_DISABLED",
6905491d2cSKalle Valo "BCME_NONRESIDENT",
7005491d2cSKalle Valo "BCME_SCANREJECT",
7105491d2cSKalle Valo "BCME_USAGE_ERROR",
7205491d2cSKalle Valo "BCME_IOCTL_ERROR",
7305491d2cSKalle Valo "BCME_SERIAL_PORT_ERR",
7405491d2cSKalle Valo "BCME_DISABLED",
7505491d2cSKalle Valo "BCME_DECERR",
7605491d2cSKalle Valo "BCME_ENCERR",
7705491d2cSKalle Valo "BCME_MICERR",
7805491d2cSKalle Valo "BCME_REPLAY",
7905491d2cSKalle Valo "BCME_IE_NOTFOUND",
8005491d2cSKalle Valo };
8105491d2cSKalle Valo
brcmf_fil_get_errstr(u32 err)8205491d2cSKalle Valo static const char *brcmf_fil_get_errstr(u32 err)
8305491d2cSKalle Valo {
8405491d2cSKalle Valo if (err >= ARRAY_SIZE(brcmf_fil_errstr))
8505491d2cSKalle Valo return "(unknown)";
8605491d2cSKalle Valo
8705491d2cSKalle Valo return brcmf_fil_errstr[err];
8805491d2cSKalle Valo }
8905491d2cSKalle Valo #else
brcmf_fil_get_errstr(u32 err)9005491d2cSKalle Valo static const char *brcmf_fil_get_errstr(u32 err)
9105491d2cSKalle Valo {
9205491d2cSKalle Valo return "";
9305491d2cSKalle Valo }
9405491d2cSKalle Valo #endif /* DEBUG */
9505491d2cSKalle Valo
9605491d2cSKalle Valo static s32
brcmf_fil_cmd_data(struct brcmf_if * ifp,u32 cmd,void * data,u32 len,bool set)9705491d2cSKalle Valo brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
9805491d2cSKalle Valo {
9905491d2cSKalle Valo struct brcmf_pub *drvr = ifp->drvr;
100b69c1df4SArend Van Spriel s32 err, fwerr;
10105491d2cSKalle Valo
10205491d2cSKalle Valo if (drvr->bus_if->state != BRCMF_BUS_UP) {
103dcb1471bSRafał Miłecki bphy_err(drvr, "bus is down. we have nothing to do.\n");
10405491d2cSKalle Valo return -EIO;
10505491d2cSKalle Valo }
10605491d2cSKalle Valo
10705491d2cSKalle Valo if (data != NULL)
10805491d2cSKalle Valo len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
10905491d2cSKalle Valo if (set)
110b69c1df4SArend Van Spriel err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd,
111b69c1df4SArend Van Spriel data, len, &fwerr);
11205491d2cSKalle Valo else
113b69c1df4SArend Van Spriel err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
114b69c1df4SArend Van Spriel data, len, &fwerr);
11505491d2cSKalle Valo
116b69c1df4SArend Van Spriel if (err) {
1171170f6d1SArend Van Spriel brcmf_dbg(FIL, "Failed: error=%d\n", err);
118b69c1df4SArend Van Spriel } else if (fwerr < 0) {
119b69c1df4SArend Van Spriel brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
120b69c1df4SArend Van Spriel brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
121b69c1df4SArend Van Spriel err = -EBADE;
122b69c1df4SArend Van Spriel }
12393389734SArend Van Spriel if (ifp->fwil_fwerr)
12493389734SArend Van Spriel return fwerr;
12593389734SArend Van Spriel
12621000b3fSHante Meuleman return err;
12705491d2cSKalle Valo }
12805491d2cSKalle Valo
12905491d2cSKalle Valo s32
brcmf_fil_cmd_data_set(struct brcmf_if * ifp,u32 cmd,void * data,u32 len)13005491d2cSKalle Valo brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
13105491d2cSKalle Valo {
13205491d2cSKalle Valo s32 err;
13305491d2cSKalle Valo
13405491d2cSKalle Valo mutex_lock(&ifp->drvr->proto_block);
13505491d2cSKalle Valo
13605491d2cSKalle Valo brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
13705491d2cSKalle Valo brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
13805491d2cSKalle Valo min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
13905491d2cSKalle Valo
14005491d2cSKalle Valo err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
14105491d2cSKalle Valo mutex_unlock(&ifp->drvr->proto_block);
14205491d2cSKalle Valo
14305491d2cSKalle Valo return err;
14405491d2cSKalle Valo }
145*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_set);
14605491d2cSKalle Valo
14705491d2cSKalle Valo s32
brcmf_fil_cmd_data_get(struct brcmf_if * ifp,u32 cmd,void * data,u32 len)14805491d2cSKalle Valo brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
14905491d2cSKalle Valo {
15005491d2cSKalle Valo s32 err;
15105491d2cSKalle Valo
15205491d2cSKalle Valo mutex_lock(&ifp->drvr->proto_block);
15305491d2cSKalle Valo err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
15405491d2cSKalle Valo
155a7dd0ac9SArend van Spriel brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d, err=%d\n", ifp->ifidx, cmd,
156a7dd0ac9SArend van Spriel len, err);
15705491d2cSKalle Valo brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
15805491d2cSKalle Valo min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
15905491d2cSKalle Valo
16005491d2cSKalle Valo mutex_unlock(&ifp->drvr->proto_block);
16105491d2cSKalle Valo
16205491d2cSKalle Valo return err;
16305491d2cSKalle Valo }
164*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_get);
16505491d2cSKalle Valo
16605491d2cSKalle Valo static u32
brcmf_create_iovar(const char * name,const char * data,u32 datalen,char * buf,u32 buflen)167e7191182SHector Martin brcmf_create_iovar(const char *name, const char *data, u32 datalen,
16805491d2cSKalle Valo char *buf, u32 buflen)
16905491d2cSKalle Valo {
17005491d2cSKalle Valo u32 len;
17105491d2cSKalle Valo
17205491d2cSKalle Valo len = strlen(name) + 1;
17305491d2cSKalle Valo
17405491d2cSKalle Valo if ((len + datalen) > buflen)
17505491d2cSKalle Valo return 0;
17605491d2cSKalle Valo
17705491d2cSKalle Valo memcpy(buf, name, len);
17805491d2cSKalle Valo
17905491d2cSKalle Valo /* append data onto the end of the name string */
18005491d2cSKalle Valo if (data && datalen)
18105491d2cSKalle Valo memcpy(&buf[len], data, datalen);
18205491d2cSKalle Valo
18305491d2cSKalle Valo return len + datalen;
18405491d2cSKalle Valo }
18505491d2cSKalle Valo
18605491d2cSKalle Valo
18705491d2cSKalle Valo s32
brcmf_fil_iovar_data_set(struct brcmf_if * ifp,const char * name,const void * data,u32 len)188e7191182SHector Martin brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data,
18905491d2cSKalle Valo u32 len)
19005491d2cSKalle Valo {
19105491d2cSKalle Valo struct brcmf_pub *drvr = ifp->drvr;
19205491d2cSKalle Valo s32 err;
19305491d2cSKalle Valo u32 buflen;
19405491d2cSKalle Valo
19505491d2cSKalle Valo mutex_lock(&drvr->proto_block);
19605491d2cSKalle Valo
19705491d2cSKalle Valo brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
19805491d2cSKalle Valo brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
19905491d2cSKalle Valo min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
20005491d2cSKalle Valo
20105491d2cSKalle Valo buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
20205491d2cSKalle Valo sizeof(drvr->proto_buf));
20305491d2cSKalle Valo if (buflen) {
20405491d2cSKalle Valo err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
20505491d2cSKalle Valo buflen, true);
20605491d2cSKalle Valo } else {
20705491d2cSKalle Valo err = -EPERM;
208dcb1471bSRafał Miłecki bphy_err(drvr, "Creating iovar failed\n");
20905491d2cSKalle Valo }
21005491d2cSKalle Valo
21105491d2cSKalle Valo mutex_unlock(&drvr->proto_block);
21205491d2cSKalle Valo return err;
21305491d2cSKalle Valo }
2148d59a64cSHector Martin BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_set);
21505491d2cSKalle Valo
21605491d2cSKalle Valo s32
brcmf_fil_iovar_data_get(struct brcmf_if * ifp,const char * name,void * data,u32 len)217e7191182SHector Martin brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data,
21805491d2cSKalle Valo u32 len)
21905491d2cSKalle Valo {
22005491d2cSKalle Valo struct brcmf_pub *drvr = ifp->drvr;
22105491d2cSKalle Valo s32 err;
22205491d2cSKalle Valo u32 buflen;
22305491d2cSKalle Valo
22405491d2cSKalle Valo mutex_lock(&drvr->proto_block);
22505491d2cSKalle Valo
22605491d2cSKalle Valo buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
22705491d2cSKalle Valo sizeof(drvr->proto_buf));
22805491d2cSKalle Valo if (buflen) {
22905491d2cSKalle Valo err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
23005491d2cSKalle Valo buflen, false);
23105491d2cSKalle Valo if (err == 0)
23205491d2cSKalle Valo memcpy(data, drvr->proto_buf, len);
23305491d2cSKalle Valo } else {
23405491d2cSKalle Valo err = -EPERM;
235dcb1471bSRafał Miłecki bphy_err(drvr, "Creating iovar failed\n");
23605491d2cSKalle Valo }
23705491d2cSKalle Valo
238a7dd0ac9SArend van Spriel brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d, err=%d\n", ifp->ifidx, name,
239a7dd0ac9SArend van Spriel len, err);
24005491d2cSKalle Valo brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
24105491d2cSKalle Valo min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
24205491d2cSKalle Valo
24305491d2cSKalle Valo mutex_unlock(&drvr->proto_block);
24405491d2cSKalle Valo return err;
24505491d2cSKalle Valo }
246*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_get);
24705491d2cSKalle Valo
24805491d2cSKalle Valo static u32
brcmf_create_bsscfg(s32 bsscfgidx,const char * name,char * data,u32 datalen,char * buf,u32 buflen)249e7191182SHector Martin brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen,
25037a869ecSHante Meuleman char *buf, u32 buflen)
25105491d2cSKalle Valo {
25205491d2cSKalle Valo const s8 *prefix = "bsscfg:";
25305491d2cSKalle Valo s8 *p;
25405491d2cSKalle Valo u32 prefixlen;
25505491d2cSKalle Valo u32 namelen;
25605491d2cSKalle Valo u32 iolen;
25737a869ecSHante Meuleman __le32 bsscfgidx_le;
25805491d2cSKalle Valo
25937a869ecSHante Meuleman if (bsscfgidx == 0)
26005491d2cSKalle Valo return brcmf_create_iovar(name, data, datalen, buf, buflen);
26105491d2cSKalle Valo
26205491d2cSKalle Valo prefixlen = strlen(prefix);
263b07e1ae2SWeitao Hou namelen = strlen(name) + 1; /* length of iovar name + null */
26437a869ecSHante Meuleman iolen = prefixlen + namelen + sizeof(bsscfgidx_le) + datalen;
26505491d2cSKalle Valo
26605491d2cSKalle Valo if (buflen < iolen) {
26705491d2cSKalle Valo brcmf_err("buffer is too short\n");
26805491d2cSKalle Valo return 0;
26905491d2cSKalle Valo }
27005491d2cSKalle Valo
27105491d2cSKalle Valo p = buf;
27205491d2cSKalle Valo
27305491d2cSKalle Valo /* copy prefix, no null */
27405491d2cSKalle Valo memcpy(p, prefix, prefixlen);
27505491d2cSKalle Valo p += prefixlen;
27605491d2cSKalle Valo
27705491d2cSKalle Valo /* copy iovar name including null */
27805491d2cSKalle Valo memcpy(p, name, namelen);
27905491d2cSKalle Valo p += namelen;
28005491d2cSKalle Valo
28105491d2cSKalle Valo /* bss config index as first data */
28237a869ecSHante Meuleman bsscfgidx_le = cpu_to_le32(bsscfgidx);
28337a869ecSHante Meuleman memcpy(p, &bsscfgidx_le, sizeof(bsscfgidx_le));
28437a869ecSHante Meuleman p += sizeof(bsscfgidx_le);
28505491d2cSKalle Valo
28605491d2cSKalle Valo /* parameter buffer follows */
28705491d2cSKalle Valo if (datalen)
28805491d2cSKalle Valo memcpy(p, data, datalen);
28905491d2cSKalle Valo
29005491d2cSKalle Valo return iolen;
29105491d2cSKalle Valo }
29205491d2cSKalle Valo
29305491d2cSKalle Valo s32
brcmf_fil_bsscfg_data_set(struct brcmf_if * ifp,const char * name,void * data,u32 len)294e7191182SHector Martin brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name,
29505491d2cSKalle Valo void *data, u32 len)
29605491d2cSKalle Valo {
29705491d2cSKalle Valo struct brcmf_pub *drvr = ifp->drvr;
29805491d2cSKalle Valo s32 err;
29905491d2cSKalle Valo u32 buflen;
30005491d2cSKalle Valo
30105491d2cSKalle Valo mutex_lock(&drvr->proto_block);
30205491d2cSKalle Valo
30337a869ecSHante Meuleman brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d\n", ifp->ifidx,
30437a869ecSHante Meuleman ifp->bsscfgidx, name, len);
30505491d2cSKalle Valo brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
30605491d2cSKalle Valo min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
30705491d2cSKalle Valo
30837a869ecSHante Meuleman buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len,
30905491d2cSKalle Valo drvr->proto_buf, sizeof(drvr->proto_buf));
31005491d2cSKalle Valo if (buflen) {
31105491d2cSKalle Valo err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
31205491d2cSKalle Valo buflen, true);
31305491d2cSKalle Valo } else {
31405491d2cSKalle Valo err = -EPERM;
315dcb1471bSRafał Miłecki bphy_err(drvr, "Creating bsscfg failed\n");
31605491d2cSKalle Valo }
31705491d2cSKalle Valo
31805491d2cSKalle Valo mutex_unlock(&drvr->proto_block);
31905491d2cSKalle Valo return err;
32005491d2cSKalle Valo }
321*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_set);
32205491d2cSKalle Valo
32305491d2cSKalle Valo s32
brcmf_fil_bsscfg_data_get(struct brcmf_if * ifp,const char * name,void * data,u32 len)324e7191182SHector Martin brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name,
32505491d2cSKalle Valo void *data, u32 len)
32605491d2cSKalle Valo {
32705491d2cSKalle Valo struct brcmf_pub *drvr = ifp->drvr;
32805491d2cSKalle Valo s32 err;
32905491d2cSKalle Valo u32 buflen;
33005491d2cSKalle Valo
33105491d2cSKalle Valo mutex_lock(&drvr->proto_block);
33205491d2cSKalle Valo
33337a869ecSHante Meuleman buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len,
33405491d2cSKalle Valo drvr->proto_buf, sizeof(drvr->proto_buf));
33505491d2cSKalle Valo if (buflen) {
33605491d2cSKalle Valo err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
33705491d2cSKalle Valo buflen, false);
33805491d2cSKalle Valo if (err == 0)
33905491d2cSKalle Valo memcpy(data, drvr->proto_buf, len);
34005491d2cSKalle Valo } else {
34105491d2cSKalle Valo err = -EPERM;
342dcb1471bSRafał Miłecki bphy_err(drvr, "Creating bsscfg failed\n");
34305491d2cSKalle Valo }
344a7dd0ac9SArend van Spriel brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d, err=%d\n",
345a7dd0ac9SArend van Spriel ifp->ifidx, ifp->bsscfgidx, name, len, err);
34605491d2cSKalle Valo brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
34705491d2cSKalle Valo min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
34805491d2cSKalle Valo
34905491d2cSKalle Valo mutex_unlock(&drvr->proto_block);
35005491d2cSKalle Valo return err;
35105491d2cSKalle Valo }
352*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_get);
353a7dd0ac9SArend van Spriel
brcmf_create_xtlv(const char * name,u16 id,char * data,u32 len,char * buf,u32 buflen)354e7191182SHector Martin static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len,
355a7dd0ac9SArend van Spriel char *buf, u32 buflen)
356a7dd0ac9SArend van Spriel {
357a7dd0ac9SArend van Spriel u32 iolen;
358a7dd0ac9SArend van Spriel u32 nmlen;
359a7dd0ac9SArend van Spriel
360a7dd0ac9SArend van Spriel nmlen = strlen(name) + 1;
361a7dd0ac9SArend van Spriel iolen = nmlen + brcmf_xtlv_data_size(len, BRCMF_XTLV_OPTION_ALIGN32);
362a7dd0ac9SArend van Spriel
363a7dd0ac9SArend van Spriel if (iolen > buflen) {
364a7dd0ac9SArend van Spriel brcmf_err("buffer is too short\n");
365a7dd0ac9SArend van Spriel return 0;
366a7dd0ac9SArend van Spriel }
367a7dd0ac9SArend van Spriel
368a7dd0ac9SArend van Spriel memcpy(buf, name, nmlen);
369a7dd0ac9SArend van Spriel brcmf_xtlv_pack_header((void *)(buf + nmlen), id, len, data,
370a7dd0ac9SArend van Spriel BRCMF_XTLV_OPTION_ALIGN32);
371a7dd0ac9SArend van Spriel
372a7dd0ac9SArend van Spriel return iolen;
373a7dd0ac9SArend van Spriel }
374a7dd0ac9SArend van Spriel
brcmf_fil_xtlv_data_set(struct brcmf_if * ifp,const char * name,u16 id,void * data,u32 len)375e7191182SHector Martin s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id,
376a7dd0ac9SArend van Spriel void *data, u32 len)
377a7dd0ac9SArend van Spriel {
378a7dd0ac9SArend van Spriel struct brcmf_pub *drvr = ifp->drvr;
379a7dd0ac9SArend van Spriel s32 err;
380a7dd0ac9SArend van Spriel u32 buflen;
381a7dd0ac9SArend van Spriel
382a7dd0ac9SArend van Spriel mutex_lock(&drvr->proto_block);
383a7dd0ac9SArend van Spriel
384a7dd0ac9SArend van Spriel brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u\n", ifp->ifidx, name,
385a7dd0ac9SArend van Spriel id, len);
386a7dd0ac9SArend van Spriel brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
387a7dd0ac9SArend van Spriel min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
388a7dd0ac9SArend van Spriel
389a7dd0ac9SArend van Spriel buflen = brcmf_create_xtlv(name, id, data, len,
390a7dd0ac9SArend van Spriel drvr->proto_buf, sizeof(drvr->proto_buf));
391a7dd0ac9SArend van Spriel if (buflen) {
392a7dd0ac9SArend van Spriel err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
393a7dd0ac9SArend van Spriel buflen, true);
394a7dd0ac9SArend van Spriel } else {
395a7dd0ac9SArend van Spriel err = -EPERM;
396a7dd0ac9SArend van Spriel bphy_err(drvr, "Creating xtlv failed\n");
397a7dd0ac9SArend van Spriel }
398a7dd0ac9SArend van Spriel
399a7dd0ac9SArend van Spriel mutex_unlock(&drvr->proto_block);
400a7dd0ac9SArend van Spriel return err;
401a7dd0ac9SArend van Spriel }
402*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_set);
403a7dd0ac9SArend van Spriel
brcmf_fil_xtlv_data_get(struct brcmf_if * ifp,const char * name,u16 id,void * data,u32 len)404e7191182SHector Martin s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id,
405a7dd0ac9SArend van Spriel void *data, u32 len)
406a7dd0ac9SArend van Spriel {
407a7dd0ac9SArend van Spriel struct brcmf_pub *drvr = ifp->drvr;
408a7dd0ac9SArend van Spriel s32 err;
409a7dd0ac9SArend van Spriel u32 buflen;
410a7dd0ac9SArend van Spriel
411a7dd0ac9SArend van Spriel mutex_lock(&drvr->proto_block);
412a7dd0ac9SArend van Spriel
413a7dd0ac9SArend van Spriel buflen = brcmf_create_xtlv(name, id, data, len,
414a7dd0ac9SArend van Spriel drvr->proto_buf, sizeof(drvr->proto_buf));
415a7dd0ac9SArend van Spriel if (buflen) {
416a7dd0ac9SArend van Spriel err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
417a7dd0ac9SArend van Spriel buflen, false);
418a7dd0ac9SArend van Spriel if (err == 0)
419a7dd0ac9SArend van Spriel memcpy(data, drvr->proto_buf, len);
420a7dd0ac9SArend van Spriel } else {
421a7dd0ac9SArend van Spriel err = -EPERM;
422a7dd0ac9SArend van Spriel bphy_err(drvr, "Creating bsscfg failed\n");
423a7dd0ac9SArend van Spriel }
424a7dd0ac9SArend van Spriel brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u, err=%d\n",
425a7dd0ac9SArend van Spriel ifp->ifidx, name, id, len, err);
426a7dd0ac9SArend van Spriel brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
427a7dd0ac9SArend van Spriel min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
428a7dd0ac9SArend van Spriel
429a7dd0ac9SArend van Spriel mutex_unlock(&drvr->proto_block);
430a7dd0ac9SArend van Spriel return err;
431a7dd0ac9SArend van Spriel }
432*c3cfcf51SArend van Spriel BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_get);
433