diff options
Diffstat (limited to 'src/core/devices/wifi/nm-wifi-utils.c')
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-utils.c | 256 |
1 files changed, 202 insertions, 54 deletions
diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index 4939e786..1a8204b0 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -41,9 +41,9 @@ verify_no_wep(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error static gboolean verify_leap(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, + NMSetting8021x *s_8021x, gboolean adhoc, - GError ** error) + GError **error) { const char *key_mgmt, *auth_alg, *leap_username; @@ -224,9 +224,9 @@ verify_no_wpa(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error static gboolean verify_dynamic_wep(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, + NMSetting8021x *s_8021x, gboolean adhoc, - GError ** error) + GError **error) { const char *key_mgmt, *auth_alg, *leap_username; @@ -303,11 +303,11 @@ verify_dynamic_wep(NMSettingWirelessSecurity *s_wsec, static gboolean verify_wpa_psk(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, + NMSetting8021x *s_8021x, gboolean adhoc, guint32 wpa_flags, guint32 rsn_flags, - GError ** error) + GError **error) { const char *key_mgmt, *auth_alg; @@ -400,10 +400,10 @@ verify_wpa_psk(NMSettingWirelessSecurity *s_wsec, static gboolean verify_wpa_eap(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, + NMSetting8021x *s_8021x, guint32 wpa_flags, guint32 rsn_flags, - GError ** error) + GError **error) { const char *key_mgmt, *auth_alg; gboolean is_wpa_eap = FALSE; @@ -465,9 +465,9 @@ verify_wpa_eap(NMSettingWirelessSecurity *s_wsec, static gboolean verify_adhoc(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, + NMSetting8021x *s_8021x, gboolean adhoc, - GError ** error) + GError **error) { const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL; @@ -529,8 +529,8 @@ verify_adhoc(NMSettingWirelessSecurity *s_wsec, } gboolean -nm_wifi_utils_complete_connection(GBytes * ap_ssid, - const char * bssid, +nm_wifi_utils_complete_connection(GBytes *ap_ssid, + const char *bssid, _NM80211Mode ap_mode, guint32 ap_freq, guint32 ap_flags, @@ -538,13 +538,13 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, guint32 ap_rsn_flags, NMConnection *connection, gboolean lock_bssid, - GError ** error) + GError **error) { - NMSettingWireless * s_wifi; + NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; - NMSetting8021x * s_8021x; - GBytes * ssid; - const char * mode, *key_mgmt, *auth_alg, *leap_username; + NMSetting8021x *s_8021x; + GBytes *ssid; + const char *mode, *key_mgmt, *auth_alg, *leap_username; gboolean adhoc = FALSE; gboolean mesh = FALSE; @@ -892,20 +892,20 @@ nm_wifi_utils_is_manf_default_ssid(GBytes *ssid) /* To be used for connections where the SSID has been validated before */ gboolean -nm_wifi_connection_get_iwd_ssid_and_security(NMConnection * connection, - char ** ssid, +nm_wifi_connection_get_iwd_ssid_and_security(NMConnection *connection, + char **ssid, NMIwdNetworkSecurity *security) { - NMSettingWireless * s_wireless; + NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; - const char * key_mgmt = NULL; + const char *key_mgmt = NULL; s_wireless = nm_connection_get_setting_wireless(connection); if (!s_wireless) return FALSE; if (ssid) { - GBytes * bytes = nm_setting_wireless_get_ssid(s_wireless); + GBytes *bytes = nm_setting_wireless_get_ssid(s_wireless); gsize ssid_len; const char *ssid_str = (const char *) g_bytes_get_data(bytes, &ssid_len); @@ -947,7 +947,7 @@ nm_wifi_connection_get_iwd_ssid_and_security(NMConnection * connection, * @ssid_len can be -1 instead of actual SSID length. */ char * -nm_wifi_utils_get_iwd_config_filename(const char * ssid, +nm_wifi_utils_get_iwd_config_filename(const char *ssid, gssize ssid_len, NMIwdNetworkSecurity security) { @@ -995,10 +995,10 @@ static gboolean psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GError **error) { NMSettingSecretFlags psk_flags = nm_setting_wireless_security_get_psk_flags(s_wsec); - const char * psk = nm_setting_wireless_security_get_psk(s_wsec); + const char *psk = nm_setting_wireless_security_get_psk(s_wsec); gsize psk_len; guint8 buffer[32]; - const char * key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); + const char *key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); if (!psk || NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { if (NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { @@ -1029,11 +1029,11 @@ psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GEr } static gboolean -eap_certs_to_iwd_config(GKeyFile * file, +eap_certs_to_iwd_config(GKeyFile *file, NMSetting8021x *s_8021x, bool phase2, - char * iwd_prefix, - GError ** error) + char *iwd_prefix, + GError **error) { NMSetting8021xCKScheme ca_cert_scheme = phase2 ? nm_setting_802_1x_get_phase2_ca_cert_scheme(s_8021x) @@ -1043,13 +1043,13 @@ eap_certs_to_iwd_config(GKeyFile * file, : nm_setting_802_1x_get_client_cert_scheme(s_8021x); NMSetting8021xCKScheme key_scheme; NMSettingSecretFlags key_password_flags; - const char * ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x) + const char *ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x) : nm_setting_802_1x_get_ca_path(s_8021x); - const char * cert_path; - const char * key_path = NULL; - const char * key_password; - const char * domain_suffix_match; - const char * domain_match; + const char *cert_path; + const char *key_path = NULL; + const char *key_password; + const char *domain_suffix_match; + const char *domain_match; char setting_buf[128]; /* TODO: should check that all certificates and the key are RSA */ @@ -1220,7 +1220,7 @@ private_key_done: : nm_setting_802_1x_get_domain_match(s_8021x); if (domain_suffix_match || domain_match) { - GString * s = g_string_sized_new(128); + GString *s = g_string_sized_new(128); const char *ptr; const char *end; @@ -1287,13 +1287,13 @@ eap_optional_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, cons } static gboolean -eap_optional_password_to_iwd_config(GKeyFile * file, - const char * iwd_prefix, +eap_optional_password_to_iwd_config(GKeyFile *file, + const char *iwd_prefix, NMSetting8021x *s_8021x, - GError ** error) + GError **error) { char setting_buf[128]; - const char * password = nm_setting_802_1x_get_password(s_8021x); + const char *password = nm_setting_802_1x_get_password(s_8021x); NMSettingSecretFlags flags = nm_setting_802_1x_get_password_flags(s_8021x); if (!password && nm_setting_802_1x_get_password_raw(s_8021x)) { @@ -1347,12 +1347,12 @@ eap_phase1_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, NMSett } static gboolean -eap_method_config_to_iwd_config(GKeyFile * file, +eap_method_config_to_iwd_config(GKeyFile *file, NMSetting8021x *s_8021x, gboolean phase2, - const char * method, - const char * iwd_prefix, - GError ** error) + const char *method, + const char *iwd_prefix, + GError **error) { char prefix_buf[128]; @@ -1677,18 +1677,18 @@ ip6_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error GKeyFile * nm_wifi_utils_connection_to_iwd_config(NMConnection *connection, - char ** out_filename, - GError ** error) + char **out_filename, + GError **error) { - NMSettingConnection * s_conn = nm_connection_get_setting_connection(connection); - NMSettingWireless * s_wifi = nm_connection_get_setting_wireless(connection); - GBytes * ssid; - const guint8 * ssid_data; - gsize ssid_len; - NMIwdNetworkSecurity security; - const char * cloned_mac_addr; - gs_free char * comment = NULL; - nm_auto_unref_keyfile GKeyFile *file = NULL; + NMSettingConnection *s_conn = nm_connection_get_setting_connection(connection); + NMSettingWireless *s_wifi = nm_connection_get_setting_wireless(connection); + GBytes *ssid; + const guint8 *ssid_data; + gsize ssid_len; + NMIwdNetworkSecurity security; + const char *cloned_mac_addr; + gs_free char *comment = NULL; + nm_auto_unref_keyfile GKeyFile *file = NULL; if (!s_conn || !s_wifi || !nm_streq(nm_setting_connection_get_connection_type(s_conn), @@ -1800,3 +1800,151 @@ nm_wifi_utils_connection_to_iwd_config(NMConnection *connection, return g_steal_pointer(&file); } + +/* Wi-Fi Display Technical Specification v2.1.0 Table 27 */ +enum wfd_subelem_type { + WFD_SUBELEM_WFD_DEVICE_INFORMATION = 0, + WFD_SUBELEM_ASSOCIATED_BSSID = 1, + WFD_SUBELEM_COUPLED_SINK_INFORMATION = 6, + WFD_SUBELEM_EXTENDED_CAPABILITY = 7, + WFD_SUBELEM_LOCAL_IP_ADDRESS = 8, + WFD_SUBELEM_SESION_INFORMATION = 9, + WFD_SUBELEM_ALTERNATIVE_MAC_ADDRESS = 10, + WFD_SUBELEM_R2_DEVICE_INFORMATION = 11, +}; + +bool +nm_wifi_utils_parse_wfd_ies(GBytes *ies, NMIwdWfdInfo *out_wfd) +{ + size_t len; + const uint8_t *data = g_bytes_get_data(ies, &len); + const uint8_t *dev_info = NULL; + uint16_t dev_info_len = 0; + uint16_t dev_info_flags; + const uint8_t *ext_capability = NULL; + uint16_t ext_capability_len = 0; + + /* The single WFD IEs array provided by the client is supposed to be sent to + * the peer in the different frame types that may include the WFD IE: Probe + * Request/Response, Beacon, (Re)Association Request/Response, GO + * Negotiation Request/Response/Confirm and Provision Discovery + * Request/Response. + * + * It's going to be a subset of the elements allowed in all those frames. + * Validate that it contains at least a valid WFD Device Information (with + * the Session Available bit true) and that the sequence of subelements is + * valid. + */ + while (len) { + uint8_t subelem_id; + uint16_t subelem_len; + + /* Does the subelement header fit */ + if (len < 3) + return FALSE; + + subelem_id = data[0]; + subelem_len = (data[1] << 8) | data[2]; + data += 3; + len -= 3; + + if (subelem_len > len) + return FALSE; + + if (subelem_id == WFD_SUBELEM_WFD_DEVICE_INFORMATION) { + /* Is there a duplicate WFD Device Information */ + if (dev_info) + return FALSE; + + dev_info = data; + dev_info_len = subelem_len; + } + + if (subelem_id == WFD_SUBELEM_EXTENDED_CAPABILITY) { + /* Is there a duplicate WFD Extended Capability */ + if (ext_capability) + return FALSE; + + ext_capability = data; + ext_capability_len = subelem_len; + } + + data += subelem_len; + len -= subelem_len; + } + + if (!dev_info || dev_info_len != 6) + return FALSE; + + dev_info_flags = (dev_info[0] << 8) | dev_info[1]; + + /* Secondary sink not supported */ + if ((dev_info_flags & 3) == 2) + return FALSE; + + /* Must be available for WFD Session */ + if (((dev_info_flags >> 4) & 3) != 1) + return FALSE; + + /* TDLS persistent group re-invocation not supported */ + if ((dev_info_flags >> 13) & 1) + return FALSE; + + /* All other flags indicate support but not a requirement for something + * so not preserving them in the IEs IWD eventually sends doesn't break + * basic functionality. + */ + + if (ext_capability && ext_capability_len != 2) + return FALSE; + + if (!out_wfd) + return TRUE; + + out_wfd->source = NM_IN_SET(dev_info_flags & 3, 0, 3); + out_wfd->sink = NM_IN_SET(dev_info_flags & 3, 1, 3); + out_wfd->port = (dev_info[2] << 8) | dev_info[3]; + out_wfd->has_audio = + out_wfd->sink ? ((dev_info_flags >> 10) & 1) == 0 : (((dev_info_flags >> 11) & 1) == 1); + out_wfd->has_uibc = ext_capability && (ext_capability[1] & 1) == 1; + out_wfd->has_cp = ((dev_info_flags >> 8) & 1) == 1; + return TRUE; +} + +GBytes * +nm_wifi_utils_build_wfd_ies(const NMIwdWfdInfo *wfd) +{ + uint8_t data[64]; + uint8_t *ptr = data; + + *ptr++ = WFD_SUBELEM_WFD_DEVICE_INFORMATION; + *ptr++ = 0; /* WFD Subelement length */ + *ptr++ = 6; + *ptr++ = 0; /* WFD Device Information bitmap: */ + *ptr++ = (wfd->source ? (wfd->sink ? 3 : 0) : 1) | 0x10 | /* WFD Session Available */ + (wfd->has_cp ? 0x100 : 0) | (wfd->has_audio ? 0 : 0x400); + *ptr++ = wfd->port >> 8; + *ptr++ = wfd->port & 255; + *ptr++ = 0; /* WFD Device Maximum throughput */ + *ptr++ = 10; + + if (wfd->has_uibc) { + *ptr++ = WFD_SUBELEM_EXTENDED_CAPABILITY; + *ptr++ = 0; /* WFD Subelement length */ + *ptr++ = 2; + *ptr++ = 0x00; /* WFD Extended Capability Bitmap: */ + *ptr++ = 0x10; /* UIBC Support */ + } + + return g_bytes_new(data, ptr - data); +} + +bool +nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b) +{ + if (!a || !b) + return a == b; + + return a->source == b->source && a->sink == b->sink && a->port == b->port + && a->has_audio == b->has_audio && a->has_uibc == b->has_uibc && a->has_cp == b->has_cp; +} |