Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[linux] Add WiFi support in ConnectivityManager. #1975

Merged
merged 3 commits into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions src/platform/Linux/ConnectivityManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,21 @@
#include <platform/internal/GenericConnectivityManagerImpl_Thread.ipp>
#endif

#if CHIP_DEVICE_CONFIG_ENABLE_WPA
#include <platform/internal/GenericConnectivityManagerImpl_WiFi.ipp>
#endif

using namespace ::chip;
using namespace ::chip::TLV;
using namespace ::chip::DeviceLayer::Internal;

#if CHIP_DEVICE_CONFIG_ENABLE_WPA
namespace {
const char kWpaSupplicantServiceName[] = "fi.w1.wpa_supplicant1";
const char kWpaSupplicantObjectPath[] = "/fi/w1/wpa_supplicant1";
} // namespace
#endif

namespace chip {
namespace DeviceLayer {

Expand All @@ -52,6 +63,19 @@ CHIP_ERROR ConnectivityManagerImpl::_Init()
GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_Init();
#endif

#if CHIP_DEVICE_CONFIG_ENABLE_WPA
mConnectivityFlag = 0;
mWpaSupplicant.state = GDBusWpaSupplicant::INIT;
mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
mWpaSupplicant.proxy = NULL;
mWpaSupplicant.iface = NULL;
mWpaSupplicant.interfacePath = NULL;
mWpaSupplicant.networkPath = NULL;

wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
kWpaSupplicantObjectPath, NULL, _OnWpaProxyReady, NULL);
#endif

SuccessOrExit(err);

exit:
Expand All @@ -66,5 +90,186 @@ void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
#endif
}

#if CHIP_DEVICE_CONFIG_ENABLE_WPA

uint16_t ConnectivityManagerImpl::mConnectivityFlag;
struct GDBusWpaSupplicant ConnectivityManagerImpl::mWpaSupplicant;

bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity(void)
{
return ((mConnectivityFlag & kFlag_HaveIPv4InternetConnectivity) != 0);
}

bool ConnectivityManagerImpl::_HaveIPv6InternetConnectivity(void)
{
return ((mConnectivityFlag & kFlag_HaveIPv6InternetConnectivity) != 0);
}

bool ConnectivityManagerImpl::_IsWiFiStationConnected(void)
{
bool ret = false;
const gchar * state = NULL;

if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
{
ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationConnected: interface not connected");
return false;
}

state = wpa_fi_w1_wpa_supplicant1_interface_get_state(mWpaSupplicant.iface);
ChipLogProgress(DeviceLayer, "wpa_supplicant: wpa_fi_w1_wpa_supplicant1_interface_get_state: %s", state);

if (g_strcmp0(state, "completed") == 0)
{
ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi already connected");
SetFlag(mConnectivityFlag, kFlag_HaveIPv4InternetConnectivity, true);
SetFlag(mConnectivityFlag, kFlag_HaveIPv6InternetConnectivity, true);
ret = true;
}

return ret;
}

bool ConnectivityManagerImpl::_CanStartWiFiScan()
{
return mWpaSupplicant.state == GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED &&
mWpaSupplicant.scanState == GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
}

void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
{
GError * err = NULL;
WpaFiW1Wpa_supplicant1Interface * iface = wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus_finish(res, &err);

if (mWpaSupplicant.iface)
{
g_object_unref(mWpaSupplicant.iface);
mWpaSupplicant.iface = NULL;
}

if (iface != NULL && err == NULL)
{
mWpaSupplicant.iface = iface;
mWpaSupplicant.state = GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED;
ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant interface proxy");
}
else
{
ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant1 interface proxy %s: %s",
mWpaSupplicant.interfacePath, err ? err->message : "unknown error");

mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
}

if (err != NULL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to check for NULL here as g_error_free() already does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer always check NULL before calling all g_error_free() even it handles NULL case, this pattern is used throughout gio source code. Suppose there are 0.001 chance of error, then we can prevent 99.99% unnecessary function call.

g_error_free(err);
}

void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
{
GError * err = NULL;

gboolean result =
wpa_fi_w1_wpa_supplicant1_call_get_interface_finish(mWpaSupplicant.proxy, &mWpaSupplicant.interfacePath, res, &err);
if (result)
{
mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);

wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
mWpaSupplicant.interfacePath, NULL, _OnWpaInterfaceProxyReady, NULL);
}
else
{
ChipLogProgress(DeviceLayer, "wpa_supplicant: can't find interface %s: %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME,
err ? err->message : "unknown error");

mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;

if (mWpaSupplicant.interfacePath)
{
g_free(mWpaSupplicant.interfacePath);
mWpaSupplicant.interfacePath = NULL;
}
}

if (err != NULL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need this branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comments above

g_error_free(err);
}

void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
gpointer user_data)
{
if (mWpaSupplicant.interfacePath)
return;

mWpaSupplicant.interfacePath = const_cast<gchar *>(path);
if (mWpaSupplicant.interfacePath)
{
mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface added: %s", mWpaSupplicant.interfacePath);

wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
mWpaSupplicant.interfacePath, NULL, _OnWpaInterfaceProxyReady, NULL);
}
}

void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
gpointer user_data)
{
if (mWpaSupplicant.interfacePath == NULL)
return;

if (g_strcmp0(mWpaSupplicant.interfacePath, path) == 0)
{
ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface removed: %s", path);

mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;

if (mWpaSupplicant.interfacePath)
{
g_free(mWpaSupplicant.interfacePath);
mWpaSupplicant.interfacePath = NULL;
}

if (mWpaSupplicant.iface)
{
g_object_unref(mWpaSupplicant.iface);
mWpaSupplicant.iface = NULL;
}

mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
}
}

void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
{
GError * err = NULL;

mWpaSupplicant.proxy = wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus_finish(res, &err);
if (mWpaSupplicant.proxy != NULL && err == NULL)
{
mWpaSupplicant.state = GDBusWpaSupplicant::WPA_CONNECTED;
ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant proxy");

g_signal_connect(mWpaSupplicant.proxy, "interface-added", G_CALLBACK(_OnWpaInterfaceAdded), NULL);

g_signal_connect(mWpaSupplicant.proxy, "interface-removed", G_CALLBACK(_OnWpaInterfaceRemoved), NULL);

wpa_fi_w1_wpa_supplicant1_call_get_interface(mWpaSupplicant.proxy, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, NULL,
_OnWpaInterfaceReady, NULL);
}
else
{
ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant proxy %s",
err ? err->message : "unknown error");
mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
}

if (err != NULL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need this branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above

g_error_free(err);
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA

} // namespace DeviceLayer
} // namespace chip
55 changes: 55 additions & 0 deletions src/platform/Linux/ConnectivityManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@
#include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
#endif
#include <platform/internal/GenericConnectivityManagerImpl_NoTunnel.h>
#if CHIP_DEVICE_CONFIG_ENABLE_WPA
#include <platform/internal/GenericConnectivityManagerImpl_WiFi.h>
#else
#include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
#endif
#include <support/FlagUtils.hpp>

#if CHIP_DEVICE_CONFIG_ENABLE_WPA
#include <platform/Linux/dbus/DBusWpa.h>
#include <platform/Linux/dbus/DBusWpaInterface.h>
#include <platform/Linux/dbus/DBusWpaNetwork.h>
#endif

namespace chip {
namespace Inet {
class IPAddress;
Expand All @@ -44,6 +54,33 @@ class IPAddress;
namespace chip {
namespace DeviceLayer {

#if CHIP_DEVICE_CONFIG_ENABLE_WPA
struct GDBusWpaSupplicant
{
enum
{
INIT,
WPA_CONNECTING,
WPA_CONNECTED,
WPA_NOT_CONNECTED,
WPA_NO_INTERFACE_PATH,
WPA_GOT_INTERFACE_PATH,
WPA_INTERFACE_CONNECTED,
} state;

enum
{
WIFI_SCANNING_IDLE,
WIFI_SCANNING,
} scanState;

WpaFiW1Wpa_supplicant1 * proxy;
WpaFiW1Wpa_supplicant1Interface * iface;
gchar * interfacePath;
gchar * networkPath;
};
#endif

/**
* Concrete implementation of the ConnectivityManager singleton object for Linux platforms.
*/
Expand All @@ -59,7 +96,11 @@ class ConnectivityManagerImpl final : public ConnectivityManager,
#else
public Internal::GenericConnectivityManagerImpl_NoThread<ConnectivityManagerImpl>,
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_WPA
public Internal::GenericConnectivityManagerImpl_WiFi<ConnectivityManagerImpl>,
#else
public Internal::GenericConnectivityManagerImpl_NoWiFi<ConnectivityManagerImpl>,
#endif
public Internal::GenericConnectivityManagerImpl_NoTunnel<ConnectivityManagerImpl>
{
// Allow the ConnectivityManager interface class to delegate method calls to
Expand All @@ -75,6 +116,20 @@ class ConnectivityManagerImpl final : public ConnectivityManager,
CHIP_ERROR _Init(void);
void _OnPlatformEvent(const ChipDeviceEvent * event);

#if CHIP_DEVICE_CONFIG_ENABLE_WPA
bool _IsWiFiStationConnected(void);
bool _CanStartWiFiScan();
static void _OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data);
static void _OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
gpointer user_data);
static void _OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, gpointer user_data);
static void _OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data);
static void _OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data);

static uint16_t mConnectivityFlag;
static struct GDBusWpaSupplicant mWpaSupplicant;
#endif

// ===== Members for internal use by the following friends.

friend ConnectivityManager & ConnectivityMgr(void);
Expand Down
Loading