1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2018 IPFire Network Development Team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
22 #include <linux/nl80211.h>
23 #include <netlink/attr.h>
24 #include <netlink/genl/genl.h>
25 #include <netlink/msg.h>
30 #include <network/libnetwork.h>
31 #include <network/logging.h>
32 #include <network/phy.h>
33 #include "libnetwork-private.h"
36 struct network_ctx
* ctx
;
45 static int phy_get_index(const char* name
) {
49 snprintf(path
, sizeof(path
), "/sys/class/ieee80211/%s/index", name
);
51 FILE* f
= fopen(path
, "r");
55 int p
= fread(index
, 1, sizeof(index
), f
);
68 static void phy_parse_ht_capabilities(struct network_phy
* phy
, __u16 caps
) {
71 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_LDCP
;
75 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_HT40
;
77 // Static/Dynamic SM Power Save
78 switch ((caps
>> 2) & 0x3) {
80 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_SMPS_STATIC
;
84 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_SMPS_DYNAMIC
;
93 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_GF
;
97 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_HT20_SGI
;
101 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_HT40_SGI
;
105 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_TX_STBC
;
108 switch ((caps
>> 8) & 0x3) {
110 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_STBC1
;
114 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_STBC2
;
118 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_RX_STBC3
;
125 // HT Delayed Block ACK
127 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_DELAYED_BA
;
129 // Max AMSDU length 7935
131 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_MAX_AMSDU_7935
;
135 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_DSSS_CCK_HT40
;
137 // Bit 13 is reserved
141 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_HT40_INTOLERANT
;
143 // L-SIG TXOP protection
145 phy
->ht_caps
|= NETWORK_PHY_HT_CAP_LSIG_TXOP_PROT
;
148 static int phy_parse_info(struct nl_msg
* msg
, void* data
) {
149 struct network_phy
* phy
= data
;
151 struct nlattr
* attrs
[NL80211_ATTR_MAX
+ 1];
152 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
154 nla_parse(attrs
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
155 genlmsg_attrlen(gnlh
, 0), NULL
);
157 if (attrs
[NL80211_ATTR_WIPHY_BANDS
]) {
158 struct nlattr
* nl_band
;
161 nla_for_each_nested(nl_band
, attrs
[NL80211_ATTR_WIPHY_BANDS
], i
) {
162 struct nlattr
* band_attrs
[NL80211_BAND_ATTR_MAX
+ 1];
163 nla_parse(band_attrs
, NL80211_BAND_ATTR_MAX
, nla_data(nl_band
),
164 nla_len(nl_band
), NULL
);
167 if (band_attrs
[NL80211_BAND_ATTR_HT_CAPA
]) {
168 __u16 caps
= nla_get_u16(band_attrs
[NL80211_BAND_ATTR_HT_CAPA
]);
169 phy_parse_ht_capabilities(phy
, caps
);
177 static int phy_get_info(struct network_phy
* phy
) {
178 DEBUG(phy
->ctx
, "Getting information for %s\n", phy
->name
);
180 struct nl_msg
* msg
= network_phy_make_netlink_message(phy
, NL80211_CMD_GET_WIPHY
, 0);
184 return network_send_netlink_message(phy
->ctx
, msg
, phy_parse_info
, phy
);
187 static void network_phy_free(struct network_phy
* phy
) {
188 DEBUG(phy
->ctx
, "Releasing phy at %p\n", phy
);
193 network_unref(phy
->ctx
);
197 NETWORK_EXPORT
int network_phy_new(struct network_ctx
* ctx
, struct network_phy
** phy
,
202 int index
= phy_get_index(name
);
206 struct network_phy
* p
= calloc(1, sizeof(*p
));
211 p
->ctx
= network_ref(ctx
);
214 p
->name
= strdup(name
);
216 // Load information from kernel
217 int r
= phy_get_info(p
);
219 ERROR(p
->ctx
, "Error getting PHY information from kernel\n");
225 DEBUG(p
->ctx
, "Allocated phy at %p\n", p
);
230 NETWORK_EXPORT
struct network_phy
* network_phy_ref(struct network_phy
* phy
) {
238 NETWORK_EXPORT
struct network_phy
* network_phy_unref(struct network_phy
* phy
) {
242 if (--phy
->refcount
> 0)
245 network_phy_free(phy
);
249 struct nl_msg
* network_phy_make_netlink_message(struct network_phy
* phy
,
250 enum nl80211_commands cmd
, int flags
) {
251 struct nl_msg
* msg
= network_make_netlink_message(phy
->ctx
, cmd
, flags
);
256 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, phy
->index
);
266 NETWORK_EXPORT
int network_phy_has_ht_capability(struct network_phy
* phy
, const enum network_phy_ht_caps cap
) {
267 return phy
->ht_caps
& cap
;
270 static const char* network_phy_get_ht_capability_string(const enum network_phy_ht_caps cap
) {
272 case NETWORK_PHY_HT_CAP_RX_LDCP
:
275 case NETWORK_PHY_HT_CAP_HT40
:
276 return "[HT40+][HT40-]";
278 case NETWORK_PHY_HT_CAP_SMPS_STATIC
:
279 return "[SMPS-STATIC]";
281 case NETWORK_PHY_HT_CAP_SMPS_DYNAMIC
:
282 return "[SMPS-DYNAMIC]";
284 case NETWORK_PHY_HT_CAP_RX_GF
:
287 case NETWORK_PHY_HT_CAP_RX_HT20_SGI
:
288 return "[SHORT-GI-20]";
290 case NETWORK_PHY_HT_CAP_RX_HT40_SGI
:
291 return "[SHORT-GI-40]";
293 case NETWORK_PHY_HT_CAP_TX_STBC
:
296 case NETWORK_PHY_HT_CAP_RX_STBC1
:
299 case NETWORK_PHY_HT_CAP_RX_STBC2
:
300 return "[RX-STBC12]";
302 case NETWORK_PHY_HT_CAP_RX_STBC3
:
303 return "[RX-STBC123]";
305 case NETWORK_PHY_HT_CAP_DELAYED_BA
:
306 return "[DELAYED-BA]";
308 case NETWORK_PHY_HT_CAP_MAX_AMSDU_7935
:
309 return "[MAX-AMSDU-7935]";
311 case NETWORK_PHY_HT_CAP_DSSS_CCK_HT40
:
312 return "[DSSS_CCK-40]";
314 case NETWORK_PHY_HT_CAP_HT40_INTOLERANT
:
315 return "[40-INTOLERANT]";
317 case NETWORK_PHY_HT_CAP_LSIG_TXOP_PROT
:
318 return "[LSIG-TXOP-PROT]";
324 NETWORK_EXPORT
char* network_phy_list_ht_capabilities(struct network_phy
* phy
) {
325 char* buffer
= malloc(1024);
329 foreach_ht_cap(cap
) {
330 if (network_phy_has_ht_capability(phy
, cap
)) {
331 const char* cap_str
= network_phy_get_ht_capability_string(cap
);
334 p
= strncat(p
, cap_str
, 1024 - 1);