Apply Upstream code (2021-03-15)
[platform/upstream/connectedhomeip.git] / src / platform / Linux / ConnectivityManagerImpl.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    Copyright (c) 2019 Nest Labs, Inc.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 #include <platform/internal/CHIPDeviceLayerInternal.h>
20
21 #include <platform/ConnectivityManager.h>
22 #include <platform/internal/BLEManager.h>
23
24 #include <cstdlib>
25 #include <new>
26
27 #include <support/CodeUtils.h>
28 #include <support/logging/CHIPLogging.h>
29
30 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
31 #include <platform/internal/GenericConnectivityManagerImpl_BLE.cpp>
32 #endif
33
34 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
35 #include <platform/internal/GenericConnectivityManagerImpl_Thread.cpp>
36 #endif
37
38 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
39 #include <platform/internal/GenericConnectivityManagerImpl_WiFi.cpp>
40 #endif
41
42 using namespace ::chip;
43 using namespace ::chip::TLV;
44 using namespace ::chip::DeviceLayer::Internal;
45
46 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
47 namespace {
48 const char kWpaSupplicantServiceName[] = "fi.w1.wpa_supplicant1";
49 const char kWpaSupplicantObjectPath[]  = "/fi/w1/wpa_supplicant1";
50
51 constexpr uint16_t kWiFi_BAND_2_4_GHZ = 2400;
52 constexpr uint16_t kWiFi_BAND_5_0_GHZ = 5000;
53
54 uint16_t Map2400MHz(const uint8_t inChannel)
55 {
56     uint16_t frequency = 0;
57
58     if (inChannel >= 1 && inChannel <= 13)
59     {
60         frequency = static_cast<uint16_t>(2412 + ((inChannel - 1) * 5));
61     }
62     else if (inChannel == 14)
63     {
64         frequency = 2484;
65     }
66
67     return frequency;
68 }
69
70 uint16_t Map5000MHz(const uint8_t inChannel)
71 {
72     uint16_t frequency = 0;
73
74     switch (inChannel)
75     {
76
77     case 183:
78         frequency = 4915;
79         break;
80     case 184:
81         frequency = 4920;
82         break;
83     case 185:
84         frequency = 4925;
85         break;
86     case 187:
87         frequency = 4935;
88         break;
89     case 188:
90         frequency = 4940;
91         break;
92     case 189:
93         frequency = 4945;
94         break;
95     case 192:
96         frequency = 4960;
97         break;
98     case 196:
99         frequency = 4980;
100         break;
101     case 7:
102         frequency = 5035;
103         break;
104     case 8:
105         frequency = 5040;
106         break;
107     case 9:
108         frequency = 5045;
109         break;
110     case 11:
111         frequency = 5055;
112         break;
113     case 12:
114         frequency = 5060;
115         break;
116     case 16:
117         frequency = 5080;
118         break;
119     case 34:
120         frequency = 5170;
121         break;
122     case 36:
123         frequency = 5180;
124         break;
125     case 38:
126         frequency = 5190;
127         break;
128     case 40:
129         frequency = 5200;
130         break;
131     case 42:
132         frequency = 5210;
133         break;
134     case 44:
135         frequency = 5220;
136         break;
137     case 46:
138         frequency = 5230;
139         break;
140     case 48:
141         frequency = 5240;
142         break;
143     case 52:
144         frequency = 5260;
145         break;
146     case 56:
147         frequency = 5280;
148         break;
149     case 60:
150         frequency = 5300;
151         break;
152     case 64:
153         frequency = 5320;
154         break;
155     case 100:
156         frequency = 5500;
157         break;
158     case 104:
159         frequency = 5520;
160         break;
161     case 108:
162         frequency = 5540;
163         break;
164     case 112:
165         frequency = 5560;
166         break;
167     case 116:
168         frequency = 5580;
169         break;
170     case 120:
171         frequency = 5600;
172         break;
173     case 124:
174         frequency = 5620;
175         break;
176     case 128:
177         frequency = 5640;
178         break;
179     case 132:
180         frequency = 5660;
181         break;
182     case 136:
183         frequency = 5680;
184         break;
185     case 140:
186         frequency = 5700;
187         break;
188     case 149:
189         frequency = 5745;
190         break;
191     case 153:
192         frequency = 5765;
193         break;
194     case 157:
195         frequency = 5785;
196         break;
197     case 161:
198         frequency = 5805;
199         break;
200     case 165:
201         frequency = 5825;
202         break;
203     }
204
205     return frequency;
206 }
207
208 static uint16_t MapFrequency(const uint16_t inBand, const uint8_t inChannel)
209 {
210     uint16_t frequency = 0;
211
212     if (inBand == kWiFi_BAND_2_4_GHZ)
213     {
214         frequency = Map2400MHz(inChannel);
215     }
216     else if (inBand == kWiFi_BAND_5_0_GHZ)
217     {
218         frequency = Map5000MHz(inChannel);
219     }
220
221     return frequency;
222 }
223 } // namespace
224 #endif
225
226 namespace chip {
227 namespace DeviceLayer {
228
229 ConnectivityManagerImpl ConnectivityManagerImpl::sInstance;
230
231 CHIP_ERROR ConnectivityManagerImpl::_Init()
232 {
233     CHIP_ERROR err = CHIP_NO_ERROR;
234
235     mWiFiStationMode                = kWiFiStationMode_Disabled;
236     mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL;
237
238     // Initialize the generic base classes that require it.
239 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
240     GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_Init();
241 #endif
242
243     SuccessOrExit(err);
244
245 exit:
246     return err;
247 }
248
249 void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
250 {
251     // Forward the event to the generic base classes as needed.
252 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
253     GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_OnPlatformEvent(event);
254 #endif
255 }
256
257 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
258
259 BitFlags<Internal::GenericConnectivityManagerImpl_WiFi<ConnectivityManagerImpl>::ConnectivityFlags>
260     ConnectivityManagerImpl::mConnectivityFlag;
261 struct GDBusWpaSupplicant ConnectivityManagerImpl::mWpaSupplicant;
262
263 bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity()
264 {
265     return mConnectivityFlag.Has(ConnectivityFlags::kHaveIPv4InternetConnectivity);
266 }
267
268 bool ConnectivityManagerImpl::_HaveIPv6InternetConnectivity()
269 {
270     return mConnectivityFlag.Has(ConnectivityFlags::kHaveIPv6InternetConnectivity);
271 }
272
273 ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode()
274 {
275     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
276     {
277         mWiFiStationMode = (mWpaSupplicant.iface != nullptr) ? kWiFiStationMode_Enabled : kWiFiStationMode_Disabled;
278     }
279
280     return mWiFiStationMode;
281 }
282
283 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode val)
284 {
285     CHIP_ERROR err = CHIP_NO_ERROR;
286
287     VerifyOrExit(val != ConnectivityManager::kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
288
289     if (mWiFiStationMode != val)
290     {
291         ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode),
292                         WiFiStationModeToStr(val));
293     }
294
295     mWiFiStationMode = val;
296 exit:
297     return err;
298 }
299
300 uint32_t ConnectivityManagerImpl::_GetWiFiStationReconnectIntervalMS()
301 {
302     return mWiFiStationReconnectIntervalMS;
303 }
304
305 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationReconnectIntervalMS(uint32_t val)
306 {
307     mWiFiStationReconnectIntervalMS = val;
308
309     return CHIP_NO_ERROR;
310 }
311
312 bool ConnectivityManagerImpl::_IsWiFiStationEnabled()
313 {
314     return GetWiFiStationMode() == kWiFiStationMode_Enabled;
315 }
316
317 bool ConnectivityManagerImpl::_IsWiFiStationConnected()
318 {
319     bool ret            = false;
320     const gchar * state = nullptr;
321
322     if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
323     {
324         ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationConnected: interface not connected");
325         return false;
326     }
327
328     state = wpa_fi_w1_wpa_supplicant1_interface_get_state(mWpaSupplicant.iface);
329     if (g_strcmp0(state, "completed") == 0)
330     {
331         mConnectivityFlag.Set(ConnectivityFlags::kHaveIPv4InternetConnectivity)
332             .Set(ConnectivityFlags::kHaveIPv6InternetConnectivity);
333         ret = true;
334     }
335
336     return ret;
337 }
338
339 bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled()
340 {
341     return mWiFiStationMode == ConnectivityManager::kWiFiStationMode_ApplicationControlled;
342 }
343
344 bool ConnectivityManagerImpl::_IsWiFiStationProvisioned()
345 {
346     bool ret          = false;
347     const gchar * bss = nullptr;
348
349     if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
350     {
351         ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationProvisioned: interface not connected");
352         return false;
353     }
354
355     bss = wpa_fi_w1_wpa_supplicant1_interface_get_current_bss(mWpaSupplicant.iface);
356     if (g_str_match_string("BSSs", bss, true))
357     {
358         ret = true;
359     }
360
361     return ret;
362 }
363
364 void ConnectivityManagerImpl::_ClearWiFiStationProvision()
365 {
366     if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
367     {
368         ChipLogProgress(DeviceLayer, "wpa_supplicant: _ClearWiFiStationProvision: interface not connected");
369         return;
370     }
371
372     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
373     {
374         GError * err = nullptr;
375         wpa_fi_w1_wpa_supplicant1_interface_call_remove_all_networks_sync(mWpaSupplicant.iface, nullptr, &err);
376
377         if (err != nullptr)
378         {
379             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to remove all networks with error: %s",
380                             err ? err->message : "unknown error");
381             g_error_free(err);
382         }
383     }
384 }
385
386 bool ConnectivityManagerImpl::_CanStartWiFiScan()
387 {
388     return mWpaSupplicant.state == GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED &&
389         mWpaSupplicant.scanState == GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
390 }
391
392 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val)
393 {
394     CHIP_ERROR err = CHIP_NO_ERROR;
395
396     VerifyOrExit(val != kWiFiAPMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
397
398     if (mWiFiAPMode != val)
399     {
400         ChipLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val));
401         mWiFiAPMode = val;
402
403         SystemLayer.ScheduleWork(DriveAPState, NULL);
404     }
405
406 exit:
407     return err;
408 }
409
410 void ConnectivityManagerImpl::_DemandStartWiFiAP()
411 {
412     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
413     {
414         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP");
415         mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
416         SystemLayer.ScheduleWork(DriveAPState, NULL);
417     }
418     else
419     {
420         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode));
421     }
422 }
423
424 void ConnectivityManagerImpl::_StopOnDemandWiFiAP()
425 {
426     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
427     {
428         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP");
429         mLastAPDemandTime = 0;
430         SystemLayer.ScheduleWork(DriveAPState, NULL);
431     }
432     else
433     {
434         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode));
435     }
436 }
437
438 void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP()
439 {
440     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
441     {
442         if (mWiFiAPState == kWiFiAPState_Active)
443         {
444             mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
445         }
446     }
447 }
448
449 void ConnectivityManagerImpl::_SetWiFiAPIdleTimeoutMS(uint32_t val)
450 {
451     mWiFiAPIdleTimeoutMS = val;
452     SystemLayer.ScheduleWork(DriveAPState, NULL);
453 }
454
455 void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
456 {
457     GError * err                            = nullptr;
458     WpaFiW1Wpa_supplicant1Interface * iface = wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus_finish(res, &err);
459
460     if (mWpaSupplicant.iface)
461     {
462         g_object_unref(mWpaSupplicant.iface);
463         mWpaSupplicant.iface = nullptr;
464     }
465
466     if (iface != nullptr && err == nullptr)
467     {
468         mWpaSupplicant.iface = iface;
469         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED;
470         ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant interface proxy");
471     }
472     else
473     {
474         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant1 interface proxy %s: %s",
475                         mWpaSupplicant.interfacePath, err ? err->message : "unknown error");
476
477         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
478     }
479
480     if (err != nullptr)
481         g_error_free(err);
482 }
483
484 void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
485 {
486     GError * err = nullptr;
487
488     gboolean result =
489         wpa_fi_w1_wpa_supplicant1_call_get_interface_finish(mWpaSupplicant.proxy, &mWpaSupplicant.interfacePath, res, &err);
490     if (result)
491     {
492         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
493         ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);
494
495         wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
496                                                               mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady,
497                                                               nullptr);
498     }
499     else
500     {
501         GError * error  = nullptr;
502         GVariant * args = nullptr;
503         GVariantBuilder builder;
504
505         ChipLogProgress(DeviceLayer, "wpa_supplicant: can't find interface %s: %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME,
506                         err ? err->message : "unknown error");
507
508         ChipLogProgress(DeviceLayer, "wpa_supplicant: try to create interface %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
509
510         g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
511         g_variant_builder_add(&builder, "{sv}", "Ifname", g_variant_new_string(CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME));
512         args = g_variant_builder_end(&builder);
513
514         result = wpa_fi_w1_wpa_supplicant1_call_create_interface_sync(mWpaSupplicant.proxy, args, &mWpaSupplicant.interfacePath,
515                                                                       nullptr, &error);
516
517         if (result)
518         {
519             mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
520             ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);
521
522             wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
523                                                                   kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr,
524                                                                   _OnWpaInterfaceProxyReady, nullptr);
525         }
526         else
527         {
528             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create interface %s: %s",
529                             CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, error ? error->message : "unknown error");
530
531             mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;
532
533             if (mWpaSupplicant.interfacePath)
534             {
535                 g_free(mWpaSupplicant.interfacePath);
536                 mWpaSupplicant.interfacePath = nullptr;
537             }
538         }
539
540         if (error != nullptr)
541             g_error_free(error);
542     }
543
544     if (err != nullptr)
545         g_error_free(err);
546 }
547
548 void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
549                                                    gpointer user_data)
550 {
551     if (mWpaSupplicant.interfacePath)
552         return;
553
554     mWpaSupplicant.interfacePath = const_cast<gchar *>(path);
555     if (mWpaSupplicant.interfacePath)
556     {
557         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
558         ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface added: %s", mWpaSupplicant.interfacePath);
559
560         wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
561                                                               mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady,
562                                                               nullptr);
563     }
564 }
565
566 void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
567                                                      gpointer user_data)
568 {
569     if (mWpaSupplicant.interfacePath == nullptr)
570         return;
571
572     if (g_strcmp0(mWpaSupplicant.interfacePath, path) == 0)
573     {
574         ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface removed: %s", path);
575
576         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;
577
578         if (mWpaSupplicant.interfacePath)
579         {
580             g_free(mWpaSupplicant.interfacePath);
581             mWpaSupplicant.interfacePath = nullptr;
582         }
583
584         if (mWpaSupplicant.iface)
585         {
586             g_object_unref(mWpaSupplicant.iface);
587             mWpaSupplicant.iface = nullptr;
588         }
589
590         mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
591     }
592 }
593
594 void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
595 {
596     GError * err = nullptr;
597
598     mWpaSupplicant.proxy = wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus_finish(res, &err);
599     if (mWpaSupplicant.proxy != nullptr && err == nullptr)
600     {
601         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_CONNECTED;
602         ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant proxy");
603
604         g_signal_connect(mWpaSupplicant.proxy, "interface-added", G_CALLBACK(_OnWpaInterfaceAdded), NULL);
605
606         g_signal_connect(mWpaSupplicant.proxy, "interface-removed", G_CALLBACK(_OnWpaInterfaceRemoved), NULL);
607
608         wpa_fi_w1_wpa_supplicant1_call_get_interface(mWpaSupplicant.proxy, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, nullptr,
609                                                      _OnWpaInterfaceReady, nullptr);
610     }
611     else
612     {
613         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant proxy %s",
614                         err ? err->message : "unknown error");
615         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
616     }
617
618     if (err != nullptr)
619         g_error_free(err);
620 }
621
622 void ConnectivityManagerImpl::StartWiFiManagement()
623 {
624     mConnectivityFlag.ClearAll();
625     mWpaSupplicant.state         = GDBusWpaSupplicant::INIT;
626     mWpaSupplicant.scanState     = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
627     mWpaSupplicant.proxy         = nullptr;
628     mWpaSupplicant.iface         = nullptr;
629     mWpaSupplicant.interfacePath = nullptr;
630     mWpaSupplicant.networkPath   = nullptr;
631
632     wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
633                                                 kWpaSupplicantObjectPath, nullptr, _OnWpaProxyReady, nullptr);
634 }
635
636 void ConnectivityManagerImpl::DriveAPState()
637 {
638     CHIP_ERROR err = CHIP_NO_ERROR;
639     WiFiAPState targetState;
640     uint64_t now;
641     uint32_t apTimeout;
642
643     // If the AP interface is not under application control...
644     if (mWiFiAPMode != kWiFiAPMode_ApplicationControlled)
645     {
646         // Determine the target (desired) state for AP interface...
647
648         // The target state is 'NotActive' if the application has expressly disabled the AP interface.
649         if (mWiFiAPMode == kWiFiAPMode_Disabled)
650         {
651             targetState = kWiFiAPState_NotActive;
652         }
653
654         // The target state is 'Active' if the application has expressly enabled the AP interface.
655         else if (mWiFiAPMode == kWiFiAPMode_Enabled)
656         {
657             targetState = kWiFiAPState_Active;
658         }
659
660         // The target state is 'Active' if the AP mode is 'On demand, when no station is available'
661         // and the station interface is not provisioned or the application has disabled the station
662         // interface.
663         else if (mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision &&
664                  (!IsWiFiStationProvisioned() || GetWiFiStationMode() == kWiFiStationMode_Disabled))
665         {
666             targetState = kWiFiAPState_Active;
667         }
668
669         // The target state is 'Active' if the AP mode is one of the 'On demand' modes and there
670         // has been demand for the AP within the idle timeout period.
671         else if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
672         {
673             now = System::Layer::GetClock_MonotonicMS();
674
675             if (mLastAPDemandTime != 0 && now < (mLastAPDemandTime + mWiFiAPIdleTimeoutMS))
676             {
677                 targetState = kWiFiAPState_Active;
678
679                 // Compute the amount of idle time before the AP should be deactivated and
680                 // arm a timer to fire at that time.
681                 apTimeout = (uint32_t)((mLastAPDemandTime + mWiFiAPIdleTimeoutMS) - now);
682                 err       = SystemLayer.StartTimer(apTimeout, DriveAPState, NULL);
683                 SuccessOrExit(err);
684                 ChipLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " s", apTimeout / 1000);
685             }
686             else
687             {
688                 targetState = kWiFiAPState_NotActive;
689             }
690         }
691
692         // Otherwise the target state is 'NotActive'.
693         else
694         {
695             targetState = kWiFiAPState_NotActive;
696         }
697
698         // If the current AP state does not match the target state...
699         if (mWiFiAPState != targetState)
700         {
701             if (targetState == kWiFiAPState_Active)
702             {
703                 err = ConfigureWiFiAP();
704                 SuccessOrExit(err);
705
706                 ChangeWiFiAPState(kWiFiAPState_Active);
707             }
708             else
709             {
710                 if (mWpaSupplicant.networkPath)
711                 {
712                     GError * error = nullptr;
713
714                     gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(
715                         mWpaSupplicant.iface, mWpaSupplicant.networkPath, nullptr, &error);
716
717                     if (result)
718                     {
719                         ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath);
720                         g_free(mWpaSupplicant.networkPath);
721                         mWpaSupplicant.networkPath = nullptr;
722                         ChangeWiFiAPState(kWiFiAPState_NotActive);
723                     }
724                     else
725                     {
726                         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s",
727                                         error ? error->message : "unknown error");
728                         err = CHIP_ERROR_INTERNAL;
729                     }
730
731                     if (error != nullptr)
732                         g_error_free(error);
733                 }
734             }
735         }
736     }
737
738 exit:
739     if (err != CHIP_NO_ERROR)
740     {
741         SetWiFiAPMode(kWiFiAPMode_Disabled);
742         ChipLogError(DeviceLayer, "Drive AP state failed: %s", ErrorStr(err));
743     }
744 }
745
746 CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP()
747 {
748     CHIP_ERROR ret  = CHIP_NO_ERROR;
749     GError * err    = nullptr;
750     GVariant * args = nullptr;
751     GVariantBuilder builder;
752
753     uint16_t channel       = 1;
754     uint16_t discriminator = 0;
755     char ssid[32];
756
757     channel = MapFrequency(kWiFi_BAND_2_4_GHZ, CHIP_DEVICE_CONFIG_WIFI_AP_CHANNEL);
758
759     if (ConfigurationMgr().GetSetupDiscriminator(discriminator) != CHIP_NO_ERROR)
760         discriminator = 0;
761
762     snprintf(ssid, 32, "%s%04u", CHIP_DEVICE_CONFIG_WIFI_AP_SSID_PREFIX, discriminator);
763
764     ChipLogProgress(DeviceLayer, "wpa_supplicant: ConfigureWiFiAP, ssid: %s, channel: %d", ssid, channel);
765
766     // Clean up current network if exists
767     if (mWpaSupplicant.networkPath)
768     {
769         g_object_unref(mWpaSupplicant.networkPath);
770         mWpaSupplicant.networkPath = nullptr;
771     }
772
773     g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
774     g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid));
775     g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("NONE"));
776     g_variant_builder_add(&builder, "{sv}", "mode", g_variant_new_int32(2));
777     g_variant_builder_add(&builder, "{sv}", "frequency", g_variant_new_int32(channel));
778     args = g_variant_builder_end(&builder);
779
780     gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args,
781                                                                                 &mWpaSupplicant.networkPath, nullptr, &err);
782
783     if (result)
784     {
785         GError * error = nullptr;
786
787         ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath);
788
789         result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
790                                                                               nullptr, &error);
791         if (result)
792         {
793             ChipLogProgress(DeviceLayer, "wpa_supplicant: succeeded to start softAP: SSID: %s", ssid);
794         }
795         else
796         {
797             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to start softAP: SSID: %s: %s", ssid,
798                             error ? error->message : "unknown error");
799
800             ret = CHIP_ERROR_INTERNAL;
801         }
802
803         if (error != nullptr)
804             g_error_free(error);
805     }
806     else
807     {
808         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error");
809
810         if (mWpaSupplicant.networkPath)
811         {
812             g_object_unref(mWpaSupplicant.networkPath);
813             mWpaSupplicant.networkPath = nullptr;
814         }
815
816         ret = CHIP_ERROR_INTERNAL;
817     }
818
819     if (err != nullptr)
820         g_error_free(err);
821
822     return ret;
823 }
824
825 void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState)
826 {
827     if (mWiFiAPState != newState)
828     {
829         ChipLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState));
830         mWiFiAPState = newState;
831     }
832 }
833
834 void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState, ::chip::System::Error aError)
835 {
836     sInstance.DriveAPState();
837 }
838 #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
839
840 CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, const char * key)
841 {
842 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
843     CHIP_ERROR ret  = CHIP_NO_ERROR;
844     GError * err    = nullptr;
845     GVariant * args = nullptr;
846     GVariantBuilder builder;
847     gboolean result;
848
849     // Clean up current network if exists
850     if (mWpaSupplicant.networkPath)
851     {
852         GError * error = nullptr;
853
854         result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
855                                                                               nullptr, &error);
856
857         if (result)
858         {
859             ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath);
860             g_free(mWpaSupplicant.networkPath);
861             mWpaSupplicant.networkPath = nullptr;
862         }
863         else
864         {
865             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s",
866                             error ? error->message : "unknown error");
867             ret = CHIP_ERROR_INTERNAL;
868         }
869
870         if (error != nullptr)
871             g_error_free(error);
872
873         SuccessOrExit(ret);
874     }
875
876     g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
877     g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid));
878     g_variant_builder_add(&builder, "{sv}", "psk", g_variant_new_string(key));
879     g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("WPA-PSK"));
880     args = g_variant_builder_end(&builder);
881
882     result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args, &mWpaSupplicant.networkPath,
883                                                                        nullptr, &err);
884
885     if (result)
886     {
887         GError * error = nullptr;
888
889         ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath);
890
891         result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
892                                                                               nullptr, &error);
893         if (result)
894         {
895             GError * gerror = nullptr;
896
897             ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to network: SSID: %s", ssid);
898
899             result = wpa_fi_w1_wpa_supplicant1_interface_call_save_config_sync(mWpaSupplicant.iface, nullptr, &gerror);
900
901             if (result)
902             {
903                 ChipLogProgress(DeviceLayer, "wpa_supplicant: save config succeeded!");
904             }
905             else
906             {
907                 ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to save config: %s",
908                                 gerror ? gerror->message : "unknown error");
909             }
910
911             if (gerror != nullptr)
912                 g_error_free(gerror);
913
914             // Iterate on the network interface to see if we already have beed assigned addresses.
915             // The temporary hack for getting IP address change on linux for network provisioning in the rendezvous session.
916             // This should be removed or find a better place once we depercate the rendezvous session.
917             for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next())
918             {
919                 char ifName[chip::Inet::InterfaceIterator::kMaxIfNameLength];
920                 if (it.IsUp() && CHIP_NO_ERROR == it.GetInterfaceName(ifName, sizeof(ifName)) &&
921                     strncmp(ifName, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, sizeof(ifName)) == 0)
922                 {
923                     chip::Inet::IPAddress addr = it.GetAddress();
924                     if (addr.IsIPv4())
925                     {
926                         ChipDeviceEvent event;
927                         event.Type                            = DeviceEventType::kInternetConnectivityChange;
928                         event.InternetConnectivityChange.IPv4 = kConnectivity_Established;
929                         event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange;
930                         addr.ToString(event.InternetConnectivityChange.address);
931
932                         ChipLogDetail(DeviceLayer, "Got IP address on interface: %s IP: %s", ifName,
933                                       event.InternetConnectivityChange.address);
934
935                         PlatformMgr().PostEvent(&event);
936                     }
937                 }
938             }
939
940             // Run dhclient for IP on WiFi.
941             // TODO: The wifi can be managed by networkmanager on linux so we don't have to care about this.
942             char cmdBuffer[128];
943             sprintf(cmdBuffer, "dhclient -nw %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
944             int dhclientSystemRet = system(cmdBuffer);
945             if (dhclientSystemRet != 0)
946             {
947                 ChipLogError(DeviceLayer, "Failed to run dhclient, system() returns %d", dhclientSystemRet);
948             }
949             else
950             {
951                 ChipLogProgress(DeviceLayer, "dhclient is running on the %s interface.", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
952             }
953
954             // Return success as long as the device is connected to the network
955             ret = CHIP_NO_ERROR;
956         }
957         else
958         {
959             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to connect to network: SSID: %s: %s", ssid,
960                             error ? error->message : "unknown error");
961
962             ret = CHIP_ERROR_INTERNAL;
963         }
964
965         if (error != nullptr)
966             g_error_free(error);
967     }
968     else
969     {
970         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error");
971
972         if (mWpaSupplicant.networkPath)
973         {
974             g_object_unref(mWpaSupplicant.networkPath);
975             mWpaSupplicant.networkPath = nullptr;
976         }
977
978         ret = CHIP_ERROR_INTERNAL;
979     }
980
981 exit:
982     if (err != nullptr)
983         g_error_free(err);
984
985     return ret;
986 #else
987     return CHIP_ERROR_NOT_IMPLEMENTED;
988 #endif
989 }
990
991 } // namespace DeviceLayer
992 } // namespace chip