8426e65380f5d56e4541ac9a282e7c7037bdfaf3
[platform/upstream/connectedhomeip.git] / src / platform / Linux / ConnectivityManagerImpl.cpp
1 /*
2  *
3  *    Copyright (c) 2020 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 uint16_t ConnectivityManagerImpl::mConnectivityFlag;
260 struct GDBusWpaSupplicant ConnectivityManagerImpl::mWpaSupplicant;
261
262 bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity()
263 {
264     return ((mConnectivityFlag & kFlag_HaveIPv4InternetConnectivity) != 0);
265 }
266
267 bool ConnectivityManagerImpl::_HaveIPv6InternetConnectivity()
268 {
269     return ((mConnectivityFlag & kFlag_HaveIPv6InternetConnectivity) != 0);
270 }
271
272 ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode()
273 {
274     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
275     {
276         mWiFiStationMode = (mWpaSupplicant.iface != nullptr) ? kWiFiStationMode_Enabled : kWiFiStationMode_Disabled;
277     }
278
279     return mWiFiStationMode;
280 }
281
282 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode val)
283 {
284     CHIP_ERROR err = CHIP_NO_ERROR;
285
286     VerifyOrExit(val != ConnectivityManager::kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
287
288     if (mWiFiStationMode != val)
289     {
290         ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode),
291                         WiFiStationModeToStr(val));
292     }
293
294     mWiFiStationMode = val;
295 exit:
296     return err;
297 }
298
299 uint32_t ConnectivityManagerImpl::_GetWiFiStationReconnectIntervalMS()
300 {
301     return mWiFiStationReconnectIntervalMS;
302 }
303
304 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationReconnectIntervalMS(uint32_t val)
305 {
306     mWiFiStationReconnectIntervalMS = val;
307
308     return CHIP_NO_ERROR;
309 }
310
311 bool ConnectivityManagerImpl::_IsWiFiStationEnabled()
312 {
313     return GetWiFiStationMode() == kWiFiStationMode_Enabled;
314 }
315
316 bool ConnectivityManagerImpl::_IsWiFiStationConnected()
317 {
318     bool ret            = false;
319     const gchar * state = nullptr;
320
321     if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
322     {
323         ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationConnected: interface not connected");
324         return false;
325     }
326
327     state = wpa_fi_w1_wpa_supplicant1_interface_get_state(mWpaSupplicant.iface);
328     if (g_strcmp0(state, "completed") == 0)
329     {
330         SetFlag(mConnectivityFlag, kFlag_HaveIPv4InternetConnectivity, true);
331         SetFlag(mConnectivityFlag, kFlag_HaveIPv6InternetConnectivity, true);
332         ret = true;
333     }
334
335     return ret;
336 }
337
338 bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled()
339 {
340     return mWiFiStationMode == ConnectivityManager::kWiFiStationMode_ApplicationControlled;
341 }
342
343 bool ConnectivityManagerImpl::_IsWiFiStationProvisioned()
344 {
345     bool ret          = false;
346     const gchar * bss = nullptr;
347
348     if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
349     {
350         ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationProvisioned: interface not connected");
351         return false;
352     }
353
354     bss = wpa_fi_w1_wpa_supplicant1_interface_get_current_bss(mWpaSupplicant.iface);
355     if (g_str_match_string("BSSs", bss, true))
356     {
357         ret = true;
358     }
359
360     return ret;
361 }
362
363 void ConnectivityManagerImpl::_ClearWiFiStationProvision()
364 {
365     if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
366     {
367         ChipLogProgress(DeviceLayer, "wpa_supplicant: _ClearWiFiStationProvision: interface not connected");
368         return;
369     }
370
371     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
372     {
373         GError * err = nullptr;
374         wpa_fi_w1_wpa_supplicant1_interface_call_remove_all_networks_sync(mWpaSupplicant.iface, nullptr, &err);
375
376         if (err != nullptr)
377         {
378             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to remove all networks with error: %s",
379                             err ? err->message : "unknown error");
380             g_error_free(err);
381         }
382     }
383 }
384
385 bool ConnectivityManagerImpl::_CanStartWiFiScan()
386 {
387     return mWpaSupplicant.state == GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED &&
388         mWpaSupplicant.scanState == GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
389 }
390
391 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val)
392 {
393     CHIP_ERROR err = CHIP_NO_ERROR;
394
395     VerifyOrExit(val != kWiFiAPMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
396
397     if (mWiFiAPMode != val)
398     {
399         ChipLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val));
400         mWiFiAPMode = val;
401
402         SystemLayer.ScheduleWork(DriveAPState, NULL);
403     }
404
405 exit:
406     return err;
407 }
408
409 void ConnectivityManagerImpl::_DemandStartWiFiAP()
410 {
411     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
412     {
413         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP");
414         mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
415         SystemLayer.ScheduleWork(DriveAPState, NULL);
416     }
417     else
418     {
419         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode));
420     }
421 }
422
423 void ConnectivityManagerImpl::_StopOnDemandWiFiAP()
424 {
425     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
426     {
427         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP");
428         mLastAPDemandTime = 0;
429         SystemLayer.ScheduleWork(DriveAPState, NULL);
430     }
431     else
432     {
433         ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode));
434     }
435 }
436
437 void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP()
438 {
439     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
440     {
441         if (mWiFiAPState == kWiFiAPState_Active)
442         {
443             mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
444         }
445     }
446 }
447
448 void ConnectivityManagerImpl::_SetWiFiAPIdleTimeoutMS(uint32_t val)
449 {
450     mWiFiAPIdleTimeoutMS = val;
451     SystemLayer.ScheduleWork(DriveAPState, NULL);
452 }
453
454 void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
455 {
456     GError * err                            = nullptr;
457     WpaFiW1Wpa_supplicant1Interface * iface = wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus_finish(res, &err);
458
459     if (mWpaSupplicant.iface)
460     {
461         g_object_unref(mWpaSupplicant.iface);
462         mWpaSupplicant.iface = nullptr;
463     }
464
465     if (iface != nullptr && err == nullptr)
466     {
467         mWpaSupplicant.iface = iface;
468         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED;
469         ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant interface proxy");
470     }
471     else
472     {
473         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant1 interface proxy %s: %s",
474                         mWpaSupplicant.interfacePath, err ? err->message : "unknown error");
475
476         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
477     }
478
479     if (err != nullptr)
480         g_error_free(err);
481 }
482
483 void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
484 {
485     GError * err = nullptr;
486
487     gboolean result =
488         wpa_fi_w1_wpa_supplicant1_call_get_interface_finish(mWpaSupplicant.proxy, &mWpaSupplicant.interfacePath, res, &err);
489     if (result)
490     {
491         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
492         ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);
493
494         wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
495                                                               mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady,
496                                                               nullptr);
497     }
498     else
499     {
500         GError * error  = nullptr;
501         GVariant * args = nullptr;
502         GVariantBuilder builder;
503
504         ChipLogProgress(DeviceLayer, "wpa_supplicant: can't find interface %s: %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME,
505                         err ? err->message : "unknown error");
506
507         ChipLogProgress(DeviceLayer, "wpa_supplicant: try to create interface %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
508
509         g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
510         g_variant_builder_add(&builder, "{sv}", "Ifname", g_variant_new_string(CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME));
511         args = g_variant_builder_end(&builder);
512
513         result = wpa_fi_w1_wpa_supplicant1_call_create_interface_sync(mWpaSupplicant.proxy, args, &mWpaSupplicant.interfacePath,
514                                                                       nullptr, &error);
515
516         if (result)
517         {
518             mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
519             ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);
520
521             wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
522                                                                   kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr,
523                                                                   _OnWpaInterfaceProxyReady, nullptr);
524         }
525         else
526         {
527             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create interface %s: %s",
528                             CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, error ? error->message : "unknown error");
529
530             mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;
531
532             if (mWpaSupplicant.interfacePath)
533             {
534                 g_free(mWpaSupplicant.interfacePath);
535                 mWpaSupplicant.interfacePath = nullptr;
536             }
537         }
538
539         if (error != nullptr)
540             g_error_free(error);
541     }
542
543     if (err != nullptr)
544         g_error_free(err);
545 }
546
547 void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
548                                                    gpointer user_data)
549 {
550     if (mWpaSupplicant.interfacePath)
551         return;
552
553     mWpaSupplicant.interfacePath = const_cast<gchar *>(path);
554     if (mWpaSupplicant.interfacePath)
555     {
556         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
557         ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface added: %s", mWpaSupplicant.interfacePath);
558
559         wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
560                                                               mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady,
561                                                               nullptr);
562     }
563 }
564
565 void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
566                                                      gpointer user_data)
567 {
568     if (mWpaSupplicant.interfacePath == nullptr)
569         return;
570
571     if (g_strcmp0(mWpaSupplicant.interfacePath, path) == 0)
572     {
573         ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface removed: %s", path);
574
575         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;
576
577         if (mWpaSupplicant.interfacePath)
578         {
579             g_free(mWpaSupplicant.interfacePath);
580             mWpaSupplicant.interfacePath = nullptr;
581         }
582
583         if (mWpaSupplicant.iface)
584         {
585             g_object_unref(mWpaSupplicant.iface);
586             mWpaSupplicant.iface = nullptr;
587         }
588
589         mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
590     }
591 }
592
593 void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
594 {
595     GError * err = nullptr;
596
597     mWpaSupplicant.proxy = wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus_finish(res, &err);
598     if (mWpaSupplicant.proxy != nullptr && err == nullptr)
599     {
600         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_CONNECTED;
601         ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant proxy");
602
603         g_signal_connect(mWpaSupplicant.proxy, "interface-added", G_CALLBACK(_OnWpaInterfaceAdded), NULL);
604
605         g_signal_connect(mWpaSupplicant.proxy, "interface-removed", G_CALLBACK(_OnWpaInterfaceRemoved), NULL);
606
607         wpa_fi_w1_wpa_supplicant1_call_get_interface(mWpaSupplicant.proxy, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, nullptr,
608                                                      _OnWpaInterfaceReady, nullptr);
609     }
610     else
611     {
612         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant proxy %s",
613                         err ? err->message : "unknown error");
614         mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
615     }
616
617     if (err != nullptr)
618         g_error_free(err);
619 }
620
621 void ConnectivityManagerImpl::StartWiFiManagement()
622 {
623     mConnectivityFlag            = 0;
624     mWpaSupplicant.state         = GDBusWpaSupplicant::INIT;
625     mWpaSupplicant.scanState     = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
626     mWpaSupplicant.proxy         = nullptr;
627     mWpaSupplicant.iface         = nullptr;
628     mWpaSupplicant.interfacePath = nullptr;
629     mWpaSupplicant.networkPath   = nullptr;
630
631     wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
632                                                 kWpaSupplicantObjectPath, nullptr, _OnWpaProxyReady, nullptr);
633 }
634
635 void ConnectivityManagerImpl::DriveAPState()
636 {
637     CHIP_ERROR err = CHIP_NO_ERROR;
638     WiFiAPState targetState;
639     uint64_t now;
640     uint32_t apTimeout;
641
642     // If the AP interface is not under application control...
643     if (mWiFiAPMode != kWiFiAPMode_ApplicationControlled)
644     {
645         // Determine the target (desired) state for AP interface...
646
647         // The target state is 'NotActive' if the application has expressly disabled the AP interface.
648         if (mWiFiAPMode == kWiFiAPMode_Disabled)
649         {
650             targetState = kWiFiAPState_NotActive;
651         }
652
653         // The target state is 'Active' if the application has expressly enabled the AP interface.
654         else if (mWiFiAPMode == kWiFiAPMode_Enabled)
655         {
656             targetState = kWiFiAPState_Active;
657         }
658
659         // The target state is 'Active' if the AP mode is 'On demand, when no station is available'
660         // and the station interface is not provisioned or the application has disabled the station
661         // interface.
662         else if (mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision &&
663                  (!IsWiFiStationProvisioned() || GetWiFiStationMode() == kWiFiStationMode_Disabled))
664         {
665             targetState = kWiFiAPState_Active;
666         }
667
668         // The target state is 'Active' if the AP mode is one of the 'On demand' modes and there
669         // has been demand for the AP within the idle timeout period.
670         else if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
671         {
672             now = System::Layer::GetClock_MonotonicMS();
673
674             if (mLastAPDemandTime != 0 && now < (mLastAPDemandTime + mWiFiAPIdleTimeoutMS))
675             {
676                 targetState = kWiFiAPState_Active;
677
678                 // Compute the amount of idle time before the AP should be deactivated and
679                 // arm a timer to fire at that time.
680                 apTimeout = (uint32_t)((mLastAPDemandTime + mWiFiAPIdleTimeoutMS) - now);
681                 err       = SystemLayer.StartTimer(apTimeout, DriveAPState, NULL);
682                 SuccessOrExit(err);
683                 ChipLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " s", apTimeout / 1000);
684             }
685             else
686             {
687                 targetState = kWiFiAPState_NotActive;
688             }
689         }
690
691         // Otherwise the target state is 'NotActive'.
692         else
693         {
694             targetState = kWiFiAPState_NotActive;
695         }
696
697         // If the current AP state does not match the target state...
698         if (mWiFiAPState != targetState)
699         {
700             if (targetState == kWiFiAPState_Active)
701             {
702                 err = ConfigureWiFiAP();
703                 SuccessOrExit(err);
704
705                 ChangeWiFiAPState(kWiFiAPState_Active);
706             }
707             else
708             {
709                 if (mWpaSupplicant.networkPath)
710                 {
711                     GError * error = nullptr;
712
713                     gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(
714                         mWpaSupplicant.iface, mWpaSupplicant.networkPath, nullptr, &error);
715
716                     if (result)
717                     {
718                         ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath);
719                         g_free(mWpaSupplicant.networkPath);
720                         mWpaSupplicant.networkPath = nullptr;
721                         ChangeWiFiAPState(kWiFiAPState_NotActive);
722                     }
723                     else
724                     {
725                         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s",
726                                         error ? error->message : "unknown error");
727                         err = CHIP_ERROR_INTERNAL;
728                     }
729
730                     if (error != nullptr)
731                         g_error_free(error);
732                 }
733             }
734         }
735     }
736
737 exit:
738     if (err != CHIP_NO_ERROR)
739     {
740         SetWiFiAPMode(kWiFiAPMode_Disabled);
741         ChipLogError(DeviceLayer, "Drive AP state failed: %s", ErrorStr(err));
742     }
743 }
744
745 CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP()
746 {
747     CHIP_ERROR ret  = CHIP_NO_ERROR;
748     GError * err    = nullptr;
749     GVariant * args = nullptr;
750     GVariantBuilder builder;
751
752     uint16_t channel       = 1;
753     uint16_t discriminator = 0;
754     char ssid[32];
755
756     channel = MapFrequency(kWiFi_BAND_2_4_GHZ, CHIP_DEVICE_CONFIG_WIFI_AP_CHANNEL);
757
758     if (ConfigurationMgr().GetSetupDiscriminator(discriminator) != CHIP_NO_ERROR)
759         discriminator = 0;
760
761     snprintf(ssid, 32, "%s%04u", CHIP_DEVICE_CONFIG_WIFI_AP_SSID_PREFIX, discriminator);
762
763     ChipLogProgress(DeviceLayer, "wpa_supplicant: ConfigureWiFiAP, ssid: %s, channel: %d", ssid, channel);
764
765     // Clean up current network if exists
766     if (mWpaSupplicant.networkPath)
767     {
768         g_object_unref(mWpaSupplicant.networkPath);
769         mWpaSupplicant.networkPath = nullptr;
770     }
771
772     g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
773     g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid));
774     g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("NONE"));
775     g_variant_builder_add(&builder, "{sv}", "mode", g_variant_new_int32(2));
776     g_variant_builder_add(&builder, "{sv}", "frequency", g_variant_new_int32(channel));
777     args = g_variant_builder_end(&builder);
778
779     gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args,
780                                                                                 &mWpaSupplicant.networkPath, nullptr, &err);
781
782     if (result)
783     {
784         GError * error = nullptr;
785
786         ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath);
787
788         result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
789                                                                               nullptr, &error);
790         if (result)
791         {
792             ChipLogProgress(DeviceLayer, "wpa_supplicant: succeeded to start softAP: SSID: %s", ssid);
793         }
794         else
795         {
796             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to start softAP: SSID: %s: %s", ssid,
797                             error ? error->message : "unknown error");
798
799             ret = CHIP_ERROR_INTERNAL;
800         }
801
802         if (error != nullptr)
803             g_error_free(error);
804     }
805     else
806     {
807         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error");
808
809         if (mWpaSupplicant.networkPath)
810         {
811             g_object_unref(mWpaSupplicant.networkPath);
812             mWpaSupplicant.networkPath = nullptr;
813         }
814
815         ret = CHIP_ERROR_INTERNAL;
816     }
817
818     if (err != nullptr)
819         g_error_free(err);
820
821     return ret;
822 }
823
824 void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState)
825 {
826     if (mWiFiAPState != newState)
827     {
828         ChipLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState));
829         mWiFiAPState = newState;
830     }
831 }
832
833 void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState, ::chip::System::Error aError)
834 {
835     sInstance.DriveAPState();
836 }
837 #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
838
839 CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, const char * key)
840 {
841 #if CHIP_DEVICE_CONFIG_ENABLE_WPA
842     CHIP_ERROR ret  = CHIP_NO_ERROR;
843     GError * err    = nullptr;
844     GVariant * args = nullptr;
845     GVariantBuilder builder;
846     gboolean result;
847
848     // Clean up current network if exists
849     if (mWpaSupplicant.networkPath)
850     {
851         GError * error = nullptr;
852
853         result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
854                                                                               nullptr, &error);
855
856         if (result)
857         {
858             ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath);
859             g_free(mWpaSupplicant.networkPath);
860             mWpaSupplicant.networkPath = nullptr;
861         }
862         else
863         {
864             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s",
865                             error ? error->message : "unknown error");
866             ret = CHIP_ERROR_INTERNAL;
867         }
868
869         if (error != nullptr)
870             g_error_free(error);
871
872         SuccessOrExit(ret);
873     }
874
875     g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
876     g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid));
877     g_variant_builder_add(&builder, "{sv}", "psk", g_variant_new_string(key));
878     g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("WPA-PSK"));
879     args = g_variant_builder_end(&builder);
880
881     result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args, &mWpaSupplicant.networkPath,
882                                                                        nullptr, &err);
883
884     if (result)
885     {
886         GError * error = nullptr;
887
888         ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath);
889
890         result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
891                                                                               nullptr, &error);
892         if (result)
893         {
894             GError * gerror = nullptr;
895
896             ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to network: SSID: %s", ssid);
897
898             result = wpa_fi_w1_wpa_supplicant1_interface_call_save_config_sync(mWpaSupplicant.iface, nullptr, &gerror);
899
900             if (result)
901             {
902                 ChipLogProgress(DeviceLayer, "wpa_supplicant: save config succeeded!");
903             }
904             else
905             {
906                 ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to save config: %s",
907                                 gerror ? gerror->message : "unknown error");
908             }
909
910             if (gerror != nullptr)
911                 g_error_free(gerror);
912
913             // Iterate on the network interface to see if we already have beed assigned addresses.
914             // The temporary hack for getting IP address change on linux for network provisioning in the rendezvous session.
915             // This should be removed or find a better place once we depercate the rendezvous session.
916             for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next())
917             {
918                 char ifName[chip::Inet::InterfaceIterator::kMaxIfNameLength];
919                 if (it.IsUp() && CHIP_NO_ERROR == it.GetInterfaceName(ifName, sizeof(ifName)) &&
920                     strncmp(ifName, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, sizeof(ifName)) == 0)
921                 {
922                     chip::Inet::IPAddress addr = it.GetAddress();
923                     if (addr.IsIPv4())
924                     {
925                         ChipDeviceEvent event;
926                         event.Type                            = DeviceEventType::kInternetConnectivityChange;
927                         event.InternetConnectivityChange.IPv4 = kConnectivity_Established;
928                         event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange;
929                         addr.ToString(event.InternetConnectivityChange.address);
930
931                         ChipLogDetail(DeviceLayer, "Got IP address on interface: %s IP: %s", ifName,
932                                       event.InternetConnectivityChange.address);
933
934                         PlatformMgr().PostEvent(&event);
935                     }
936                 }
937             }
938
939             // Run dhclient for IP on WiFi.
940             // TODO: The wifi can be managed by networkmanager on linux so we don't have to care about this.
941             char cmdBuffer[128];
942             sprintf(cmdBuffer, "dhclient -nw %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
943             int dhclientSystemRet = system(cmdBuffer);
944             if (dhclientSystemRet != 0)
945             {
946                 ChipLogError(DeviceLayer, "Failed to run dhclient, system() returns %d", dhclientSystemRet);
947             }
948             else
949             {
950                 ChipLogProgress(DeviceLayer, "dhclient is running on the %s interface.", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
951             }
952
953             // Return success as long as the device is connected to the network
954             ret = CHIP_NO_ERROR;
955         }
956         else
957         {
958             ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to connect to network: SSID: %s: %s", ssid,
959                             error ? error->message : "unknown error");
960
961             ret = CHIP_ERROR_INTERNAL;
962         }
963
964         if (error != nullptr)
965             g_error_free(error);
966     }
967     else
968     {
969         ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error");
970
971         if (mWpaSupplicant.networkPath)
972         {
973             g_object_unref(mWpaSupplicant.networkPath);
974             mWpaSupplicant.networkPath = nullptr;
975         }
976
977         ret = CHIP_ERROR_INTERNAL;
978     }
979
980 exit:
981     if (err != nullptr)
982         g_error_free(err);
983
984     return ret;
985 #else
986     return CHIP_ERROR_NOT_IMPLEMENTED;
987 #endif
988 }
989
990 } // namespace DeviceLayer
991 } // namespace chip