static void add_group_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec) { guint32 num = nm_setting_wireless_security_get_num_groups (sec); guint32 flags = NM_802_11_AP_SEC_NONE; guint32 i; /* If no ciphers are specified, that means "all" WPA ciphers */ if (num == 0) { flags |= NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP; } else { for (i = 0; i < num; i++) { const char *cipher = nm_setting_wireless_security_get_group (sec, i); if (!strcmp (cipher, "wep40")) flags |= NM_802_11_AP_SEC_GROUP_WEP40; else if (!strcmp (cipher, "wep104")) flags |= NM_802_11_AP_SEC_GROUP_WEP104; else if (!strcmp (cipher, "tkip")) flags |= NM_802_11_AP_SEC_GROUP_TKIP; else if (!strcmp (cipher, "ccmp")) flags |= NM_802_11_AP_SEC_GROUP_CCMP; } } if (has_proto (sec, PROTO_WPA)) nm_ap_set_wpa_flags (ap, nm_ap_get_wpa_flags (ap) | flags); if (has_proto (sec, PROTO_RSN)) nm_ap_set_rsn_flags (ap, nm_ap_get_rsn_flags (ap) | flags); }
static void add_pair_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec) { guint32 num = nm_setting_wireless_security_get_num_pairwise (sec); NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; guint32 i; /* If no ciphers are specified, that means "all" WPA ciphers */ if (num == 0) { flags |= NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP; } else { for (i = 0; i < num; i++) { const char *cipher = nm_setting_wireless_security_get_pairwise (sec, i); if (!strcmp (cipher, "tkip")) flags |= NM_802_11_AP_SEC_PAIR_TKIP; else if (!strcmp (cipher, "ccmp")) flags |= NM_802_11_AP_SEC_PAIR_CCMP; } } if (has_proto (sec, PROTO_WPA)) nm_ap_set_wpa_flags (ap, nm_ap_get_wpa_flags (ap) | flags); if (has_proto (sec, PROTO_RSN)) nm_ap_set_rsn_flags (ap, nm_ap_get_rsn_flags (ap) | flags); }
NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection) { NMAccessPoint *ap; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; const GByteArray *ssid; const char *mode, *band, *key_mgmt; guint32 channel, flags; gboolean psk = FALSE, eap = FALSE; g_return_val_if_fail (connection != NULL, NULL); s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS)); g_return_val_if_fail (s_wireless != NULL, NULL); ssid = nm_setting_wireless_get_ssid (s_wireless); g_return_val_if_fail (ssid != NULL, NULL); g_return_val_if_fail (ssid->len > 0, NULL); ap = nm_ap_new (); nm_ap_set_fake (ap, TRUE); nm_ap_set_ssid (ap, ssid); // FIXME: bssid too? mode = nm_setting_wireless_get_mode (s_wireless); if (mode) { if (!strcmp (mode, "infrastructure")) nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); else if (!strcmp (mode, "adhoc")) nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); else goto error; } else { nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); } band = nm_setting_wireless_get_band (s_wireless); channel = nm_setting_wireless_get_channel (s_wireless); if (band && channel) { guint32 freq = channel_to_freq (channel, band); if (freq == 0) goto error; nm_ap_set_freq (ap, freq); } s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); /* Assume presence of a security setting means the AP is encrypted */ if (!s_wireless_sec) goto done; key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); /* Everything below here uses encryption */ nm_ap_set_flags (ap, nm_ap_get_flags (ap) | NM_802_11_AP_FLAGS_PRIVACY); /* Static & Dynamic WEP */ if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x")) goto done; psk = !strcmp (key_mgmt, "wpa-psk"); eap = !strcmp (key_mgmt, "wpa-eap"); if (psk || eap) { if (has_proto (s_wireless_sec, PROTO_WPA)) { flags = nm_ap_get_wpa_flags (ap); flags |= eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK; nm_ap_set_wpa_flags (ap, flags); } if (has_proto (s_wireless_sec, PROTO_RSN)) { flags = nm_ap_get_rsn_flags (ap); flags |= eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK; nm_ap_set_rsn_flags (ap, flags); } add_pair_ciphers (ap, s_wireless_sec); add_group_ciphers (ap, s_wireless_sec); } else if (!strcmp (key_mgmt, "wpa-none")) { guint32 i; /* Ad-Hoc has special requirements: proto=WPA, pairwise=(none), and * group=TKIP/CCMP (but not both). */ flags = nm_ap_get_wpa_flags (ap); flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; /* Clear ciphers; pairwise must be unset anyway, and group gets set below */ flags &= ~( NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 | NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_WEP40 | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP); for (i = 0; i < nm_setting_wireless_security_get_num_groups (s_wireless_sec); i++) { if (!strcmp (nm_setting_wireless_security_get_group (s_wireless_sec, i), "ccmp")) { flags |= NM_802_11_AP_SEC_GROUP_CCMP; break; } } /* Default to TKIP since not all WPA-capable cards can do CCMP */ if (!(flags & NM_802_11_AP_SEC_GROUP_CCMP)) flags |= NM_802_11_AP_SEC_GROUP_TKIP; nm_ap_set_wpa_flags (ap, flags); /* Don't use Ad-Hoc RSN yet */ nm_ap_set_rsn_flags (ap, NM_802_11_AP_SEC_NONE); } done: return ap; error: g_object_unref (ap); return NULL; }
static void foreach_property_cb (gpointer key, gpointer value, gpointer user_data) { GValue *variant = (GValue *) value; NMAccessPoint *ap = (NMAccessPoint *) user_data; if (G_VALUE_HOLDS_BOXED (variant)) { GArray *array = g_value_get_boxed (variant); if (!strcmp (key, "ssid")) { guint32 len = MIN (IW_ESSID_MAX_SIZE, array->len); GByteArray * ssid; /* Stupid ieee80211 layer uses <hidden> */ if (((len == 8) || (len == 9)) && (memcmp (array->data, "<hidden>", 8) == 0)) return; if (nm_utils_is_empty_ssid ((const guint8 *) array->data, len)) return; ssid = g_byte_array_sized_new (len); g_byte_array_append (ssid, (const guint8 *) array->data, len); nm_ap_set_ssid (ap, ssid); g_byte_array_free (ssid, TRUE); } else if (!strcmp (key, "bssid")) { struct ether_addr addr; if (array->len != ETH_ALEN) return; memset (&addr, 0, sizeof (struct ether_addr)); memcpy (&addr, array->data, ETH_ALEN); nm_ap_set_address (ap, &addr); } else if (!strcmp (key, "wpaie")) { guint8 * ie = (guint8 *) array->data; guint32 flags = nm_ap_get_wpa_flags (ap); if (array->len <= 0 || array->len > WPA_MAX_IE_LEN) return; flags = nm_ap_add_security_from_ie (flags, ie, array->len); nm_ap_set_wpa_flags (ap, flags); } else if (!strcmp (key, "rsnie")) { guint8 * ie = (guint8 *) array->data; guint32 flags = nm_ap_get_rsn_flags (ap); if (array->len <= 0 || array->len > WPA_MAX_IE_LEN) return; flags = nm_ap_add_security_from_ie (flags, ie, array->len); nm_ap_set_rsn_flags (ap, flags); } } else if (G_VALUE_HOLDS_INT (variant)) { gint32 int_val = g_value_get_int (variant); if (!strcmp (key, "frequency")) { nm_ap_set_freq (ap, (guint32) int_val); } else if (!strcmp (key, "maxrate")) { /* Supplicant reports as b/s, we use Kb/s internally */ nm_ap_set_max_bitrate (ap, int_val / 1000); } } else if (G_VALUE_HOLDS_UINT (variant)) { guint32 val = g_value_get_uint (variant); if (!strcmp (key, "capabilities")) { if (val & IEEE80211_CAP_ESS) { nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); } else if (val & IEEE80211_CAP_IBSS) { nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); } if (val & IEEE80211_CAP_PRIVACY) { guint32 flags = nm_ap_get_flags (ap); nm_ap_set_flags (ap, flags | NM_802_11_AP_FLAGS_PRIVACY); } } } }
static void foreach_property_cb (gpointer key, gpointer value, gpointer user_data) { GValue *variant = (GValue *) value; NMAccessPoint *ap = (NMAccessPoint *) user_data; if (G_VALUE_HOLDS_BOXED (variant)) { GArray *array = g_value_get_boxed (variant); if (!strcmp (key, "SSID")) { guint32 len = MIN (32, array->len); GByteArray *ssid; /* Stupid ieee80211 layer uses <hidden> */ if (((len == 8) || (len == 9)) && (memcmp (array->data, "<hidden>", 8) == 0)) return; if (nm_utils_is_empty_ssid ((const guint8 *) array->data, len)) return; ssid = g_byte_array_sized_new (len); g_byte_array_append (ssid, (const guint8 *) array->data, len); nm_ap_set_ssid (ap, ssid); g_byte_array_free (ssid, TRUE); } else if (!strcmp (key, "BSSID")) { struct ether_addr addr; if (array->len != ETH_ALEN) return; memset (&addr, 0, sizeof (struct ether_addr)); memcpy (&addr, array->data, ETH_ALEN); nm_ap_set_address (ap, &addr); } else if (!strcmp (key, "Rates")) { guint32 maxrate = 0; int i; /* Find the max AP rate */ for (i = 0; i < array->len; i++) { guint32 r = g_array_index (array, guint32, i); if (r > maxrate) { maxrate = r; nm_ap_set_max_bitrate (ap, r / 1000); } } } else if (!strcmp (key, "WPA")) { NM80211ApSecurityFlags flags = nm_ap_get_wpa_flags (ap); flags |= security_from_dict (g_value_get_boxed (variant)); nm_ap_set_wpa_flags (ap, flags); } else if (!strcmp (key, "RSN")) { NM80211ApSecurityFlags flags = nm_ap_get_rsn_flags (ap); flags |= security_from_dict (g_value_get_boxed (variant)); nm_ap_set_rsn_flags (ap, flags); } } else if (G_VALUE_HOLDS_UINT (variant)) { guint32 val = g_value_get_uint (variant); if (!strcmp (key, "Frequency")) nm_ap_set_freq (ap, val); } else if (G_VALUE_HOLDS_INT (variant)) { gint val = g_value_get_int (variant); if (!strcmp (key, "Signal")) nm_ap_set_strength (ap, nm_ap_utils_level_to_quality (val)); } else if (G_VALUE_HOLDS_STRING (variant)) { const char *val = g_value_get_string (variant); if (val && !strcmp (key, "Mode")) { if (strcmp (val, "infrastructure") == 0) nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); else if (strcmp (val, "ad-hoc") == 0) nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); } } else if (G_VALUE_HOLDS_BOOLEAN (variant)) { gboolean val = g_value_get_boolean (variant); if (strcmp (key, "Privacy") == 0) { if (val) { NM80211ApFlags flags = nm_ap_get_flags (ap); nm_ap_set_flags (ap, flags | NM_802_11_AP_FLAGS_PRIVACY); } } } }
NMAccessPoint * nm_ap_match_in_list (NMAccessPoint *find_ap, GSList *ap_list, gboolean strict_match) { GSList *iter; g_return_val_if_fail (find_ap != NULL, NULL); for (iter = ap_list; iter; iter = g_slist_next (iter)) { NMAccessPoint * list_ap = NM_AP (iter->data); const GByteArray * list_ssid = nm_ap_get_ssid (list_ap); const struct ether_addr * list_addr = nm_ap_get_address (list_ap); const GByteArray * find_ssid = nm_ap_get_ssid (find_ap); const struct ether_addr * find_addr = nm_ap_get_address (find_ap); /* SSID match; if both APs are hiding their SSIDs, * let matching continue on BSSID and other properties */ if ( (!list_ssid && find_ssid) || (list_ssid && !find_ssid) || !nm_utils_same_ssid (list_ssid, find_ssid, TRUE)) continue; /* BSSID match */ if ( (strict_match || nm_ethernet_address_is_valid (find_addr)) && nm_ethernet_address_is_valid (list_addr) && memcmp (list_addr->ether_addr_octet, find_addr->ether_addr_octet, ETH_ALEN) != 0) { continue; } /* mode match */ if (nm_ap_get_mode (list_ap) != nm_ap_get_mode (find_ap)) continue; /* Frequency match */ if (nm_ap_get_freq (list_ap) != nm_ap_get_freq (find_ap)) continue; /* AP flags */ if (nm_ap_get_flags (list_ap) != nm_ap_get_flags (find_ap)) continue; if (strict_match) { if (nm_ap_get_wpa_flags (list_ap) != nm_ap_get_wpa_flags (find_ap)) continue; if (nm_ap_get_rsn_flags (list_ap) != nm_ap_get_rsn_flags (find_ap)) continue; } else { NM80211ApSecurityFlags list_wpa_flags = nm_ap_get_wpa_flags (list_ap); NM80211ApSecurityFlags find_wpa_flags = nm_ap_get_wpa_flags (find_ap); NM80211ApSecurityFlags list_rsn_flags = nm_ap_get_rsn_flags (list_ap); NM80211ApSecurityFlags find_rsn_flags = nm_ap_get_rsn_flags (find_ap); /* Just ensure that there is overlap in the capabilities */ if ( !capabilities_compatible (list_wpa_flags, find_wpa_flags) && !capabilities_compatible (list_rsn_flags, find_rsn_flags)) continue; } return list_ap; } return NULL; }
gboolean nm_ap_check_compatible (NMAccessPoint *self, NMConnection *connection) { NMAccessPointPrivate *priv; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; const char *mode; const char *band; const GByteArray *bssid; guint32 channel; g_return_val_if_fail (NM_IS_AP (self), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); priv = NM_AP_GET_PRIVATE (self); s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS)); if (s_wireless == NULL) return FALSE; if (!nm_utils_same_ssid (nm_setting_wireless_get_ssid (s_wireless), priv->ssid, TRUE)) return FALSE; bssid = nm_setting_wireless_get_bssid (s_wireless); if (bssid && memcmp (bssid->data, &priv->address, ETH_ALEN)) return FALSE; mode = nm_setting_wireless_get_mode (s_wireless); if (mode) { if (!strcmp (mode, "infrastructure") && (priv->mode != NM_802_11_MODE_INFRA)) return FALSE; if (!strcmp (mode, "adhoc") && (priv->mode != NM_802_11_MODE_ADHOC)) return FALSE; } band = nm_setting_wireless_get_band (s_wireless); if (band) { if (!strcmp (band, "a")) { if (priv->freq < 4915 || priv->freq > 5825) return FALSE; } else if (!strcmp (band, "bg")) { if (priv->freq < 2412 || priv->freq > 2484) return FALSE; } } channel = nm_setting_wireless_get_channel (s_wireless); if (channel) { guint32 ap_chan = nm_utils_wifi_freq_to_channel (priv->freq); if (channel != ap_chan) return FALSE; } s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); return nm_setting_wireless_ap_security_compatible (s_wireless, s_wireless_sec, nm_ap_get_flags (self), nm_ap_get_wpa_flags (self), nm_ap_get_rsn_flags (self), nm_ap_get_mode (self)); }