From: "Niu,Bing" <[email protected]>

add new callback function ap_create_fail. supplicant layer will
detect AP creataion fail, and callback wifi plugin. ap_create_fail
will call tech_set_tethering() to try to create AP at next interface.
---
 plugins/wifi.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 109 insertions(+), 12 deletions(-)
 mode change 100644 => 100755 plugins/wifi.c

diff --git a/plugins/wifi.c b/plugins/wifi.c
old mode 100644
new mode 100755
index 42dd407..a12c210
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -74,6 +74,12 @@
 static struct connman_technology *wifi_technology = NULL;
 static struct connman_technology *p2p_technology = NULL;
 
+enum wifi_ap_capability{
+       WIFI_AP_UNKNOWN         = 0,
+       WIFI_AP_SUPPORTED       = 1,
+       WIFI_AP_NOT_SUPPORTED   = 2,
+};
+
 struct hidden_params {
        char ssid[32];
        unsigned int ssid_len;
@@ -95,6 +101,13 @@ struct autoscan_params {
        unsigned int timeout;
 };
 
+struct wifi_tethering_info {
+       struct wifi_data *wifi;
+       struct connman_technology *technology;
+       char *ifname;
+       GSupplicantSSID *ssid;
+};
+
 struct wifi_data {
        char *identifier;
        struct connman_device *device;
@@ -106,6 +119,7 @@ struct wifi_data {
        bool connected;
        bool disconnecting;
        bool tethering;
+       enum wifi_ap_capability ap_supported;
        bool bridged;
        bool interface_ready;
        const char *bridge;
@@ -115,6 +129,7 @@ struct wifi_data {
        int retries;
        struct hidden_params *hidden;
        bool postpone_hidden;
+       struct wifi_tethering_info *tethering_param;
        /**
         * autoscan "emulation".
         */
@@ -137,6 +152,9 @@ static GList *p2p_iface_list = NULL;
 bool wfd_service_registered = false;
 
 static void start_autoscan(struct connman_device *device);
+static int tech_set_tethering(struct connman_technology *technology,
+                               const char *identifier, const char *passphrase,
+                               const char *bridge, bool enabled);
 
 static int p2p_tech_probe(struct connman_technology *technology)
 {
@@ -737,6 +755,8 @@ static int wifi_probe(struct connman_device *device)
                return -ENOMEM;
 
        wifi->state = G_SUPPLICANT_STATE_INACTIVE;
+       wifi->ap_supported = WIFI_AP_UNKNOWN;
+       wifi->tethering_param = NULL;
 
        connman_device_set_data(device, wifi);
        wifi->device = connman_device_ref(device);
@@ -2294,6 +2314,14 @@ static void interface_state(GSupplicantInterface 
*interface)
        if (!wifi)
                return;
 
+       if (state == G_SUPPLICANT_STATE_COMPLETED) {
+               if (wifi->tethering_param) {
+                       g_free(wifi->tethering_param->ssid);
+                       g_free(wifi->tethering_param);
+                       wifi->tethering_param = NULL;
+               }
+       }
+
        device = wifi->device;
        if (!device)
                return;
@@ -2500,6 +2528,36 @@ static void scan_finished(GSupplicantInterface 
*interface)
        DBG("");
 }
 
+static void ap_create_fail(GSupplicantInterface *interface)
+{
+       struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+       int ret;
+
+       if ((wifi->tethering) && (wifi->tethering_param)) {
+               DBG("%s create AP fail \n",
+                               
g_supplicant_interface_get_ifname(wifi->interface));
+
+               connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
+               wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
+               wifi->tethering = false;
+
+               ret = tech_set_tethering(wifi->tethering_param->technology,
+                               wifi->tethering_param->ssid->ssid,
+                               wifi->tethering_param->ssid->passphrase,
+                               wifi->bridge, true);
+
+               if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
+                       
connman_technology_tethering_notify(wifi_technology,false);
+               }
+
+               g_free(wifi->tethering_param->ssid);
+               g_free(wifi->tethering_param);
+               wifi->tethering_param = NULL;
+       }
+
+       return;
+}
+
 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
 {
        unsigned char strength;
@@ -2844,6 +2902,7 @@ static const GSupplicantCallbacks callbacks = {
        .p2p_support            = p2p_support,
        .scan_started           = scan_started,
        .scan_finished          = scan_finished,
+       .ap_create_fail         = ap_create_fail,
        .network_added          = network_added,
        .network_removed        = network_removed,
        .network_changed        = network_changed,
@@ -2867,13 +2926,6 @@ static void tech_remove(struct connman_technology 
*technology)
        wifi_technology = NULL;
 }
 
-struct wifi_tethering_info {
-       struct wifi_data *wifi;
-       struct connman_technology *technology;
-       char *ifname;
-       GSupplicantSSID *ssid;
-};
-
 static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
 {
        GSupplicantSSID *ap;
@@ -2910,10 +2962,16 @@ static void ap_start_callback(int result, 
GSupplicantInterface *interface,
        DBG("result %d index %d bridge %s",
                result, info->wifi->index, info->wifi->bridge);
 
-       if (result < 0) {
+       if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
                connman_inet_remove_from_bridge(info->wifi->index,
                                                        info->wifi->bridge);
-               connman_technology_tethering_notify(info->technology, false);
+
+               if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
+                       connman_technology_tethering_notify(info->technology, 
false);
+                       g_free(info->wifi->tethering_param->ssid);
+                       g_free(info->wifi->tethering_param);
+                       info->wifi->tethering_param = NULL;
+               }
        }
 
        g_free(info->ifname);
@@ -2929,10 +2987,17 @@ static void ap_create_callback(int result,
        DBG("result %d ifname %s", result,
                                g_supplicant_interface_get_ifname(interface));
 
-       if (result < 0) {
+       if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
                connman_inet_remove_from_bridge(info->wifi->index,
                                                        info->wifi->bridge);
-               connman_technology_tethering_notify(info->technology, false);
+
+               if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
+                       connman_technology_tethering_notify(info->technology, 
false);
+                       g_free(info->wifi->tethering_param->ssid);
+                       g_free(info->wifi->tethering_param);
+                       info->wifi->tethering_param = NULL;
+
+               }
 
                g_free(info->ifname);
                g_free(info->ssid);
@@ -2959,12 +3024,18 @@ static void sta_remove_callback(int result,
 
        DBG("ifname %s result %d ", info->ifname, result);
 
-       if (result < 0) {
+       if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
                info->wifi->tethering = true;
 
                g_free(info->ifname);
                g_free(info->ssid);
                g_free(info);
+
+               if (info->wifi->ap_supported == WIFI_AP_SUPPORTED){
+                       g_free(info->wifi->tethering_param->ssid);
+                       g_free(info->wifi->tethering_param);
+                       info->wifi->tethering_param = NULL;
+               }
                return;
        }
 
@@ -3017,10 +3088,14 @@ static int tech_set_tethering(struct connman_technology 
*technology,
                if (!interface)
                        continue;
 
+               if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
+                       continue;
+
                ifname = g_supplicant_interface_get_ifname(wifi->interface);
 
                mode = g_supplicant_interface_get_mode(interface);
                if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
+                       wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
                        DBG("%s does not support AP mode", ifname);
                        continue;
                }
@@ -3029,22 +3104,44 @@ static int tech_set_tethering(struct connman_technology 
*technology,
                if (!info)
                        return -ENOMEM;
 
+               wifi->tethering_param = g_try_malloc0(sizeof(struct 
wifi_tethering_info));
+               if (!wifi->tethering_param) {
+                       g_free(info);
+                       return -ENOMEM;
+               }
+
                info->wifi = wifi;
                info->technology = technology;
                info->wifi->bridge = bridge;
                info->ssid = ssid_ap_init(identifier, passphrase);
                if (!info->ssid) {
                        g_free(info);
+                       g_free(wifi->tethering_param);
+                       wifi->tethering_param = NULL;
                        continue;
                }
                info->ifname = g_strdup(ifname);
                if (!info->ifname) {
                        g_free(info->ssid);
+                       g_free(wifi->tethering_param);
+                       g_free(info);
+                       wifi->tethering_param = NULL;
+                       continue;
+               }
+
+               wifi->tethering_param->technology = technology;
+               wifi->tethering_param->ssid = ssid_ap_init(identifier, 
passphrase);
+               if (!wifi->tethering_param->ssid) {
+                       g_free(info->ifname);
+                       g_free(info->ssid);
+                       g_free(wifi->tethering_param);
                        g_free(info);
+                       wifi->tethering_param = NULL;
                        continue;
                }
 
                info->wifi->tethering = true;
+               info->wifi->ap_supported = WIFI_AP_SUPPORTED;
 
                err = g_supplicant_interface_remove(interface,
                                                sta_remove_callback,
-- 
1.7.11.7

_______________________________________________
connman mailing list
[email protected]
https://lists.connman.net/mailman/listinfo/connman

Reply via email to