diff --git a/cli/src/devices.c b/cli/src/devices.c index 3d58679e2c..ac57e4e68d 100644 --- a/cli/src/devices.c +++ b/cli/src/devices.c @@ -407,7 +407,10 @@ detail_access_point (gpointer data, gpointer user_data) info->nmc->allowed_fields[0].value = ap_name; info->nmc->allowed_fields[1].value = ssid_str; info->nmc->allowed_fields[2].value = bssid; - info->nmc->allowed_fields[3].value = mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc") : mode == NM_802_11_MODE_INFRA ? _("Infrastructure") : _("Unknown"); + info->nmc->allowed_fields[3].value = mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc") + : mode == NM_802_11_MODE_AP ? _("AP") + : mode == NM_802_11_MODE_INFRA ? _("Infrastructure") + : _("Unknown"); info->nmc->allowed_fields[4].value = freq_str; info->nmc->allowed_fields[5].value = bitrate_str; info->nmc->allowed_fields[6].value = strength_str; diff --git a/examples/C/glib/get-ap-info-libnm-glib.c b/examples/C/glib/get-ap-info-libnm-glib.c index 316bce0e0d..67ee78d16c 100644 --- a/examples/C/glib/get-ap-info-libnm-glib.c +++ b/examples/C/glib/get-ap-info-libnm-glib.c @@ -133,7 +133,10 @@ show_access_point_info (NMAccessPoint *ap) printf ("SSID: %s\n", ssid_str); printf ("BSSID: %s\n", hwaddr); - printf ("Mode: %s\n", mode == NM_802_11_MODE_ADHOC ? "Ad-Hoc" : mode == NM_802_11_MODE_INFRA ? "Infrastructure" : "Unknown"); + printf ("Mode: %s\n", mode == NM_802_11_MODE_ADHOC ? "Ad-Hoc" + : mode == NM_802_11_MODE_AP ? "AP" + : mode == NM_802_11_MODE_INFRA ? "Infrastructure" + : "Unknown"); printf ("Freq: %s\n", freq_str); printf ("Bitrate: %s\n", bitrate_str); printf ("Strength: %s\n", strength_str); diff --git a/include/NetworkManager.h b/include/NetworkManager.h index 91b03f8f50..2e6d8c3cce 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -225,15 +225,23 @@ typedef enum { /** * NM80211Mode: * @NM_802_11_MODE_UNKNOWN: the device or access point mode is unknown - * @NM_802_11_MODE_ADHOC: the device or access point is in Ad-Hoc mode - * @NM_802_11_MODE_INFRA: the device or access point is in infrastructure mode + * @NM_802_11_MODE_ADHOC: for both devices and access point objects, indicates + * the object is part of an Ad-Hoc 802.11 network without a central + * coordinating access point. + * @NM_802_11_MODE_INFRA: the device or access point is in infrastructure mode. + * For devices, this indicates the device is an 802.11 client/station. For + * access point objects, this indicates the object is an access point that + * provides connectivity to clients. + * @NM_802_11_MODE_AP: the device is an access point/hotspot. Not valid for + * access point objects; used only for hotspot mode on the local machine. * * Indicates the 802.11 mode an access point or device is currently in. **/ typedef enum { NM_802_11_MODE_UNKNOWN = 0, NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA + NM_802_11_MODE_INFRA, + NM_802_11_MODE_AP } NM80211Mode; /** diff --git a/introspection/generic-types.xml b/introspection/generic-types.xml index 1a9e316959..681b6662b7 100644 --- a/introspection/generic-types.xml +++ b/introspection/generic-types.xml @@ -26,10 +26,25 @@ Mode is unknown. - Uncoordinated network without central infrastructure. + + For both devices and access point objects, indicates the object is + part of an Ad-Hoc 802.11 network without a central coordinating access + point. + - Coordinated network with one or more central controllers. + + The wireless device or access point is in infrastructure mode. For + devices, this indicates the device is an 802.11 client/station. For + access point objects, this indicates the object is an access point that + provides connectivity to clients. + + + + + The device is an access point/hotspot. Not valid for access point + objects themselves. + diff --git a/libnm-glib/nm-access-point.c b/libnm-glib/nm-access-point.c index fef65575c7..9326d3abce 100644 --- a/libnm-glib/nm-access-point.c +++ b/libnm-glib/nm-access-point.c @@ -347,6 +347,9 @@ nm_access_point_connection_valid (NMAccessPoint *ap, NMConnection *connection) return FALSE; if (!strcmp (setting_mode, "adhoc") && (ap_mode != NM_802_11_MODE_ADHOC)) return FALSE; + /* Hotspot never matches against APs as it's a device-specific mode. */ + if (!strcmp (setting_mode, "ap")) + return FALSE; } /* Band and Channel/Frequency */ @@ -658,7 +661,9 @@ nm_access_point_class_init (NMAccessPointClass *ap_class) /** * NMAccessPoint:mode: * - * The mode of the access point. + * The mode of the access point; either "infrastructure" (a central + * coordinator of the wireless network allowing clients to connect) or + * "ad-hoc" (a network with no central controller). **/ g_object_class_install_property (object_class, PROP_MODE, diff --git a/libnm-util/nm-setting-wireless.c b/libnm-util/nm-setting-wireless.c index 8dfaf4e4c0..4102658fbe 100644 --- a/libnm-util/nm-setting-wireless.c +++ b/libnm-util/nm-setting-wireless.c @@ -592,7 +592,7 @@ static gboolean verify (NMSetting *setting, GSList *all_settings, GError **error) { NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting); - const char *valid_modes[] = { NM_SETTING_WIRELESS_MODE_INFRA, NM_SETTING_WIRELESS_MODE_ADHOC, NULL }; + const char *valid_modes[] = { NM_SETTING_WIRELESS_MODE_INFRA, NM_SETTING_WIRELESS_MODE_ADHOC, NM_SETTING_WIRELESS_MODE_AP, NULL }; const char *valid_bands[] = { "a", "bg", NULL }; GSList *iter; @@ -889,15 +889,15 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class) /** * NMSettingWireless:mode: * - * WiFi network mode; one of 'infrastructure' or 'adhoc'. If blank, + * WiFi network mode; one of 'infrastructure', 'adhoc' or 'ap'. If blank, * infrastructure is assumed. **/ g_object_class_install_property (object_class, PROP_MODE, g_param_spec_string (NM_SETTING_WIRELESS_MODE, "Mode", - "WiFi network mode; one of 'infrastructure' or " - "'adhoc'. If blank, infrastructure is assumed.", + "WiFi network mode; one of 'infrastructure', " + "'adhoc' or 'ap'. If blank, infrastructure is assumed.", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); diff --git a/libnm-util/nm-setting-wireless.h b/libnm-util/nm-setting-wireless.h index e54e8353ee..6e9c4d68f3 100644 --- a/libnm-util/nm-setting-wireless.h +++ b/libnm-util/nm-setting-wireless.h @@ -85,6 +85,14 @@ GQuark nm_setting_wireless_error_quark (void); */ #define NM_SETTING_WIRELESS_MODE_ADHOC "adhoc" +/** + * NM_SETTING_WIRELESS_MODE_AP: + * + * Indicates AP/master mode where the wireless device is started as an access + * point/hotspot. + */ +#define NM_SETTING_WIRELESS_MODE_AP "ap" + /** * NM_SETTING_WIRELESS_MODE_INFRA: * diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index e8b4333dc4..cebde612a1 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -726,6 +726,10 @@ periodic_update (gpointer user_data) || nm_supplicant_interface_get_scanning (priv->supplicant.iface)) return TRUE; + /* In AP mode we currently have nothing to do. */ + if (priv->current_ap && (nm_ap_get_mode (priv->current_ap) == NM_802_11_MODE_AP)) + return TRUE; + /* In IBSS mode, most newer firmware/drivers do "BSS coalescing" where * multiple IBSS stations using the same SSID will eventually switch to * using the same BSSID to avoid network segmentation. When this happens, @@ -1073,6 +1077,15 @@ check_connection_compatible (NMDevice *device, return FALSE; } + if ( (g_strcmp0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) == 0) + && !(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { + g_set_error_literal (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, + "Access Point (AP) mode is not supported by this device."); + return FALSE; + } + // FIXME: check channel/freq/band against bands the hardware supports // FIXME: check encryption against device capabilities // FIXME: check bitrate against device capabilities @@ -2760,7 +2773,7 @@ build_supplicant_config (NMDeviceWifi *self, NMSupplicantConfig *config = NULL; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; - guint32 adhoc_freq = 0; + guint32 fixed_freq = 0; g_return_val_if_fail (self != NULL, NULL); @@ -2771,35 +2784,36 @@ build_supplicant_config (NMDeviceWifi *self, if (!config) return NULL; - /* Supplicant requires an initial frequency for Ad-Hoc networks; if the user + /* Supplicant requires an initial frequency for Ad-Hoc and Hotspot; if the user * didn't specify one and we didn't find an AP that matched the connection, * just pick a frequency the device supports. */ - if (nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) { + if ( nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC + || nm_ap_get_mode (ap) == NM_802_11_MODE_AP) { const char *band = nm_setting_wireless_get_band (s_wireless); const guint32 a_freqs[] = { 5180, 5200, 5220, 5745, 5765, 5785, 5805, 0 }; const guint32 bg_freqs[] = { 2412, 2437, 2462, 2472, 0 }; - adhoc_freq = nm_ap_get_freq (ap); - if (!adhoc_freq) { + fixed_freq = nm_ap_get_freq (ap); + if (!fixed_freq) { if (g_strcmp0 (band, "a") == 0) - adhoc_freq = wifi_utils_find_freq (priv->wifi_data, a_freqs); + fixed_freq = wifi_utils_find_freq (priv->wifi_data, a_freqs); else - adhoc_freq = wifi_utils_find_freq (priv->wifi_data, bg_freqs); + fixed_freq = wifi_utils_find_freq (priv->wifi_data, bg_freqs); } - if (!adhoc_freq) { + if (!fixed_freq) { if (g_strcmp0 (band, "a") == 0) - adhoc_freq = 5180; + fixed_freq = 5180; else - adhoc_freq = 2462; + fixed_freq = 2462; } } if (!nm_supplicant_config_add_setting_wireless (config, s_wireless, nm_ap_get_broadcast (ap), - adhoc_freq, + fixed_freq, wifi_utils_can_scan_ssid (priv->wifi_data))) { nm_log_err (LOGD_WIFI, "Couldn't add 802-11-wireless setting to supplicant config."); goto error; diff --git a/src/nm-wifi-ap-utils.c b/src/nm-wifi-ap-utils.c index 215c4935c9..29aa52a4d2 100644 --- a/src/nm-wifi-ap-utils.c +++ b/src/nm-wifi-ap-utils.c @@ -514,7 +514,8 @@ nm_ap_utils_complete_connection (const GByteArray *ap_ssid, gboolean valid = FALSE; /* Make sure the supplied mode matches the AP's */ - if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA)) { + if ( !strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA) + || !strcmp (mode, NM_SETTING_WIRELESS_MODE_AP)) { if (ap_mode == NM_802_11_MODE_INFRA) valid = TRUE; } else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c index 6a607960a8..b8709e78ad 100644 --- a/src/nm-wifi-ap.c +++ b/src/nm-wifi-ap.c @@ -58,6 +58,7 @@ typedef struct /* Non-scanned attributes */ gboolean fake; /* Whether or not the AP is from a scan */ + gboolean hotspot; /* Whether the AP is a local device's hotspot network */ gboolean broadcast; /* Whether or not the AP is broadcasting (hidden) */ glong last_seen; /* Last time the AP was seen in a scan in seconds */ } NMAccessPointPrivate; @@ -650,7 +651,10 @@ nm_ap_new_fake_from_connection (NMConnection *connection) 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 + else if (!strcmp (mode, "ap")) { + nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); + NM_AP_GET_PRIVATE (ap)->hotspot = TRUE; + } else goto error; } else { nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); @@ -975,6 +979,13 @@ void nm_ap_set_mode (NMAccessPoint *ap, const NM80211Mode mode) } } +gboolean +nm_ap_is_hotspot (NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), FALSE); + + return NM_AP_GET_PRIVATE (ap)->hotspot; +} /* * Get/set functions for strength @@ -1160,6 +1171,10 @@ nm_ap_check_compatible (NMAccessPoint *self, return FALSE; if (!strcmp (mode, "adhoc") && (priv->mode != NM_802_11_MODE_ADHOC)) return FALSE; + if ( !strcmp (mode, "ap") + && (priv->mode != NM_802_11_MODE_INFRA) + && (priv->hotspot != TRUE)) + return FALSE; } band = nm_setting_wireless_get_band (s_wireless); diff --git a/src/nm-wifi-ap.h b/src/nm-wifi-ap.h index 2058deda66..a1a0da9208 100644 --- a/src/nm-wifi-ap.h +++ b/src/nm-wifi-ap.h @@ -86,6 +86,8 @@ void nm_ap_set_address (NMAccessPoint *ap, const struct ether_addr *addr); NM80211Mode nm_ap_get_mode (NMAccessPoint *ap); void nm_ap_set_mode (NMAccessPoint *ap, const NM80211Mode mode); +gboolean nm_ap_is_hotspot (NMAccessPoint *ap); + gint8 nm_ap_get_strength (NMAccessPoint *ap); void nm_ap_set_strength (NMAccessPoint *ap, gint8 strength); diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c index a8e4ab9d55..a91413fabe 100644 --- a/src/supplicant-manager/nm-supplicant-config.c +++ b/src/supplicant-manager/nm-supplicant-config.c @@ -363,11 +363,11 @@ gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, NMSettingWireless * setting, gboolean is_broadcast, - guint32 adhoc_freq, + guint32 fixed_freq, gboolean has_scan_capa_ssid) { NMSupplicantConfigPrivate *priv; - gboolean is_adhoc; + gboolean is_adhoc, is_ap; const char *mode; const GByteArray *id; @@ -378,7 +378,8 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, mode = nm_setting_wireless_get_mode (setting); is_adhoc = (mode && !strcmp (mode, "adhoc")) ? TRUE : FALSE; - if (is_adhoc) + is_ap = (mode && !strcmp (mode, "ap")) ? TRUE : FALSE; + if (is_adhoc || is_ap) priv->ap_scan = 2; else if (is_broadcast == FALSE) { /* drivers that support scanning specific SSIDs should use @@ -395,27 +396,34 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, if (is_adhoc) { if (!nm_supplicant_config_add_option (self, "mode", "1", -1, FALSE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding mode to supplicant config."); + nm_log_warn (LOGD_SUPPLICANT, "Error adding mode=1 (adhoc) to supplicant config."); return FALSE; } - - if (adhoc_freq) { - char *str_freq; - - str_freq = g_strdup_printf ("%u", adhoc_freq); - if (!nm_supplicant_config_add_option (self, "frequency", str_freq, -1, FALSE)) { - g_free (str_freq); - nm_log_warn (LOGD_SUPPLICANT, "Error adding Ad-Hoc frequency to supplicant config."); - return FALSE; - } - g_free (str_freq); - } } - /* Except for Ad-Hoc networks, request that the driver probe for the + if (is_ap) { + if (!nm_supplicant_config_add_option (self, "mode", "2", -1, FALSE)) { + nm_log_warn (LOGD_SUPPLICANT, "Error adding mode=2 (ap) to supplicant config."); + return FALSE; + } + } + + if ((is_adhoc || is_ap) && fixed_freq) { + char *str_freq; + + str_freq = g_strdup_printf ("%u", fixed_freq); + if (!nm_supplicant_config_add_option (self, "frequency", str_freq, -1, FALSE)) { + g_free (str_freq); + nm_log_warn (LOGD_SUPPLICANT, "Error adding Ad-Hoc/AP frequency to supplicant config."); + return FALSE; + } + g_free (str_freq); + } + + /* Except for Ad-Hoc and Hotspot, request that the driver probe for the * specific SSID we want to associate with. */ - if (!is_adhoc) { + if (!(is_adhoc || is_ap)) { if (!nm_supplicant_config_add_option (self, "scan_ssid", "1", -1, FALSE)) return FALSE; } diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c index 76de84d822..143e51a360 100644 --- a/src/supplicant-manager/nm-supplicant-settings-verify.c +++ b/src/supplicant-manager/nm-supplicant-settings-verify.c @@ -91,7 +91,7 @@ static const struct Opt opt_table[] = { { "ssid", TYPE_BYTES, 0, 32,FALSE, NULL }, { "bssid", TYPE_KEYWORD, 0, 0, FALSE, NULL }, { "scan_ssid", TYPE_INT, 0, 1, FALSE, NULL }, - { "mode", TYPE_INT, 0, 1, FALSE, NULL }, + { "mode", TYPE_INT, 0, 2, FALSE, NULL }, { "frequency", TYPE_INT, 2412, 5825, FALSE, NULL }, { "auth_alg", TYPE_KEYWORD, 0, 0, FALSE, auth_alg_allowed }, { "psk", TYPE_BYTES, 0, 0, FALSE, NULL }, diff --git a/src/wifi/wifi-utils-nl80211.c b/src/wifi/wifi-utils-nl80211.c index 663cbc2682..12692688b8 100644 --- a/src/wifi/wifi-utils-nl80211.c +++ b/src/wifi/wifi-utils-nl80211.c @@ -187,6 +187,9 @@ static int nl80211_iface_info_handler (struct nl_msg *msg, void *arg) case NL80211_IFTYPE_ADHOC: info->mode = NM_802_11_MODE_ADHOC; break; + case NL80211_IFTYPE_AP: + info->mode = NM_802_11_MODE_AP; + break; case NL80211_IFTYPE_STATION: info->mode = NM_802_11_MODE_INFRA; break; diff --git a/src/wifi/wifi-utils-wext.c b/src/wifi/wifi-utils-wext.c index 75d00f4120..37cd94e987 100644 --- a/src/wifi/wifi-utils-wext.c +++ b/src/wifi/wifi-utils-wext.c @@ -118,6 +118,8 @@ wifi_wext_get_mode (WifiData *data) switch (wrq.u.mode) { case IW_MODE_ADHOC: return NM_802_11_MODE_ADHOC; + case IW_MODE_MASTER: + return NM_802_11_MODE_AP; case IW_MODE_INFRA: return NM_802_11_MODE_INFRA; default: @@ -140,6 +142,9 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) case NM_802_11_MODE_ADHOC: wrq.u.mode = IW_MODE_ADHOC; break; + case NM_802_11_MODE_AP: + wrq.u.mode = IW_MODE_MASTER; + break; case NM_802_11_MODE_INFRA: wrq.u.mode = IW_MODE_INFRA; break; diff --git a/src/wifi/wifi-utils.c b/src/wifi/wifi-utils.c index a99a4b7bc9..fc491ec4f8 100644 --- a/src/wifi/wifi-utils.c +++ b/src/wifi/wifi-utils.c @@ -96,7 +96,9 @@ gboolean wifi_utils_set_mode (WifiData *data, const NM80211Mode mode) { g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail ((mode == NM_802_11_MODE_INFRA) || (mode == NM_802_11_MODE_ADHOC), FALSE); + g_return_val_if_fail ( (mode == NM_802_11_MODE_INFRA) + || (mode == NM_802_11_MODE_AP) + || (mode == NM_802_11_MODE_ADHOC), FALSE); /* nl80211 probably doesn't need this */ return data->set_mode ? data->set_mode (data, mode) : TRUE; diff --git a/test/nm-tool.c b/test/nm-tool.c index d8c75cee62..47bf2e2f74 100644 --- a/test/nm-tool.c +++ b/test/nm-tool.c @@ -161,7 +161,9 @@ detail_access_point (gpointer data, gpointer user_data) str = g_string_new (NULL); g_string_append_printf (str, "%s, %s, Freq %d MHz, Rate %d Mb/s, Strength %d", - (nm_access_point_get_mode (ap) == NM_802_11_MODE_INFRA) ? "Infra" : "Ad-Hoc", + nm_access_point_get_mode (ap) == NM_802_11_MODE_ADHOC ? "Ad-Hoc" + : nm_access_point_get_mode (ap) == NM_802_11_MODE_INFRA ? "Infra" + : "Unknown", nm_access_point_get_hw_address (ap), nm_access_point_get_frequency (ap), nm_access_point_get_max_bitrate (ap) / 1000,