diff options
Diffstat (limited to 'src/supplicant-manager/nm-supplicant-interface.c')
| -rw-r--r-- | src/supplicant-manager/nm-supplicant-interface.c | 109 |
1 files changed, 105 insertions, 4 deletions
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index dc35d5af..75450a0a 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -86,12 +86,14 @@ typedef struct { char * dev; gboolean is_wireless; gboolean has_credreq; /* Whether querying 802.1x credentials is supported */ + ApSupport ap_support; /* Lightweight AP mode support */ gboolean fast_supported; guint32 max_scan_ssids; guint32 ready_count; char * object_path; guint32 state; + int disconnect_reason; NMCallStore * assoc_pcalls; NMCallStore * other_pcalls; @@ -468,7 +470,14 @@ set_state (NMSupplicantInterface *self, guint32 new_state) || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) priv->last_scan = time (NULL); - g_signal_emit (self, signals[STATE], 0, priv->state, old_state); + /* Disconnect reason is no longer relevant when not in the DISCONNECTED state */ + if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED) + priv->disconnect_reason = 0; + + g_signal_emit (self, signals[STATE], 0, + priv->state, + old_state, + priv->disconnect_reason); } static void @@ -607,6 +616,21 @@ wpas_iface_properties_changed (DBusGProxy *proxy, value = g_hash_table_lookup (props, "Capabilities"); if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_VARIANT)) parse_capabilities (self, g_value_get_boxed (value)); + + /* Disconnect reason is currently only given for deauthentication events, + * not disassociation; currently they are IEEE 802.11 "reason codes", + * defined by (IEEE 802.11-2007, 7.3.1.7, Table 7-22). Any locally caused + * deauthentication will be negative, while authentications caused by the + * AP will be positive. + */ + value = g_hash_table_lookup (props, "DisconnectReason"); + if (value && G_VALUE_HOLDS (value, G_TYPE_INT)) { + priv->disconnect_reason = g_value_get_int (value); + if (priv->disconnect_reason != 0) { + nm_log_warn (LOGD_SUPPLICANT, "Connection disconnected (reason %d)", + priv->disconnect_reason); + } + } } static void @@ -734,6 +758,7 @@ wpas_iface_check_network_reply (NMSupplicantInterface *self) NMSupplicantInfo *info; DBusGProxyCall *call; + priv->ready_count++; info = nm_supplicant_info_new (self, priv->props_proxy, priv->other_pcalls); call = dbus_g_proxy_begin_call (priv->iface_proxy, "NetworkReply", iface_check_netreply_cb, @@ -746,6 +771,76 @@ wpas_iface_check_network_reply (NMSupplicantInterface *self) nm_supplicant_info_set_call (info, call); } +ApSupport +nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ap_support; +} + +void +nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, + ApSupport ap_support) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* Use the best indicator of support between the supplicant global + * Capabilities property and the interface's introspection data. + */ + if (ap_support > priv->ap_support) + priv->ap_support = ap_support; +} + +static void +iface_check_ap_mode_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMSupplicantInfo *info = (NMSupplicantInfo *) user_data; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface); + char *data; + + /* The ProbeRequest method only exists if AP mode has been enabled */ + if (dbus_g_proxy_end_call (proxy, call_id, NULL, + G_TYPE_STRING, + &data, + G_TYPE_INVALID)) { + if (data && strstr (data, "ProbeRequest")) + priv->ap_support = AP_SUPPORT_YES; + g_free (data); + } + + iface_check_ready (info->interface); +} + +static void +wpas_iface_check_ap_mode (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInfo *info; + DBusGProxyCall *call; + DBusGProxy *proxy; + + priv->ready_count++; + + proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr), + WPAS_DBUS_SERVICE, + priv->object_path, + DBUS_INTERFACE_INTROSPECTABLE); + + info = nm_supplicant_info_new (self, proxy, priv->other_pcalls); + g_object_unref (proxy); + + /* If the global supplicant capabilities property is not present, we can + * fall back to checking whether the ProbeRequest method is supported. If + * neither of these works we have no way of determining if AP mode is + * supported or not. hostap 1.0 and earlier don't support either of these. + */ + call = dbus_g_proxy_begin_call (proxy, "Introspect", + iface_check_ap_mode_cb, + info, + nm_supplicant_info_destroy, + G_TYPE_INVALID); + nm_supplicant_info_set_call (info, call); +} + static void interface_add_done (NMSupplicantInterface *self, char *path) { @@ -818,9 +913,13 @@ interface_add_done (NMSupplicantInterface *self, char *path) path, DBUS_INTERFACE_PROPERTIES); /* Get initial properties and check whether NetworkReply is supported */ + priv->ready_count = 1; wpas_iface_get_props (self); + + /* These two increment ready_count themselves */ wpas_iface_check_network_reply (self); - priv->ready_count = 2; + if (priv->ap_support == AP_SUPPORT_UNKNOWN) + wpas_iface_check_ap_mode (self); } static void @@ -1383,6 +1482,7 @@ nm_supplicant_interface_new (NMSupplicantManager *smgr, const char *ifname, gboolean is_wireless, gboolean fast_supported, + ApSupport ap_support, gboolean start_now) { NMSupplicantInterface *self; @@ -1406,6 +1506,7 @@ nm_supplicant_interface_new (NMSupplicantManager *smgr, priv->dev = g_strdup (ifname); priv->is_wireless = is_wireless; priv->fast_supported = fast_supported; + priv->ap_support = ap_support; if (start_now) interface_add (self, priv->is_wireless); @@ -1540,8 +1641,8 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMSupplicantInterfaceClass, state), NULL, NULL, - _nm_marshal_VOID__UINT_UINT, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + _nm_marshal_VOID__UINT_UINT_INT, + G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT); signals[REMOVED] = g_signal_new (NM_SUPPLICANT_INTERFACE_REMOVED, |