-
Notifications
You must be signed in to change notification settings - Fork 11
/
nl80211_vendor.c
110 lines (103 loc) · 3.09 KB
/
nl80211_vendor.c
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// SPDX-License-Identifier: GPL-2.0-only
/*
* Extra commands for nl80211 interface.
*
* Copyright (c) 2020, Silicon Laboratories, Inc.
*/
#include "nl80211_vendor.h"
#include "wfx.h"
#include "sta.h"
#include "hif_tx.h"
int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev,
const void *data, int data_len)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct wfx_dev *wdev = (struct wfx_dev *)hw->priv;
struct nlattr *tb[WFX_NL80211_ATTR_MAX];
u32 magic;
int rc;
#if (KERNEL_VERSION(4, 12, 0) > LINUX_VERSION_CODE)
rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len, wfx_nl_policy);
#else
rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len, wfx_nl_policy, NULL);
#endif
if (rc)
return rc;
if (!tb[WFX_NL80211_ATTR_ROLLBACK_MAGIC])
return -EINVAL;
magic = nla_get_u32(tb[WFX_NL80211_ATTR_ROLLBACK_MAGIC]);
rc = wfx_hif_burn_prevent_rollback(wdev, magic);
if (rc)
return -EINVAL;
return 0;
}
int wfx_nl_pta_params(struct wiphy *wiphy, struct wireless_dev *widev,
const void *data, int data_len)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct wfx_dev *wdev = (struct wfx_dev *)hw->priv;
int reply_size = nla_total_size(sizeof(wdev->pta_settings)) +
nla_total_size(sizeof(u8)) +
nla_total_size(sizeof(u32));
struct nlattr *tb[WFX_NL80211_ATTR_MAX];
bool do_enable = false;
struct sk_buff *msg;
struct nlattr *nla;
int rc;
#if (KERNEL_VERSION(4, 12, 0) > LINUX_VERSION_CODE)
rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len, wfx_nl_policy);
#else
rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len, wfx_nl_policy, NULL);
#endif
if (rc)
return rc;
nla = tb[WFX_NL80211_ATTR_PTA_ENABLE];
if (nla) {
do_enable = true;
wdev->pta_enable = nla_get_u8(tb[WFX_NL80211_ATTR_PTA_ENABLE]);
}
if (do_enable && !wdev->pta_enable)
rc = wfx_hif_pta_enable(wdev, wdev->pta_enable);
if (rc)
return rc;
nla = tb[WFX_NL80211_ATTR_PTA_SETTINGS];
#if (KERNEL_VERSION(4, 20, 0) > LINUX_VERSION_CODE)
if (nla && nla_len(nla) != sizeof(wdev->pta_settings))
return -EINVAL;
#endif
if (nla) {
/* User has to care about endianness of data it send. */
memcpy(&wdev->pta_settings, nla_data(nla), sizeof(wdev->pta_settings));
rc = wfx_hif_pta_settings(wdev, &wdev->pta_settings);
}
if (rc)
return rc;
nla = tb[WFX_NL80211_ATTR_PTA_PRIORITY];
if (nla) {
wdev->pta_priority = nla_get_u32(tb[WFX_NL80211_ATTR_PTA_PRIORITY]);
rc = wfx_hif_pta_priority(wdev, wdev->pta_priority);
}
if (rc)
return rc;
if (do_enable && wdev->pta_enable)
rc = wfx_hif_pta_enable(wdev, wdev->pta_enable);
if (rc)
return rc;
msg = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_size);
if (!msg)
return -ENOMEM;
rc = nla_put(msg, WFX_NL80211_ATTR_PTA_SETTINGS,
sizeof(wdev->pta_settings), &wdev->pta_settings);
if (rc)
goto error;
rc = nla_put_u32(msg, WFX_NL80211_ATTR_PTA_PRIORITY, wdev->pta_priority);
if (rc)
goto error;
rc = nla_put_u8(msg, WFX_NL80211_ATTR_PTA_ENABLE, wdev->pta_enable ? 1 : 0);
if (rc)
goto error;
return cfg80211_vendor_cmd_reply(msg);
error:
kfree_skb(msg);
return rc;
}