util_PROGRAMS = \
src/utils/network-phy-list-channels \
+ src/utils/network-phy-list-ciphers \
src/utils/network-phy-list-ht-caps \
src/utils/network-phy-list-vht-caps
src_utils_network_phy_list_channels_LDADD = \
src/libnetwork.la
+src_utils_network_phy_list_ciphers_SOURCES = \
+ src/utils/network-phy-list-ciphers.c
+
+src_utils_network_phy_list_ciphers_LDADD = \
+ src/libnetwork.la
+
src_utils_network_phy_list_ht_caps_SOURCES = \
src/utils/network-phy-list-ht-caps.c
HOSTAPD_SUPPORTED_MODES="802.11a 802.11a/n 802.11ac 802.11g 802.11g/n"
+HOSTAPD_SUPPORTED_PAIRWISE_CIPHERS=(
+ "GCMP-256" # Galois/counter mode protocol with 256 bit key
+ "CCMP-256" # AES in Counter mode with CBC-MAC with 256 bit key
+ "GCMP-128" # Galois/counter mode protocol with 128 bit key
+ "CCMP-128" # AES in Counter mode with CBC-MAC with 128 bit key
+)
+
+# This must be supported by all stations on the network and therefore
+# can effectively only be CCMP
+HOSTAPD_SUPPORTED_GROUP_CIPHERS=(
+ "CCMP-128"
+)
+
hostapd_config_write() {
local device=${1}
assert isset device
# Shift the device and file argument.
shift 2
+ # Device must exist
+ if ! device_exists "${device}"; then
+ error "Cannot write hostapd configuration for non-existant device: ${device}"
+ return ${EXIT_ERROR}
+ fi
+
+ # Get the phy for device
+ local phy="$(device_get_phy "${device}")"
+ assert isset phy
+
local broadcast_ssid
local channel
local channel_bandwidth
;;
esac
+ # Cryptography
+ local cipher
+
+ # Get all supported pairwise ciphers
+ local pairwise_ciphers=()
+ for cipher in ${HOSTAPD_SUPPORTED_PAIRWISE_CIPHERS[*]}; do
+ if phy_supports_cipher "${phy}" "${cipher}"; then
+ pairwise_ciphers+=( "$(hostapd_cipher_name "${cipher}")" )
+ fi
+ done
+
+ # Get all supported group ciphers
+ local group_ciphers=()
+ for cipher in ${HOSTAPD_SUPPORTED_GROUP_CIPHERS[*]}; do
+ if phy_supports_cipher "${phy}" "${cipher}"; then
+ group_ciphers+=( "$(hostapd_cipher_name "${cipher}")" )
+ fi
+ done
+
# Create configuration directory.
local config_dir=$(dirname ${file})
mkdir -p ${HOSTAPD_CONTROL_INTERFACE_DIR} ${config_dir} 2>/dev/null
print "wpa=${encryption_mode}"
print "wpa_passphrase=${key}"
print "wpa_key_mgmt=WPA-PSK"
- print "wpa_pairwise=TKIP"
- print "rsn_pairwise=CCMP"
+ print "wpa_pairwise=${pairwise_ciphers[*]}"
+ print "rsn_pairwise=${pairwise_ciphers[*]}"
+ print "group_cipher=${group_ciphers[*]}"
print
) >> ${file}
fi
service_stop "hostapd@${device}.service"
}
+
+hostapd_cipher_name() {
+ local cipher="${1}"
+
+ case "${cipher}" in
+ CCMP-128)
+ print "CCMP"
+ ;;
+
+ GCMP-128)
+ print "GCMP"
+ ;;
+
+ *)
+ print "${cipher}"
+ ;;
+ esac
+}
return ${EXIT_FALSE}
}
+phy_list_ciphers() {
+ local phy="${1}"
+ assert isset phy
+
+ network-phy-list-ciphers "${phy}"
+}
+
+phy_supports_cipher() {
+ local phy="${1}"
+ assert isset phy
+
+ local cipher="${2}"
+ assert isset cipher
+
+ list_match "${cipher}" $(phy_list_ciphers "${phy}")
+}
+
__phy_list_ht_capabilities() {
local phy="${1}"
assert isset phy
LIBNETWORK_0 {
global:
- network_interface_get_name;
- network_interface_new;
- network_interface_ref;
- network_interface_unref;
- network_new;
- network_phy_has_ht_capability;
- network_phy_has_vht_capability;
- network_phy_list_channels;
- network_phy_list_ht_capabilities;
- network_phy_list_vht_capabilities;
- network_phy_new;
- network_phy_ref;
- network_phy_unref;
- network_ref;
- network_unref;
- network_version;
+ network_interface_get_name;
+ network_interface_new;
+ network_interface_ref;
+ network_interface_unref;
+ network_new;
+ network_phy_get_cipher_string;
+ network_phy_has_ht_capability;
+ network_phy_has_vht_capability;
+ network_phy_list_channels;
+ network_phy_list_ciphers;
+ network_phy_list_ht_capabilities;
+ network_phy_list_vht_capabilities;
+ network_phy_supports_cipher;
+ network_phy_new;
+ network_phy_ref;
+ network_phy_unref;
+ network_ref;
+ network_unref;
+ network_version;
local:
- *;
+ *;
};
struct network_phy* network_phy_ref(struct network_phy* phy);
struct network_phy* network_phy_unref(struct network_phy* phy);
+enum network_phy_ciphers {
+ NETWORK_PHY_CIPHER_WEP40 = (1 << 0),
+ NETWORK_PHY_CIPHER_TKIP = (1 << 1),
+ NETWORK_PHY_CIPHER_CCMP128 = (1 << 2),
+ NETWORK_PHY_CIPHER_WEP104 = (1 << 3),
+ NETWORK_PHY_CIPHER_CMAC128 = (1 << 4),
+ NETWORK_PHY_CIPHER_GCMP128 = (1 << 5),
+ NETWORK_PHY_CIPHER_GCMP256 = (1 << 6),
+ NETWORK_PHY_CIPHER_CCMP256 = (1 << 7),
+ NETWORK_PHY_CIPHER_GMAC128 = (1 << 8),
+ NETWORK_PHY_CIPHER_GMAC256 = (1 << 9),
+ NETWORK_PHY_CIPHER_CMAC256 = (1 << 10),
+ NETWORK_PHY_CIPHER_WPISMS4 = (1 << 11),
+};
+
+const char* network_phy_get_cipher_string(const enum network_phy_ciphers cipher);
+int network_phy_supports_cipher(struct network_phy* phy, const enum network_phy_ciphers cipher);
+char* network_phy_list_ciphers(struct network_phy* phy);
+
enum network_phy_ht_caps {
NETWORK_PHY_HT_CAP_RX_LDPC = (1 << 0),
NETWORK_PHY_HT_CAP_HT40 = (1 << 1),
struct nl_msg* network_phy_make_netlink_message(struct network_phy* phy,
enum nl80211_commands cmd, int flags);
+#define foreach_cipher(cipher) \
+ for(enum network_phy_ciphers cipher = NETWORK_PHY_CIPHER_WEP40; cipher <= NETWORK_PHY_CIPHER_WPISMS4; cipher <<= 1)
+
#define foreach_vht_cap(cap) \
for(int cap = NETWORK_PHY_VHT_CAP_VHT160; cap <= NETWORK_PHY_VHT_CAP_TX_ANTENNA_PATTERN; cap <<= 1)
TAILQ_HEAD(head, network_phy_channel) channels;
+ enum network_phy_ciphers ciphers;
ssize_t max_mpdu_length;
unsigned int vht_caps;
unsigned int ht_caps;
return atoi(index);
}
+static void phy_parse_ciphers(struct network_phy* phy, __u32* ciphers, int num) {
+ enum network_phy_ciphers cipher;
+
+ // Reset value
+ phy->ciphers = 0;
+
+ for (int i = 0; i < num; i++) {
+ switch (ciphers[i]) {
+ case 0x000fac01:
+ cipher = NETWORK_PHY_CIPHER_WEP40;
+ break;
+
+ case 0x000fac02:
+ cipher = NETWORK_PHY_CIPHER_TKIP;
+ break;
+
+ case 0x000fac04:
+ cipher = NETWORK_PHY_CIPHER_CCMP128;
+ break;
+
+ case 0x000fac05:
+ cipher = NETWORK_PHY_CIPHER_WEP104;
+ break;
+
+ case 0x000fac06:
+ cipher = NETWORK_PHY_CIPHER_CMAC128;
+ break;
+
+ case 0x000fac08:
+ cipher = NETWORK_PHY_CIPHER_GCMP128;
+ break;
+
+ case 0x000fac09:
+ cipher = NETWORK_PHY_CIPHER_GCMP256;
+ break;
+
+ /*
+ I have no idea what these are. My card reports them but
+ I could not find out anything about them.
+ */
+ case 0x000fac0a:
+ case 0x000fac0b:
+ case 0x000fac0c:
+ case 0x000fac0d:
+ continue;
+
+ case 0x000fac10:
+ cipher = NETWORK_PHY_CIPHER_CCMP256;
+ break;
+
+ case 0x000fac11:
+ cipher = NETWORK_PHY_CIPHER_GMAC128;
+ break;
+
+ case 0x000fac12:
+ cipher = NETWORK_PHY_CIPHER_GMAC256;
+ break;
+
+ case 0x000fac13:
+ cipher = NETWORK_PHY_CIPHER_CMAC256;
+ break;
+
+ case 0x00147201:
+ cipher = NETWORK_PHY_CIPHER_WPISMS4;
+ break;
+
+ default:
+ ERROR(phy->ctx, "Unknown cipher found: %x\n", ciphers[i]);
+ continue;
+ }
+
+ phy->ciphers |= cipher;
+ }
+}
+
static void phy_parse_vht_capabilities(struct network_phy* phy, __u32 caps) {
// Max MPDU length
switch (caps & 0x3) {
nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
+ // Ciphers
+ if (attrs[NL80211_ATTR_CIPHER_SUITES]) {
+ int num = nla_len(attrs[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
+ __u32* ciphers = nla_data(attrs[NL80211_ATTR_CIPHER_SUITES]);
+ phy_parse_ciphers(phy, ciphers, num);
+ }
+
if (attrs[NL80211_ATTR_WIPHY_BANDS]) {
struct nlattr* nl_band;
int i;
return NULL;
}
+NETWORK_EXPORT const char* network_phy_get_cipher_string(const enum network_phy_ciphers cipher) {
+ switch (cipher) {
+ case NETWORK_PHY_CIPHER_WEP40:
+ return "WEP40";
+
+ case NETWORK_PHY_CIPHER_TKIP:
+ return "TKIP";
+
+ case NETWORK_PHY_CIPHER_CCMP128:
+ return "CCMP-128";
+
+ case NETWORK_PHY_CIPHER_WEP104:
+ return "WEP-104";
+
+ case NETWORK_PHY_CIPHER_CMAC128:
+ return "CMAC-128";
+
+ case NETWORK_PHY_CIPHER_GCMP128:
+ return "GCMP-128";
+
+ case NETWORK_PHY_CIPHER_GCMP256:
+ return "GCMP-256";
+
+ case NETWORK_PHY_CIPHER_CCMP256:
+ return "CCMP-256";
+
+ case NETWORK_PHY_CIPHER_GMAC128:
+ return "GMAC-128";
+
+ case NETWORK_PHY_CIPHER_GMAC256:
+ return "GMAC-256";
+
+ case NETWORK_PHY_CIPHER_CMAC256:
+ return "CMAC-256";
+
+ case NETWORK_PHY_CIPHER_WPISMS4:
+ return "WPI-SMS4";
+ }
+
+ return NULL;
+}
+
+NETWORK_EXPORT int network_phy_supports_cipher(struct network_phy* phy, const enum network_phy_ciphers cipher) {
+ return phy->ciphers & cipher;
+}
+
+NETWORK_EXPORT char* network_phy_list_ciphers(struct network_phy* phy) {
+ char* buffer = NULL;
+
+ foreach_cipher(cipher) {
+ if (network_phy_supports_cipher(phy, cipher)) {
+ const char* s = network_phy_get_cipher_string(cipher);
+
+ if (!s)
+ continue;
+
+ if (buffer)
+ asprintf(&buffer, "%s %s", buffer, s);
+ else
+ asprintf(&buffer, "%s", s);
+ }
+ }
+
+ return buffer;
+}
+
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-phy-list-channels
+/network-phy-list-ciphers
/network-phy-list-ht-caps
/network-phy-list-vht-caps
--- /dev/null
+/*#############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2019 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 ciphers
+ char* ciphers = network_phy_list_ciphers(phy);
+ if (ciphers && *ciphers) {
+ printf("%s\n", ciphers);
+ free(ciphers);
+ }
+
+END:
+ network_phy_unref(phy);
+ network_unref(ctx);
+ return r;
+}