NETWORK_PHY_HT_CAP_LSIG_TXOP_PROT = (1 << 15),
};
+enum network_phy_vht_caps {
+ NETWORK_PHY_VHT_CAP_VHT160 = (1 << 0),
+ NETWORK_PHY_VHT_CAP_VHT80PLUS80 = (1 << 1),
+ NETWORK_PHY_VHT_CAP_RX_LDPC = (1 << 2),
+ NETWORK_PHY_VHT_CAP_RX_SHORT_GI_80 = (1 << 3),
+ NETWORK_PHY_VHT_CAP_RX_SHORT_GI_160 = (1 << 4),
+ NETWORK_PHY_VHT_CAP_TX_STBC = (1 << 5),
+ NETWORK_PHY_VHT_CAP_SU_BEAMFORMER = (1 << 6),
+ NETWORK_PHY_VHT_CAP_SU_BEAMFORMEE = (1 << 7),
+ NETWORK_PHY_VHT_CAP_MU_BEAMFORMER = (1 << 8),
+ NETWORK_PHY_VHT_CAP_MU_BEAMFORMEE = (1 << 9),
+ NETWORK_PHY_VHT_CAP_TXOP_PS = (1 << 10),
+ NETWORK_PHY_VHT_CAP_HTC_VHT = (1 << 11),
+ NETWORK_PHY_VHT_CAP_RX_ANTENNA_PATTERN = (1 << 12),
+ NETWORK_PHY_VHT_CAP_TX_ANTENNA_PATTERN = (1 << 13),
+};
+
+
+int network_phy_has_vht_capability(struct network_phy* phy, const enum network_phy_vht_caps cap);
+char* network_phy_list_vht_capabilities(struct network_phy* phy);
int network_phy_has_ht_capability(struct network_phy* phy, const enum network_phy_ht_caps cap);
char* network_phy_list_ht_capabilities(struct network_phy* phy);
struct nl_msg* network_phy_make_netlink_message(struct network_phy* phy,
enum nl80211_commands cmd, int flags);
+#define foreach_vht_cap(cap) \
+ for(int cap = NETWORK_PHY_VHT_CAP_VHT160; cap <= NETWORK_PHY_VHT_CAP_TX_ANTENNA_PATTERN; cap <<= 1)
+
#define foreach_ht_cap(cap) \
for(int cap = NETWORK_PHY_HT_CAP_RX_LDCP; cap != NETWORK_PHY_HT_CAP_LSIG_TXOP_PROT; cap <<= 1)
int index;
char* name;
+ ssize_t max_mpdu_length;
+ unsigned int vht_caps;
unsigned int ht_caps;
};
return atoi(index);
}
+static void phy_parse_vht_capabilities(struct network_phy* phy, __u32 caps) {
+ // Max MPDU length
+ switch (caps & 0x3) {
+ case 0:
+ phy->max_mpdu_length = 3895;
+ break;
+
+ case 1:
+ phy->max_mpdu_length = 7991;
+ break;
+
+ case 2:
+ phy->max_mpdu_length = 11454;
+ break;
+
+ case 3:
+ phy->max_mpdu_length = -1;
+ }
+
+ // Supported channel widths
+ switch ((caps >> 2) & 0x3) {
+ case 0:
+ break;
+
+ // Supports 160 MHz
+ case 1:
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_VHT160;
+ break;
+
+ // Supports 160 MHz and 80+80 MHz
+ case 2:
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_VHT160;
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_VHT80PLUS80;
+ break;
+ }
+
+ // RX LDPC
+ if (caps & BIT(4))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_RX_LDPC;
+
+ // RX Short GI 80 MHz
+ if (caps & BIT(5))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_RX_SHORT_GI_80;
+
+ // RX Short GI 160 MHz and 80+80 MHz
+ if (caps & BIT(6))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_RX_SHORT_GI_160;
+
+ // TX STBC
+ if (caps & BIT(7))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_TX_STBC;
+
+ // Single User Beamformer
+ if (caps & BIT(11))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_SU_BEAMFORMER;
+
+ // Single User Beamformee
+ if (caps & BIT(12))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_SU_BEAMFORMEE;
+
+ // Multi User Beamformer
+ if (caps & BIT(19))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_MU_BEAMFORMER;
+
+ // Multi User Beamformee
+ if (caps & BIT(20))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_MU_BEAMFORMEE;
+
+ // TX-OP-PS
+ if (caps & BIT(21))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_TXOP_PS;
+
+ // HTC-VHT
+ if (caps & BIT(22))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_HTC_VHT;
+
+ // RX Antenna Pattern Consistency
+ if (caps & BIT(28))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_RX_ANTENNA_PATTERN;
+
+ // TX Antenna Pattern Consistency
+ if (caps & BIT(29))
+ phy->vht_caps |= NETWORK_PHY_VHT_CAP_TX_ANTENNA_PATTERN;
+}
+
static void phy_parse_ht_capabilities(struct network_phy* phy, __u16 caps) {
// RX LDCP
if (caps & BIT(0))
// HT Capabilities
if (band_attrs[NL80211_BAND_ATTR_HT_CAPA]) {
- __u16 caps = nla_get_u16(band_attrs[NL80211_BAND_ATTR_HT_CAPA]);
- phy_parse_ht_capabilities(phy, caps);
+ __u16 ht_caps = nla_get_u16(band_attrs[NL80211_BAND_ATTR_HT_CAPA]);
+ phy_parse_ht_capabilities(phy, ht_caps);
+ }
+
+ // VHT Capabilities
+ if (band_attrs[NL80211_BAND_ATTR_VHT_CAPA]) {
+ __u32 vht_caps = nla_get_u32(band_attrs[NL80211_BAND_ATTR_VHT_CAPA]);
+
+ phy_parse_vht_capabilities(phy, vht_caps);
}
}
}
return NULL;
}
+NETWORK_EXPORT int network_phy_has_vht_capability(struct network_phy* phy, const enum network_phy_vht_caps cap) {
+ return phy->vht_caps & cap;
+}
+
NETWORK_EXPORT int network_phy_has_ht_capability(struct network_phy* phy, const enum network_phy_ht_caps cap) {
return phy->ht_caps & cap;
}
+static const char* network_phy_get_vht_capability_string(const enum network_phy_vht_caps cap) {
+ switch (cap) {
+ case NETWORK_PHY_VHT_CAP_VHT160:
+ return "[VHT-160]";
+
+ case NETWORK_PHY_VHT_CAP_VHT80PLUS80:
+ return "[VHT-160-80PLUS80]";
+
+ case NETWORK_PHY_VHT_CAP_RX_LDPC:
+ return "[RXLDPC]";
+
+ case NETWORK_PHY_VHT_CAP_RX_SHORT_GI_80:
+ return "[SHORT-GI-80]";
+
+ case NETWORK_PHY_VHT_CAP_RX_SHORT_GI_160:
+ return "[SHORT-GI-160]";
+
+ case NETWORK_PHY_VHT_CAP_TX_STBC:
+ return "[TX-STBC-2BY1]";
+
+ case NETWORK_PHY_VHT_CAP_SU_BEAMFORMER:
+ return "[SU-BEAMFORMER]";
+
+ case NETWORK_PHY_VHT_CAP_SU_BEAMFORMEE:
+ return "[SU-BEAMFORMEE]";
+
+ case NETWORK_PHY_VHT_CAP_MU_BEAMFORMER:
+ return "[MU-BEAMFORMER]";
+
+ case NETWORK_PHY_VHT_CAP_MU_BEAMFORMEE:
+ return "[MU-BEAMFORMEE]";
+
+ case NETWORK_PHY_VHT_CAP_TXOP_PS:
+ return "[VHT-TXOP-PS]";
+
+ case NETWORK_PHY_VHT_CAP_HTC_VHT:
+ return "[HTC-VHT]";
+
+ case NETWORK_PHY_VHT_CAP_RX_ANTENNA_PATTERN:
+ return "[RX-ANTENNA-PATTERN]";
+
+ case NETWORK_PHY_VHT_CAP_TX_ANTENNA_PATTERN:
+ return "[TX-ANTENNA-PATTERN]";
+ }
+
+ return NULL;
+}
+
static const char* network_phy_get_ht_capability_string(const enum network_phy_ht_caps cap) {
switch (cap) {
case NETWORK_PHY_HT_CAP_RX_LDCP:
return NULL;
}
+NETWORK_EXPORT char* network_phy_list_vht_capabilities(struct network_phy* phy) {
+ char* buffer = malloc(1024);
+ *buffer = '\0';
+
+ char* p = buffer;
+
+ switch (phy->max_mpdu_length) {
+ case 7991:
+ case 11454:
+ snprintf(p, 1024 - 1, "[MAX-MPDU-%zu]", phy->max_mpdu_length);
+ break;
+
+ }
+
+ foreach_vht_cap(cap) {
+ printf("%d\n", cap);
+ if (network_phy_has_vht_capability(phy, cap)) {
+ const char* cap_str = network_phy_get_vht_capability_string(cap);
+
+ if (cap_str)
+ p = strncat(p, cap_str, 1024 - 1);
+ }
+ }
+
+ return buffer;
+}
+
NETWORK_EXPORT char* network_phy_list_ht_capabilities(struct network_phy* phy) {
char* buffer = malloc(1024);
*buffer = '\0';
--- /dev/null
+/*#############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2018 IPFire Network Development Team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <network/libnetwork.h>
+#include <network/logging.h>
+#include <network/phy.h>
+
+int main(int argc, char** argv) {
+ struct network_ctx* ctx = NULL;
+ struct network_phy* phy = NULL;
+ int r;
+
+ if (argc < 2) {
+ fprintf(stderr, "No enough arguments\n");
+ r = 2;
+ goto END;
+ }
+
+ // Initialise context
+ r = network_new(&ctx);
+ if (r)
+ return r;
+
+ r = network_phy_new(ctx, &phy, argv[1]);
+ if (r) {
+ fprintf(stderr, "Could not find %s\n", argv[1]);
+ goto END;
+ }
+
+ // Print all supported VHT capabilities
+ char* vht_caps = network_phy_list_vht_capabilities(phy);
+ if (vht_caps && *vht_caps) {
+ printf("%s\n", vht_caps);
+ free(vht_caps);
+ }
+
+END:
+ network_phy_unref(phy);
+ network_unref(ctx);
+ return r;
+}