8c0aff5c4c43eebb02722a61eb34468c4779fc80
[platform/upstream/connectedhomeip.git] / src / platform / ESP32 / ConnectivityManagerImpl.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2018 Nest Labs, Inc.
5  *    All rights reserved.
6  *
7  *    Licensed under the Apache License, Version 2.0 (the "License");
8  *    you may not use this file except in compliance with the License.
9  *    You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *    Unless required by applicable law or agreed to in writing, software
14  *    distributed under the License is distributed on an "AS IS" BASIS,
15  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *    See the License for the specific language governing permissions and
17  *    limitations under the License.
18  */
19 /* this file behaves like a config.h, comes first */
20 #include <platform/internal/CHIPDeviceLayerInternal.h>
21
22 #include <platform/ConnectivityManager.h>
23 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
24 #include <platform/internal/GenericConnectivityManagerImpl_BLE.cpp>
25 #endif
26 #include <platform/internal/GenericConnectivityManagerImpl_WiFi.cpp>
27
28 #include <platform/ESP32/ESP32Utils.h>
29 #include <platform/internal/BLEManager.h>
30 #include <support/CodeUtils.h>
31 #include <support/logging/CHIPLogging.h>
32
33 #include "esp_event.h"
34 #include "esp_netif.h"
35 #include "esp_wifi.h"
36
37 #include <lwip/dns.h>
38 #include <lwip/ip_addr.h>
39 #include <lwip/nd6.h>
40 #include <lwip/netif.h>
41
42 #include <type_traits>
43
44 #if !CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
45 #error "WiFi Station support must be enabled when building for ESP32"
46 #endif
47
48 #if !CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP
49 #error "WiFi AP support must be enabled when building for ESP32"
50 #endif
51
52 using namespace ::chip;
53 using namespace ::chip::Inet;
54 using namespace ::chip::System;
55 using namespace ::chip::TLV;
56
57 namespace chip {
58 namespace DeviceLayer {
59
60 ConnectivityManagerImpl ConnectivityManagerImpl::sInstance;
61
62 ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode(void)
63 {
64     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
65     {
66         wifi_mode_t curWiFiMode;
67         mWiFiStationMode =
68             (esp_wifi_get_mode(&curWiFiMode) == ESP_OK && (curWiFiMode == WIFI_MODE_APSTA || curWiFiMode == WIFI_MODE_STA))
69             ? kWiFiStationMode_Enabled
70             : kWiFiStationMode_Disabled;
71     }
72     return mWiFiStationMode;
73 }
74
75 bool ConnectivityManagerImpl::_IsWiFiStationEnabled(void)
76 {
77     return GetWiFiStationMode() == kWiFiStationMode_Enabled;
78 }
79
80 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(WiFiStationMode val)
81 {
82     CHIP_ERROR err = CHIP_NO_ERROR;
83
84     VerifyOrExit(val != kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
85
86     if (val != kWiFiStationMode_ApplicationControlled)
87     {
88         bool autoConnect = (val == kWiFiStationMode_Enabled);
89         err              = Internal::ESP32Utils::SetAPMode(autoConnect);
90         SuccessOrExit(err);
91
92         SystemLayer.ScheduleWork(DriveStationState, NULL);
93     }
94
95     if (mWiFiStationMode != val)
96     {
97         ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode),
98                         WiFiStationModeToStr(val));
99     }
100
101     mWiFiStationMode = val;
102
103 exit:
104     return err;
105 }
106
107 bool ConnectivityManagerImpl::_IsWiFiStationProvisioned(void)
108 {
109     return Internal::ESP32Utils::IsStationProvisioned();
110 }
111
112 void ConnectivityManagerImpl::_ClearWiFiStationProvision(void)
113 {
114     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
115     {
116         wifi_config_t stationConfig;
117
118         memset(&stationConfig, 0, sizeof(stationConfig));
119         esp_wifi_set_config(WIFI_IF_STA, &stationConfig);
120
121         SystemLayer.ScheduleWork(DriveStationState, NULL);
122         SystemLayer.ScheduleWork(DriveAPState, NULL);
123     }
124 }
125
126 CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val)
127 {
128     CHIP_ERROR err = CHIP_NO_ERROR;
129
130     VerifyOrExit(val != kWiFiAPMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
131
132     if (mWiFiAPMode != val)
133     {
134         ChipLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val));
135     }
136
137     mWiFiAPMode = val;
138
139     SystemLayer.ScheduleWork(DriveAPState, NULL);
140
141 exit:
142     return err;
143 }
144
145 void ConnectivityManagerImpl::_DemandStartWiFiAP(void)
146 {
147     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
148     {
149         mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
150         SystemLayer.ScheduleWork(DriveAPState, NULL);
151     }
152 }
153
154 void ConnectivityManagerImpl::_StopOnDemandWiFiAP(void)
155 {
156     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
157     {
158         mLastAPDemandTime = 0;
159         SystemLayer.ScheduleWork(DriveAPState, NULL);
160     }
161 }
162
163 void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP(void)
164 {
165     if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
166     {
167         if (mWiFiAPState == kWiFiAPState_Activating || mWiFiAPState == kWiFiAPState_Active)
168         {
169             mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
170         }
171     }
172 }
173
174 void ConnectivityManagerImpl::_SetWiFiAPIdleTimeoutMS(uint32_t val)
175 {
176     mWiFiAPIdleTimeoutMS = val;
177     SystemLayer.ScheduleWork(DriveAPState, NULL);
178 }
179
180 #define WIFI_BAND_2_4GHZ 2400
181 #define WIFI_BAND_5_0GHZ 5000
182
183 static uint16_t Map2400MHz(const uint8_t inChannel)
184 {
185     uint16_t frequency = 0;
186
187     if (inChannel >= 1 && inChannel <= 13)
188     {
189         // Cast is OK because we definitely fit in 16 bits.
190         frequency = static_cast<uint16_t>(2412 + ((inChannel - 1) * 5));
191     }
192     else if (inChannel == 14)
193     {
194         frequency = 2484;
195     }
196
197     return frequency;
198 }
199
200 static uint16_t Map5000MHz(const uint8_t inChannel)
201 {
202     uint16_t frequency = 0;
203
204     switch (inChannel)
205     {
206
207     case 183:
208         frequency = 4915;
209         break;
210     case 184:
211         frequency = 4920;
212         break;
213     case 185:
214         frequency = 4925;
215         break;
216     case 187:
217         frequency = 4935;
218         break;
219     case 188:
220         frequency = 4940;
221         break;
222     case 189:
223         frequency = 4945;
224         break;
225     case 192:
226         frequency = 4960;
227         break;
228     case 196:
229         frequency = 4980;
230         break;
231     case 7:
232         frequency = 5035;
233         break;
234     case 8:
235         frequency = 5040;
236         break;
237     case 9:
238         frequency = 5045;
239         break;
240     case 11:
241         frequency = 5055;
242         break;
243     case 12:
244         frequency = 5060;
245         break;
246     case 16:
247         frequency = 5080;
248         break;
249     case 34:
250         frequency = 5170;
251         break;
252     case 36:
253         frequency = 5180;
254         break;
255     case 38:
256         frequency = 5190;
257         break;
258     case 40:
259         frequency = 5200;
260         break;
261     case 42:
262         frequency = 5210;
263         break;
264     case 44:
265         frequency = 5220;
266         break;
267     case 46:
268         frequency = 5230;
269         break;
270     case 48:
271         frequency = 5240;
272         break;
273     case 52:
274         frequency = 5260;
275         break;
276     case 56:
277         frequency = 5280;
278         break;
279     case 60:
280         frequency = 5300;
281         break;
282     case 64:
283         frequency = 5320;
284         break;
285     case 100:
286         frequency = 5500;
287         break;
288     case 104:
289         frequency = 5520;
290         break;
291     case 108:
292         frequency = 5540;
293         break;
294     case 112:
295         frequency = 5560;
296         break;
297     case 116:
298         frequency = 5580;
299         break;
300     case 120:
301         frequency = 5600;
302         break;
303     case 124:
304         frequency = 5620;
305         break;
306     case 128:
307         frequency = 5640;
308         break;
309     case 132:
310         frequency = 5660;
311         break;
312     case 136:
313         frequency = 5680;
314         break;
315     case 140:
316         frequency = 5700;
317         break;
318     case 149:
319         frequency = 5745;
320         break;
321     case 153:
322         frequency = 5765;
323         break;
324     case 157:
325         frequency = 5785;
326         break;
327     case 161:
328         frequency = 5805;
329         break;
330     case 165:
331         frequency = 5825;
332         break;
333     }
334
335     return frequency;
336 }
337
338 static uint16_t MapFrequency(const uint16_t inBand, const uint8_t inChannel)
339 {
340     uint16_t frequency = 0;
341
342     if (inBand == WIFI_BAND_2_4GHZ)
343     {
344         frequency = Map2400MHz(inChannel);
345     }
346     else if (inBand == WIFI_BAND_5_0GHZ)
347     {
348         frequency = Map5000MHz(inChannel);
349     }
350
351     return frequency;
352 }
353
354 CHIP_ERROR ConnectivityManagerImpl::_GetAndLogWifiStatsCounters(void)
355 {
356     CHIP_ERROR err;
357     wifi_config_t wifiConfig;
358     uint8_t primaryChannel;
359     wifi_second_chan_t secondChannel;
360     uint16_t freq;
361     uint16_t bssid;
362
363     err = esp_wifi_get_config(WIFI_IF_STA, &wifiConfig);
364     if (err != ESP_OK)
365     {
366         ChipLogError(DeviceLayer, "esp_wifi_get_config() failed: %s", ErrorStr(err));
367     }
368     SuccessOrExit(err);
369
370     err = esp_wifi_get_channel(&primaryChannel, &secondChannel);
371     if (err != ESP_OK)
372     {
373         ChipLogError(DeviceLayer, "esp_wifi_get_channel() failed: %s", ErrorStr(err));
374     }
375     SuccessOrExit(err);
376
377     freq = MapFrequency(WIFI_BAND_2_4GHZ, primaryChannel);
378     static_assert(std::is_same<std::remove_reference<decltype(wifiConfig.sta.bssid[5])>::type, uint8_t>::value,
379                   "Our bits are going to start overlapping");
380     bssid = static_cast<uint16_t>((wifiConfig.sta.bssid[4] << 8) | wifiConfig.sta.bssid[5]);
381     ChipLogProgress(DeviceLayer,
382                     "Wifi-Telemetry\n"
383                     "BSSID: %x\n"
384                     "freq: %d\n",
385                     bssid, freq);
386 exit:
387     return CHIP_NO_ERROR;
388 }
389
390 // ==================== ConnectivityManager Platform Internal Methods ====================
391
392 CHIP_ERROR ConnectivityManagerImpl::_Init()
393 {
394     CHIP_ERROR err;
395
396     mLastStationConnectFailTime     = 0;
397     mLastAPDemandTime               = 0;
398     mWiFiStationMode                = kWiFiStationMode_Disabled;
399     mWiFiStationState               = kWiFiStationState_NotConnected;
400     mWiFiAPMode                     = kWiFiAPMode_Disabled;
401     mWiFiAPState                    = kWiFiAPState_NotActive;
402     mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL;
403     mWiFiAPIdleTimeoutMS            = CHIP_DEVICE_CONFIG_WIFI_AP_IDLE_TIMEOUT;
404     mFlags                          = 0;
405
406     // TODO Initialize the Chip Addressing and Routing Module.
407
408     // Ensure that ESP station mode is enabled.
409     err = Internal::ESP32Utils::EnableStationMode();
410     SuccessOrExit(err);
411
412     // If there is no persistent station provision...
413     if (!IsWiFiStationProvisioned())
414     {
415         // If the code has been compiled with a default WiFi station provision, configure that now.
416         if (CONFIG_DEFAULT_WIFI_SSID[0] != 0)
417         {
418             ChipLogProgress(DeviceLayer, "Setting default WiFi station configuration (SSID: %s)", CONFIG_DEFAULT_WIFI_SSID);
419
420             // Set a default station configuration.
421             wifi_config_t wifiConfig;
422             memset(&wifiConfig, 0, sizeof(wifiConfig));
423             memcpy(wifiConfig.sta.ssid, CONFIG_DEFAULT_WIFI_SSID, strlen(CONFIG_DEFAULT_WIFI_SSID) + 1);
424             memcpy(wifiConfig.sta.password, CONFIG_DEFAULT_WIFI_PASSWORD, strlen(CONFIG_DEFAULT_WIFI_PASSWORD) + 1);
425             wifiConfig.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
426             wifiConfig.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
427             err                        = esp_wifi_set_config(WIFI_IF_STA, &wifiConfig);
428             if (err != ESP_OK)
429             {
430                 ChipLogError(DeviceLayer, "esp_wifi_set_config() failed: %s", chip::ErrorStr(err));
431             }
432             err = CHIP_NO_ERROR;
433
434             // Enable WiFi station mode.
435             err = SetWiFiStationMode(kWiFiStationMode_Enabled);
436             SuccessOrExit(err);
437         }
438
439         // Otherwise, ensure WiFi station mode is disabled.
440         else
441         {
442             err = SetWiFiStationMode(kWiFiStationMode_Disabled);
443             SuccessOrExit(err);
444         }
445     }
446
447     // Force AP mode off for now.
448     err = Internal::ESP32Utils::SetAPMode(false);
449     SuccessOrExit(err);
450
451     // Queue work items to bootstrap the AP and station state machines once the Chip event loop is running.
452     err = SystemLayer.ScheduleWork(DriveStationState, NULL);
453     SuccessOrExit(err);
454     err = SystemLayer.ScheduleWork(DriveAPState, NULL);
455     SuccessOrExit(err);
456
457 exit:
458     return err;
459 }
460
461 void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
462 {
463     // Handle ESP system events...
464     if (event->Type == DeviceEventType::kESPSystemEvent)
465     {
466         if (event->Platform.ESPSystemEvent.Base == WIFI_EVENT)
467         {
468             switch (event->Platform.ESPSystemEvent.Id)
469             {
470             case WIFI_EVENT_STA_START:
471                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_STA_START");
472                 DriveStationState();
473                 break;
474             case WIFI_EVENT_STA_CONNECTED:
475                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_STA_CONNECTED");
476                 if (mWiFiStationState == kWiFiStationState_Connecting)
477                 {
478                     ChangeWiFiStationState(kWiFiStationState_Connecting_Succeeded);
479                 }
480                 DriveStationState();
481                 break;
482             case WIFI_EVENT_STA_DISCONNECTED:
483                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_STA_DISCONNECTED");
484                 if (mWiFiStationState == kWiFiStationState_Connecting)
485                 {
486                     ChangeWiFiStationState(kWiFiStationState_Connecting_Failed);
487                 }
488                 DriveStationState();
489                 break;
490             case WIFI_EVENT_STA_STOP:
491                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_STA_STOP");
492                 DriveStationState();
493                 break;
494             case WIFI_EVENT_AP_START:
495                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_AP_START");
496                 ChangeWiFiAPState(kWiFiAPState_Active);
497                 DriveAPState();
498                 break;
499             case WIFI_EVENT_AP_STOP:
500                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_AP_STOP");
501                 ChangeWiFiAPState(kWiFiAPState_NotActive);
502                 DriveAPState();
503                 break;
504             case WIFI_EVENT_AP_STACONNECTED:
505                 ChipLogProgress(DeviceLayer, "WIFI_EVENT_AP_STACONNECTED");
506                 MaintainOnDemandWiFiAP();
507                 break;
508             default:
509                 break;
510             }
511         }
512
513         if (event->Platform.ESPSystemEvent.Base == IP_EVENT)
514         {
515             switch (event->Platform.ESPSystemEvent.Id)
516             {
517             case IP_EVENT_STA_GOT_IP:
518                 ChipLogProgress(DeviceLayer, "IP_EVENT_STA_GOT_IP");
519                 OnStationIPv4AddressAvailable(event->Platform.ESPSystemEvent.Data.IpGotIp);
520                 break;
521             case IP_EVENT_STA_LOST_IP:
522                 ChipLogProgress(DeviceLayer, "IP_EVENT_STA_LOST_IP");
523                 OnStationIPv4AddressLost();
524                 break;
525             case IP_EVENT_GOT_IP6:
526                 ChipLogProgress(DeviceLayer, "IP_EVENT_GOT_IP6");
527                 OnIPv6AddressAvailable(event->Platform.ESPSystemEvent.Data.IpGotIp6);
528                 break;
529             default:
530                 break;
531             }
532         }
533     }
534 }
535
536 void ConnectivityManagerImpl::_OnWiFiScanDone()
537 {
538     // Schedule a call to DriveStationState method in case a station connect attempt was
539     // deferred because the scan was in progress.
540     SystemLayer.ScheduleWork(DriveStationState, NULL);
541 }
542
543 void ConnectivityManagerImpl::_OnWiFiStationProvisionChange()
544 {
545     // Schedule a call to the DriveStationState method to adjust the station state as needed.
546     SystemLayer.ScheduleWork(DriveStationState, NULL);
547 }
548
549 // ==================== ConnectivityManager Private Methods ====================
550
551 void ConnectivityManagerImpl::DriveStationState()
552 {
553     CHIP_ERROR err = CHIP_NO_ERROR;
554     bool stationConnected;
555
556     // Refresh the current station mode.  Specifically, this reads the ESP auto_connect flag,
557     // which determine whether the WiFi station mode is kWiFiStationMode_Enabled or
558     // kWiFiStationMode_Disabled.
559     GetWiFiStationMode();
560
561     // If the station interface is NOT under application control...
562     if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
563     {
564         // Ensure that the ESP WiFi layer is started.
565         err = Internal::ESP32Utils::StartWiFiLayer();
566         SuccessOrExit(err);
567
568         // Ensure that station mode is enabled in the ESP WiFi layer.
569         err = Internal::ESP32Utils::EnableStationMode();
570         SuccessOrExit(err);
571     }
572
573     // Determine if the ESP WiFi layer thinks the station interface is currently connected.
574     err = Internal::ESP32Utils::IsStationConnected(stationConnected);
575     SuccessOrExit(err);
576
577     // If the station interface is currently connected ...
578     if (stationConnected)
579     {
580         // Advance the station state to Connected if it was previously NotConnected or
581         // a previously initiated connect attempt succeeded.
582         if (mWiFiStationState == kWiFiStationState_NotConnected || mWiFiStationState == kWiFiStationState_Connecting_Succeeded)
583         {
584             ChangeWiFiStationState(kWiFiStationState_Connected);
585             ChipLogProgress(DeviceLayer, "WiFi station interface connected");
586             mLastStationConnectFailTime = 0;
587             OnStationConnected();
588         }
589
590         // If the WiFi station interface is no longer enabled, or no longer provisioned,
591         // disconnect the station from the AP, unless the WiFi station mode is currently
592         // under application control.
593         if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled &&
594             (mWiFiStationMode != kWiFiStationMode_Enabled || !IsWiFiStationProvisioned()))
595         {
596             ChipLogProgress(DeviceLayer, "Disconnecting WiFi station interface");
597             err = esp_wifi_disconnect();
598             if (err != ESP_OK)
599             {
600                 ChipLogError(DeviceLayer, "esp_wifi_disconnect() failed: %s", chip::ErrorStr(err));
601             }
602             SuccessOrExit(err);
603
604             ChangeWiFiStationState(kWiFiStationState_Disconnecting);
605         }
606     }
607
608     // Otherwise the station interface is NOT connected to an AP, so...
609     else
610     {
611         uint64_t now = System::Layer::GetClock_MonotonicMS();
612
613         // Advance the station state to NotConnected if it was previously Connected or Disconnecting,
614         // or if a previous initiated connect attempt failed.
615         if (mWiFiStationState == kWiFiStationState_Connected || mWiFiStationState == kWiFiStationState_Disconnecting ||
616             mWiFiStationState == kWiFiStationState_Connecting_Failed)
617         {
618             WiFiStationState prevState = mWiFiStationState;
619             ChangeWiFiStationState(kWiFiStationState_NotConnected);
620             if (prevState != kWiFiStationState_Connecting_Failed)
621             {
622                 ChipLogProgress(DeviceLayer, "WiFi station interface disconnected");
623                 mLastStationConnectFailTime = 0;
624                 OnStationDisconnected();
625             }
626             else
627             {
628                 mLastStationConnectFailTime = now;
629             }
630         }
631
632         // If the WiFi station interface is now enabled and provisioned (and by implication,
633         // not presently under application control), AND the system is not in the process of
634         // scanning, then...
635         if (mWiFiStationMode == kWiFiStationMode_Enabled && IsWiFiStationProvisioned())
636         {
637             // Initiate a connection to the AP if we haven't done so before, or if enough
638             // time has passed since the last attempt.
639             if (mLastStationConnectFailTime == 0 || now >= mLastStationConnectFailTime + mWiFiStationReconnectIntervalMS)
640             {
641                 ChipLogProgress(DeviceLayer, "Attempting to connect WiFi station interface");
642                 err = esp_wifi_connect();
643                 if (err != ESP_OK)
644                 {
645                     ChipLogError(DeviceLayer, "esp_wifi_connect() failed: %s", chip::ErrorStr(err));
646                 }
647                 SuccessOrExit(err);
648
649                 ChangeWiFiStationState(kWiFiStationState_Connecting);
650             }
651
652             // Otherwise arrange another connection attempt at a suitable point in the future.
653             else
654             {
655                 uint32_t timeToNextConnect = (uint32_t)((mLastStationConnectFailTime + mWiFiStationReconnectIntervalMS) - now);
656
657                 ChipLogProgress(DeviceLayer, "Next WiFi station reconnect in %" PRIu32 " ms", timeToNextConnect);
658
659                 err = SystemLayer.StartTimer(timeToNextConnect, DriveStationState, NULL);
660                 SuccessOrExit(err);
661             }
662         }
663     }
664
665 exit:
666
667     ChipLogProgress(DeviceLayer, "Done driving station state, nothing else to do...");
668     // Kick-off any pending network scan that might have been deferred due to the activity
669     // of the WiFi station.
670 }
671
672 void ConnectivityManagerImpl::OnStationConnected()
673 {
674     CHIP_ERROR err;
675
676     // Assign an IPv6 link local address to the station interface.
677     err = esp_netif_create_ip6_linklocal(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"));
678     if (err != ESP_OK)
679     {
680         ChipLogError(DeviceLayer, "esp_netif_create_ip6_linklocal() failed for WIFI_STA_DEF interface: %s", chip::ErrorStr(err));
681     }
682
683     // TODO Invoke WARM to perform actions that occur when the WiFi station interface comes up.
684
685     // Alert other components of the new state.
686     ChipDeviceEvent event;
687     event.Type                          = DeviceEventType::kWiFiConnectivityChange;
688     event.WiFiConnectivityChange.Result = kConnectivity_Established;
689     PlatformMgr().PostEvent(&event);
690
691     UpdateInternetConnectivityState();
692 }
693
694 void ConnectivityManagerImpl::OnStationDisconnected()
695 {
696     // TODO Invoke WARM to perform actions that occur when the WiFi station interface goes down.
697
698     // Alert other components of the new state.
699     ChipDeviceEvent event;
700     event.Type                          = DeviceEventType::kWiFiConnectivityChange;
701     event.WiFiConnectivityChange.Result = kConnectivity_Lost;
702     PlatformMgr().PostEvent(&event);
703
704     UpdateInternetConnectivityState();
705 }
706
707 void ConnectivityManagerImpl::ChangeWiFiStationState(WiFiStationState newState)
708 {
709     if (mWiFiStationState != newState)
710     {
711         ChipLogProgress(DeviceLayer, "WiFi station state change: %s -> %s", WiFiStationStateToStr(mWiFiStationState),
712                         WiFiStationStateToStr(newState));
713         mWiFiStationState = newState;
714     }
715 }
716
717 void ConnectivityManagerImpl::DriveStationState(::chip::System::Layer * aLayer, void * aAppState, ::chip::System::Error aError)
718 {
719     sInstance.DriveStationState();
720 }
721
722 void ConnectivityManagerImpl::DriveAPState()
723 {
724     CHIP_ERROR err = CHIP_NO_ERROR;
725     WiFiAPState targetState;
726     uint64_t now;
727     uint32_t apTimeout;
728     bool espAPModeEnabled;
729
730     // Determine if AP mode is currently enabled in the ESP WiFi layer.
731     err = Internal::ESP32Utils::IsAPEnabled(espAPModeEnabled);
732     SuccessOrExit(err);
733
734     // Adjust the Connectivity Manager's AP state to match the state in the WiFi layer.
735     if (espAPModeEnabled && (mWiFiAPState == kWiFiAPState_NotActive || mWiFiAPState == kWiFiAPState_Deactivating))
736     {
737         ChangeWiFiAPState(kWiFiAPState_Activating);
738     }
739     if (!espAPModeEnabled && (mWiFiAPState == kWiFiAPState_Active || mWiFiAPState == kWiFiAPState_Activating))
740     {
741         ChangeWiFiAPState(kWiFiAPState_Deactivating);
742     }
743
744     // If the AP interface is not under application control...
745     if (mWiFiAPMode != kWiFiAPMode_ApplicationControlled)
746     {
747         // Ensure the ESP WiFi layer is started.
748         err = Internal::ESP32Utils::StartWiFiLayer();
749         SuccessOrExit(err);
750
751         // Determine the target (desired) state for AP interface...
752
753         // The target state is 'NotActive' if the application has expressly disabled the AP interface.
754         if (mWiFiAPMode == kWiFiAPMode_Disabled)
755         {
756             targetState = kWiFiAPState_NotActive;
757         }
758
759         // The target state is 'Active' if the application has expressly enabled the AP interface.
760         else if (mWiFiAPMode == kWiFiAPMode_Enabled)
761         {
762             targetState = kWiFiAPState_Active;
763         }
764
765         // The target state is 'Active' if the AP mode is 'On demand, when no station is available'
766         // and the station interface is not provisioned or the application has disabled the station
767         // interface.
768         else if (mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision &&
769                  (!IsWiFiStationProvisioned() || GetWiFiStationMode() == kWiFiStationMode_Disabled))
770         {
771             targetState = kWiFiAPState_Active;
772         }
773
774         // The target state is 'Active' if the AP mode is one of the 'On demand' modes and there
775         // has been demand for the AP within the idle timeout period.
776         else if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
777         {
778             now = System::Layer::GetClock_MonotonicMS();
779
780             if (mLastAPDemandTime != 0 && now < (mLastAPDemandTime + mWiFiAPIdleTimeoutMS))
781             {
782                 targetState = kWiFiAPState_Active;
783
784                 // Compute the amount of idle time before the AP should be deactivated and
785                 // arm a timer to fire at that time.
786                 apTimeout = (uint32_t)((mLastAPDemandTime + mWiFiAPIdleTimeoutMS) - now);
787                 err       = SystemLayer.StartTimer(apTimeout, DriveAPState, NULL);
788                 SuccessOrExit(err);
789                 ChipLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " ms", apTimeout);
790             }
791             else
792             {
793                 targetState = kWiFiAPState_NotActive;
794             }
795         }
796
797         // Otherwise the target state is 'NotActive'.
798         else
799         {
800             targetState = kWiFiAPState_NotActive;
801         }
802
803         // If the current AP state does not match the target state...
804         if (mWiFiAPState != targetState)
805         {
806             // If the target state is 'Active' and the current state is NOT 'Activating', enable
807             // and configure the AP interface, and then enter the 'Activating' state.  Eventually
808             // a SYSTEM_EVENT_AP_START event will be received from the ESP WiFi layer which will
809             // cause the state to transition to 'Active'.
810             if (targetState == kWiFiAPState_Active)
811             {
812                 if (mWiFiAPState != kWiFiAPState_Activating)
813                 {
814                     err = Internal::ESP32Utils::SetAPMode(true);
815                     SuccessOrExit(err);
816
817                     err = ConfigureWiFiAP();
818                     SuccessOrExit(err);
819
820                     ChangeWiFiAPState(kWiFiAPState_Activating);
821                 }
822             }
823
824             // Otherwise, if the target state is 'NotActive' and the current state is not 'Deactivating',
825             // disable the AP interface and enter the 'Deactivating' state.  Later a SYSTEM_EVENT_AP_STOP
826             // event will move the AP state to 'NotActive'.
827             else
828             {
829                 if (mWiFiAPState != kWiFiAPState_Deactivating)
830                 {
831                     err = Internal::ESP32Utils::SetAPMode(false);
832                     SuccessOrExit(err);
833
834                     ChangeWiFiAPState(kWiFiAPState_Deactivating);
835                 }
836             }
837         }
838     }
839
840     // If AP is active, but the interface doesn't have an IPv6 link-local
841     // address, assign one now.
842     if (mWiFiAPState == kWiFiAPState_Active && Internal::ESP32Utils::IsInterfaceUp("WIFI_AP_DEF") &&
843         !Internal::ESP32Utils::HasIPv6LinkLocalAddress("WIFI_AP_DEF"))
844     {
845         err = esp_netif_create_ip6_linklocal(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"));
846         if (err != ESP_OK)
847         {
848             ChipLogError(DeviceLayer, "esp_netif_create_ip6_linklocal() failed for WIFI_AP_DEF interface: %s", chip::ErrorStr(err));
849         }
850         SuccessOrExit(err);
851     }
852
853 exit:
854     if (err != CHIP_NO_ERROR && mWiFiAPMode != kWiFiAPMode_ApplicationControlled)
855     {
856         SetWiFiAPMode(kWiFiAPMode_Disabled);
857         Internal::ESP32Utils::SetAPMode(false);
858     }
859 }
860
861 CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP()
862 {
863     CHIP_ERROR err = CHIP_NO_ERROR;
864     wifi_config_t wifiConfig;
865
866     memset(&wifiConfig, 0, sizeof(wifiConfig));
867
868     uint16_t discriminator;
869     SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator));
870
871     snprintf((char *) wifiConfig.ap.ssid, sizeof(wifiConfig.ap.ssid), "%s%04u", CHIP_DEVICE_CONFIG_WIFI_AP_SSID_PREFIX,
872              discriminator);
873     wifiConfig.ap.channel         = CHIP_DEVICE_CONFIG_WIFI_AP_CHANNEL;
874     wifiConfig.ap.authmode        = WIFI_AUTH_OPEN;
875     wifiConfig.ap.max_connection  = CHIP_DEVICE_CONFIG_WIFI_AP_MAX_STATIONS;
876     wifiConfig.ap.beacon_interval = CHIP_DEVICE_CONFIG_WIFI_AP_BEACON_INTERVAL;
877     ChipLogProgress(DeviceLayer, "Configuring WiFi AP: SSID %s, channel %u", wifiConfig.ap.ssid, wifiConfig.ap.channel);
878     err = esp_wifi_set_config(WIFI_IF_AP, &wifiConfig);
879     if (err != ESP_OK)
880     {
881         ChipLogError(DeviceLayer, "esp_wifi_set_config(WIFI_IF_AP) failed: %s", chip::ErrorStr(err));
882     }
883     SuccessOrExit(err);
884
885 exit:
886     return err;
887 }
888
889 void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState)
890 {
891     if (mWiFiAPState != newState)
892     {
893         ChipLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState));
894         mWiFiAPState = newState;
895     }
896 }
897
898 void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState, ::chip::System::Error aError)
899 {
900     sInstance.DriveAPState();
901 }
902
903 void ConnectivityManagerImpl::UpdateInternetConnectivityState(void)
904 {
905     bool haveIPv4Conn = false;
906     bool haveIPv6Conn = false;
907     bool hadIPv4Conn  = GetFlag(mFlags, kFlag_HaveIPv4InternetConnectivity);
908     bool hadIPv6Conn  = GetFlag(mFlags, kFlag_HaveIPv6InternetConnectivity);
909     IPAddress addr;
910
911     // If the WiFi station is currently in the connected state...
912     if (mWiFiStationState == kWiFiStationState_Connected)
913     {
914         // Get the LwIP netif for the WiFi station interface.
915         struct netif * netif = Internal::ESP32Utils::GetStationNetif();
916
917         // If the WiFi station interface is up...
918         if (netif != NULL && netif_is_up(netif) && netif_is_link_up(netif))
919         {
920             // Check if a DNS server is currently configured.  If so...
921             ip_addr_t dnsServerAddr = *dns_getserver(0);
922             if (!ip_addr_isany_val(dnsServerAddr))
923             {
924                 // If the station interface has been assigned an IPv4 address, and has
925                 // an IPv4 gateway, then presume that the device has IPv4 Internet
926                 // connectivity.
927                 if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) && !ip4_addr_isany_val(*netif_ip4_gw(netif)))
928                 {
929                     haveIPv4Conn = true;
930
931                     esp_netif_ip_info_t ipInfo;
932                     if (esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ipInfo) == ESP_OK)
933                     {
934                         char addrStr[INET_ADDRSTRLEN];
935                         // ToDo: change the code to using IPv6 address
936                         esp_ip4addr_ntoa(&ipInfo.ip, addrStr, sizeof(addrStr));
937                         IPAddress::FromString(addrStr, addr);
938                     }
939                 }
940
941                 // Search among the IPv6 addresses assigned to the interface for a Global Unicast
942                 // address (2000::/3) that is in the valid state.  If such an address is found...
943                 for (uint8_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
944                 {
945                     if (ip6_addr_isglobal(netif_ip6_addr(netif, i)) && ip6_addr_isvalid(netif_ip6_addr_state(netif, i)))
946                     {
947                         // Determine if there is a default IPv6 router that is currently reachable
948                         // via the station interface.  If so, presume for now that the device has
949                         // IPv6 connectivity.
950                         struct netif * found_if = nd6_find_route(IP6_ADDR_ANY6);
951                         if (found_if && netif->num == found_if->num)
952                         {
953                             haveIPv6Conn = true;
954                         }
955                     }
956                 }
957             }
958         }
959     }
960
961     // If the internet connectivity state has changed...
962     if (haveIPv4Conn != hadIPv4Conn || haveIPv6Conn != hadIPv6Conn)
963     {
964         // Update the current state.
965         SetFlag(mFlags, kFlag_HaveIPv4InternetConnectivity, haveIPv4Conn);
966         SetFlag(mFlags, kFlag_HaveIPv6InternetConnectivity, haveIPv6Conn);
967
968         // Alert other components of the state change.
969         ChipDeviceEvent event;
970         event.Type                            = DeviceEventType::kInternetConnectivityChange;
971         event.InternetConnectivityChange.IPv4 = GetConnectivityChange(hadIPv4Conn, haveIPv4Conn);
972         event.InternetConnectivityChange.IPv6 = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn);
973         addr.ToString(event.InternetConnectivityChange.address);
974         PlatformMgr().PostEvent(&event);
975
976         if (haveIPv4Conn != hadIPv4Conn)
977         {
978             ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv4", (haveIPv4Conn) ? "ESTABLISHED" : "LOST");
979         }
980
981         if (haveIPv6Conn != hadIPv6Conn)
982         {
983             ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv6", (haveIPv6Conn) ? "ESTABLISHED" : "LOST");
984         }
985     }
986 }
987
988 void ConnectivityManagerImpl::OnStationIPv4AddressAvailable(const ip_event_got_ip_t & got_ip)
989 {
990 #if CHIP_PROGRESS_LOGGING
991     {
992         ChipLogProgress(DeviceLayer, "IPv4 address %s on WiFi station interface: " IPSTR "/" IPSTR " gateway " IPSTR,
993                         (got_ip.ip_changed) ? "changed" : "ready", IP2STR(&got_ip.ip_info.ip), IP2STR(&got_ip.ip_info.netmask),
994                         IP2STR(&got_ip.ip_info.gw));
995     }
996 #endif // CHIP_PROGRESS_LOGGING
997
998     RefreshMessageLayer();
999
1000     UpdateInternetConnectivityState();
1001
1002     ChipDeviceEvent event;
1003     event.Type                           = DeviceEventType::kInterfaceIpAddressChanged;
1004     event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV4_Assigned;
1005     PlatformMgr().PostEvent(&event);
1006 }
1007
1008 void ConnectivityManagerImpl::OnStationIPv4AddressLost(void)
1009 {
1010     ChipLogProgress(DeviceLayer, "IPv4 address lost on WiFi station interface");
1011
1012     RefreshMessageLayer();
1013
1014     UpdateInternetConnectivityState();
1015
1016     ChipDeviceEvent event;
1017     event.Type                           = DeviceEventType::kInterfaceIpAddressChanged;
1018     event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV4_Lost;
1019     PlatformMgr().PostEvent(&event);
1020 }
1021
1022 void ConnectivityManagerImpl::OnIPv6AddressAvailable(const ip_event_got_ip6_t & got_ip)
1023 {
1024 #if CHIP_PROGRESS_LOGGING
1025     {
1026         ChipLogProgress(DeviceLayer, "IPv6 addr available. Ready on %s interface: " IPV6STR, esp_netif_get_ifkey(got_ip.esp_netif),
1027                         IPV62STR(got_ip.ip6_info.ip));
1028     }
1029 #endif // CHIP_PROGRESS_LOGGING
1030
1031     RefreshMessageLayer();
1032
1033     UpdateInternetConnectivityState();
1034
1035     ChipDeviceEvent event;
1036     event.Type                           = DeviceEventType::kInterfaceIpAddressChanged;
1037     event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV6_Assigned;
1038     PlatformMgr().PostEvent(&event);
1039 }
1040
1041 void ConnectivityManagerImpl::RefreshMessageLayer(void) {}
1042
1043 } // namespace DeviceLayer
1044 } // namespace chip