diff --git a/.gitmodules b/.gitmodules index 07cd7d41d2389e..f63867c8308169 100644 --- a/.gitmodules +++ b/.gitmodules @@ -331,3 +331,8 @@ url = https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c platforms = esp32 recursive = true +[submodule "third_party/hostap/repo"] + path = third_party/hostap/repo + url = https://gitlab.com/prpl-foundation/mirrors/hostap.git + branch = main + platforms = linux diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 0ebb492b45327d..b28fe89129638a 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -144,6 +144,8 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG=${chip_device_config_enable_dynamic_mrp_config}", "CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF=${chip_device_config_enable_wifipaf}", "CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC=${chip_device_config_enable_joint_fabric}", + "CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_CTRL_IFACE=${chip_device_config_enable_wifipaf_ctrl_iface}", + "CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_HOSTAPD=${chip_device_config_enable_wifipaf_hostapd}", ] public_deps = [ "${chip_root}/src/app/icd/server:icd-server-config" ] diff --git a/src/platform/Linux/BUILD.gn b/src/platform/Linux/BUILD.gn index e83f7f714d2bd5..898e8588e181cf 100644 --- a/src/platform/Linux/BUILD.gn +++ b/src/platform/Linux/BUILD.gn @@ -74,6 +74,7 @@ static_library("Linux") { "PosixConfig.h", "SystemPlatformConfig.h", "SystemTimeSupport.cpp", + "WpaDbusDefs.h", ] deps = [ @@ -181,5 +182,43 @@ static_library("Linux") { if (chip_device_config_enable_wifipaf) { public_deps += [ "${chip_root}/src/wifipaf" ] + sources += [ + "WiFiPAFDriver.cpp", + "WiFiPAFDriver.h", + ] + if (chip_device_config_enable_wifipaf_ctrl_iface) { + include_dirs = [ "${chip_root}/third_party/hostap/repo/src/common" ] + sources += [ + "WiFiPAFDriverCtrlIface.cpp", + "WiFiPAFDriverCtrlIface.h", + ] + deps += [ ":wpa_ctrl" ] + } else { + sources += [ + "WiFiPAFDriverDbus.cpp", + "WiFiPAFDriverDbus.h", + ] + } + } +} + +if (chip_device_config_enable_wifipaf_ctrl_iface) { + source_set("wpa_ctrl") { + cflags_c = [ + "-std=c99", + "-Wno-error=vla", + ] + include_dirs = [ + "${chip_root}/third_party/hostap/repo/src/common", + "${chip_root}/third_party/hostap/repo/src/utils", + ] + sources = [ + "${chip_root}/third_party/hostap/repo/src/common/wpa_ctrl.c", + "${chip_root}/third_party/hostap/repo/src/utils/os_unix.c", + ] + defines = [ + "CONFIG_CTRL_IFACE", + "CONFIG_CTRL_IFACE_UNIX", + ] } } diff --git a/src/platform/Linux/ConnectivityManagerImpl.cpp b/src/platform/Linux/ConnectivityManagerImpl.cpp index c01d00583aa004..1deec5e41e3f02 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.cpp +++ b/src/platform/Linux/ConnectivityManagerImpl.cpp @@ -68,6 +68,14 @@ #include #endif +#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF +#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_CTRL_IFACE +#include +#else +#include +#endif +#endif + using namespace ::chip; using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; @@ -717,126 +725,31 @@ bool ConnectivityManagerImpl::IsWiFiManagementStarted() } #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF -const char srv_name[] = "_matterc._udp"; -/* - NAN-USD Service Protocol Type: ref: Table 58 of Wi-Fi Aware Specificaiton -*/ -#define NAN_PUBLISH_SSI_TAG " ssi=" - -#pragma pack(push, 1) -struct PAFPublishSSI -{ - uint8_t DevOpCode; - uint16_t DevInfo; - uint16_t ProductId; - uint16_t VendorId; -}; - -enum nan_service_protocol_type -{ - NAN_SRV_PROTO_BONJOUR = 1, - NAN_SRV_PROTO_GENERIC = 2, - NAN_SRV_PROTO_CSA_MATTER = 3, -}; -#pragma pack(pop) CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFPublish(ConnectivityManager::WiFiPAFAdvertiseParam & InArgs) { CHIP_ERROR result = StartWiFiManagementSync(); VerifyOrReturnError(result == CHIP_NO_ERROR, result); - GAutoPtr err; - guint publish_id; - enum nan_service_protocol_type srv_proto_type = nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER; - unsigned int ttl = CHIP_DEVICE_CONFIG_WIFIPAF_MAX_ADVERTISING_TIMEOUT_SECS; - unsigned int freq = CHIP_DEVICE_CONFIG_WIFIPAF_24G_DEFAUTL_CHNL; - unsigned int ssi_len = sizeof(struct PAFPublishSSI); - - // Add the freq_list: - GVariant * freq_array_variant = - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT16, InArgs.freq_list.get(), InArgs.freq_list_len, sizeof(guint16)); - if (freq_array_variant == nullptr) - { - ChipLogError(DeviceLayer, "WiFi-PAF: freq_array_variant is NULL "); - return CHIP_ERROR_INTERNAL; - } - - // Construct the SSI - struct PAFPublishSSI PafPublish_ssi; - - PafPublish_ssi.DevOpCode = 0; - VerifyOrDie(DeviceLayer::GetCommissionableDataProvider()->GetSetupDiscriminator(PafPublish_ssi.DevInfo) == CHIP_NO_ERROR); - if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(PafPublish_ssi.ProductId) != CHIP_NO_ERROR) + if (mWiFiPAFDriver == nullptr) { - PafPublish_ssi.ProductId = 0; - } - if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(PafPublish_ssi.VendorId) != CHIP_NO_ERROR) - { - PafPublish_ssi.VendorId = 0; - } - GVariant * ssi_array_variant = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &PafPublish_ssi, ssi_len, sizeof(guint8)); - if (ssi_array_variant == nullptr) - { - ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL "); - return CHIP_ERROR_INTERNAL; +#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_CTRL_IFACE + mWiFiPAFDriver = std::make_unique(); +#else + mWiFiPAFDriver = std::make_unique(&mWpaSupplicant, &mWpaSupplicantMutex); +#endif + mWiFiPAFDriver->Initialize(); } - GVariantBuilder builder; - GVariant * args = nullptr; - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add(&builder, "{sv}", "srv_name", g_variant_new_string(srv_name)); - g_variant_builder_add(&builder, "{sv}", "srv_proto_type", g_variant_new_byte(srv_proto_type)); - g_variant_builder_add(&builder, "{sv}", "ttl", g_variant_new_uint16(ttl)); - g_variant_builder_add(&builder, "{sv}", "freq", g_variant_new_uint16(freq)); - g_variant_builder_add(&builder, "{sv}", "ssi", ssi_array_variant); - g_variant_builder_add(&builder, "{sv}", "freq_list", freq_array_variant); - args = g_variant_builder_end(&builder); - std::lock_guard lock(mWpaSupplicantMutex); - wpa_supplicant_1_interface_call_nanpublish_sync(mWpaSupplicant.iface.get(), args, &publish_id, nullptr, &err.GetReceiver()); - - ChipLogProgress(DeviceLayer, "WiFi-PAF: publish_id: %u ! ", publish_id); - WiFiPAFSession sessionInfo = { .role = WiFiPafRole::kWiFiPafRole_Publisher, .id = publish_id }; - WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); - ReturnErrorOnFailure(WiFiPafLayer.AddPafSession(PafInfoAccess::kAccSessionId, sessionInfo)); - InArgs.publish_id = publish_id; - - g_signal_connect(mWpaSupplicant.iface.get(), "nanreplied", - G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, ConnectivityManagerImpl * self) { - return self->OnReplied(obj); - }), - this); - - g_signal_connect(mWpaSupplicant.iface.get(), "nanreceive", - G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, ConnectivityManagerImpl * self) { - return self->OnNanReceive(obj); - }), - this); - g_signal_connect( - mWpaSupplicant.iface.get(), "nanpublish-terminated", - G_CALLBACK(+[](WpaSupplicant1Interface * proxy, guint term_publish_id, gchar * reason, ConnectivityManagerImpl * self) { - return self->OnNanPublishTerminated(term_publish_id, reason); - }), - this); - return CHIP_NO_ERROR; + + return mWiFiPAFDriver->Publish(std::move(InArgs.freq_list), InArgs.freq_list_len); } CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFCancelPublish(uint32_t PublishId) { - GAutoPtr err; - - ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel publish_id: %d ! ", PublishId); - std::lock_guard lock(mWpaSupplicantMutex); - - VerifyOrReturnError(mWpaSupplicant.iface, CHIP_ERROR_INTERNAL, - ChipLogError(DeviceLayer, "WiFi-PAF: Skip D-Bus 'cancel publish' call since wpa_supplicant is not ready")); - - gboolean result = - wpa_supplicant_1_interface_call_nancancel_publish_sync(mWpaSupplicant.iface.get(), PublishId, nullptr, &err.GetReceiver()); - - // TODO #40814: make sure that the callers do check the return values. This doesn't seem to be happening now. - VerifyOrReturnError( - result, CHIP_ERROR_INTERNAL, - ChipLogError(DeviceLayer, "WiFi-PAF: Failed to Cancel Publish with Error: %s", err ? err->message : "unknown error")); - + if (mWiFiPAFDriver != nullptr) + { + return mWiFiPAFDriver->CancelPublish(PublishId); + } return CHIP_NO_ERROR; } #endif @@ -1235,347 +1148,39 @@ CHIP_ERROR ConnectivityManagerImpl::ConnectWiFiNetworkWithPDCAsync( return _ConnectWiFiNetworkAsync(args, connectCallback); } #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_PDC -#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF -/* - NAN-USD Service Protocol Type: ref: Table 58 of Wi-Fi Aware Specificaiton -*/ -void ConnectivityManagerImpl::OnDiscoveryResult(GVariant * discov_info) -{ - ChipLogProgress(Controller, "WiFi-PAF: OnDiscoveryResult"); - uint32_t subscribe_id; - uint32_t peer_publish_id; - uint8_t peer_addr[6]; - uint32_t srv_proto_type; - - std::lock_guard lock(mWpaSupplicantMutex); - if (g_variant_n_children(discov_info) == 0) - { - return; - } - - /* - Read the data from dbus - */ - GAutoPtr dataValue; - GVariant * value; - - value = g_variant_lookup_value(discov_info, "subscribe_id", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &subscribe_id); - value = g_variant_lookup_value(discov_info, "publish_id", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &peer_publish_id); - - char addr_str[20]; - char * paddr; - value = g_variant_lookup_value(discov_info, "peer_addr", G_VARIANT_TYPE_STRING); - dataValue.reset(value); - g_variant_get(dataValue.get(), "&s", &paddr); - strncpy(addr_str, paddr, sizeof(addr_str)); - sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &peer_addr[0], &peer_addr[1], &peer_addr[2], &peer_addr[3], - &peer_addr[4], &peer_addr[5]); - - value = g_variant_lookup_value(discov_info, "srv_proto_type", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &srv_proto_type); - - // Read the ssi - size_t bufferLen; - value = g_variant_lookup_value(discov_info, "ssi", G_VARIANT_TYPE_BYTESTRING); - dataValue.reset(value); - auto ssibuf = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); - auto pPublishSSI = reinterpret_cast(ssibuf); - GetWiFiPAF()->SetWiFiPAFState(WiFiPAF::State::kConnected); - - /* - Error Checking - */ - WiFiPAFSession sessionInfo = { .discriminator = pPublishSSI->DevInfo }; - WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); - auto pPafInfo = WiFiPafLayer.GetPAFInfo(PafInfoAccess::kAccDisc, sessionInfo); - if (pPafInfo == nullptr) - { - ChipLogError(DeviceLayer, "WiFi-PAF: DiscoveryResult, no valid session with discriminator: %u", pPublishSSI->DevInfo); - return; - } - if ((pPafInfo->id == subscribe_id) && (pPafInfo->peer_id != UINT32_MAX)) - { - // Reentrance, depends on wpa_supplicant behaviors - ChipLogError(DeviceLayer, "WiFi-PAF: DiscoveryResult, reentrance, subscribe_id: %u ", subscribe_id); - return; - } - if (srv_proto_type != nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER) - { - ChipLogError(DeviceLayer, "WiFi-PAF: DiscoveryResult, Incorrect Protocol Type: %u, exp: %u", srv_proto_type, - nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER); - return; - } - - /* - Set the PAF session information - */ - ChipLogProgress(DeviceLayer, "WiFi-PAF: DiscoveryResult, set PafInfo, whose nodeId: %lu", pPafInfo->nodeId); - ChipLogProgress(DeviceLayer, "\t (subscribe_id, peer_publish_id): (%u, %u)", subscribe_id, peer_publish_id); - ChipLogProgress(DeviceLayer, "\t peer_addr: [%02x:%02x:%02x:%02x:%02x:%02x]", peer_addr[0], peer_addr[1], peer_addr[2], - peer_addr[3], peer_addr[4], peer_addr[5]); - ChipLogProgress(DeviceLayer, "\t DevInfo: %x", pPublishSSI->DevInfo); - - pPafInfo->role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber; - pPafInfo->id = subscribe_id; - pPafInfo->peer_id = peer_publish_id; - memcpy(pPafInfo->peer_addr, peer_addr, sizeof(uint8_t) * 6); - /* - Indicate the connection event - */ - ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFConnected }; - memcpy(&event.CHIPoWiFiPAFReceived.SessionInfo, pPafInfo, sizeof(chip::WiFiPAF::WiFiPAFSession)); - PlatformMgr().PostEventOrDie(&event); -} - -void ConnectivityManagerImpl::OnReplied(GVariant * reply_info) -{ - ChipLogProgress(Controller, "WiFi-PAF: OnReplied"); - uint32_t publish_id; - uint32_t peer_subscribe_id; - uint8_t peer_addr[6]; - uint32_t srv_proto_type; - - std::lock_guard lock(mWpaSupplicantMutex); - if (g_variant_n_children(reply_info) == 0) - { - return; - } - - /* - Read the data from dbus - */ - GAutoPtr dataValue; - GVariant * value; - - value = g_variant_lookup_value(reply_info, "publish_id", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &publish_id); - value = g_variant_lookup_value(reply_info, "subscribe_id", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &peer_subscribe_id); - - char addr_str[20]; - char * paddr; - value = g_variant_lookup_value(reply_info, "peer_addr", G_VARIANT_TYPE_STRING); - dataValue.reset(value); - g_variant_get(dataValue.get(), "&s", &paddr); - strncpy(addr_str, paddr, sizeof(addr_str)); - sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &peer_addr[0], &peer_addr[1], &peer_addr[2], &peer_addr[3], - &peer_addr[4], &peer_addr[5]); - - value = g_variant_lookup_value(reply_info, "srv_proto_type", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &srv_proto_type); - - // Read the ssi - size_t bufferLen; - value = g_variant_lookup_value(reply_info, "ssi", G_VARIANT_TYPE_BYTESTRING); - dataValue.reset(value); - auto ssibuf = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); - auto pPublishSSI = reinterpret_cast(ssibuf); - - /* - Error Checking - */ - uint16_t SetupDiscriminator; - DeviceLayer::GetCommissionableDataProvider()->GetSetupDiscriminator(SetupDiscriminator); - if ((pPublishSSI->DevInfo != SetupDiscriminator) || (srv_proto_type != nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER)) - { - ChipLogProgress(DeviceLayer, "WiFi-PAF: OnReplied, mismatched discriminator, got %u, ours: %u", pPublishSSI->DevInfo, - SetupDiscriminator); - return; - } - WiFiPAFSession sessionInfo = { .id = publish_id }; - WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); - auto pPafInfo = WiFiPafLayer.GetPAFInfo(PafInfoAccess::kAccSessionId, sessionInfo); - if (pPafInfo == nullptr) - { - ChipLogError(DeviceLayer, "WiFi-PAF: OnReplied, no valid session with publish_id: %d", publish_id); - return; - } - if ((pPafInfo->role == WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher) && (pPafInfo->peer_id == peer_subscribe_id) && - !memcmp(pPafInfo->peer_addr, peer_addr, sizeof(uint8_t) * 6)) - { - ChipLogError(DeviceLayer, "WiFi-PAF: OnReplied, reentrance, publish_id: %u ", publish_id); - return; - } - /* - Set the PAF session information - */ - ChipLogProgress(DeviceLayer, "WiFi-PAF: OnReplied, set PafInfo, whose nodeId: %lu", pPafInfo->nodeId); - ChipLogProgress(DeviceLayer, "\t (publish_id, peer_subscribe_id): (%u, %u)", publish_id, peer_subscribe_id); - ChipLogProgress(DeviceLayer, "\t peer_addr: [%02x:%02x:%02x:%02x:%02x:%02x]", peer_addr[0], peer_addr[1], peer_addr[2], - peer_addr[3], peer_addr[4], peer_addr[5]); - ChipLogProgress(DeviceLayer, "\t DevInfo: %x", pPublishSSI->DevInfo); - - pPafInfo->role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher; - pPafInfo->id = publish_id; - pPafInfo->peer_id = peer_subscribe_id; - memcpy(pPafInfo->peer_addr, peer_addr, sizeof(uint8_t) * 6); - WiFiPafLayer.HandleTransportConnectionInitiated(*pPafInfo); -} - -void ConnectivityManagerImpl::OnNanReceive(GVariant * obj) -{ - if (g_variant_n_children(obj) == 0) - { - return; - } - // Read the rx_info - WiFiPAF::WiFiPAFSession RxInfo; - GAutoPtr dataValue; - GVariant * value; - value = g_variant_lookup_value(obj, "id", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &RxInfo.id); - - value = g_variant_lookup_value(obj, "peer_id", G_VARIANT_TYPE_UINT32); - dataValue.reset(value); - g_variant_get(dataValue.get(), "u", &RxInfo.peer_id); - - char addr_str[20]; - char * paddr; - value = g_variant_lookup_value(obj, "peer_addr", G_VARIANT_TYPE_STRING); - dataValue.reset(value); - g_variant_get(dataValue.get(), "&s", &paddr); - strncpy(addr_str, paddr, sizeof(addr_str)); - sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &RxInfo.peer_addr[0], &RxInfo.peer_addr[1], &RxInfo.peer_addr[2], - &RxInfo.peer_addr[3], &RxInfo.peer_addr[4], &RxInfo.peer_addr[5]); - - // Read the rx_data - size_t bufferLen; - System::PacketBufferHandle buf; - - value = g_variant_lookup_value(obj, "ssi", G_VARIANT_TYPE_BYTESTRING); - dataValue.reset(value); - - auto rxbuf = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); - ChipLogProgress(DeviceLayer, "WiFi-PAF: wpa_supplicant: nan-rx: [len: %lu]", bufferLen); - buf = System::PacketBufferHandle::NewWithData(rxbuf, bufferLen); - - // Post an event to the Chip queue to deliver the data into the Chip stack. - ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFReceived, - .CHIPoWiFiPAFReceived = { .Data = std::move(buf).UnsafeRelease() } }; - memcpy(&event.CHIPoWiFiPAFReceived.SessionInfo, &RxInfo, sizeof(WiFiPAF::WiFiPAFSession)); - PlatformMgr().PostEventOrDie(&event); -} - -void ConnectivityManagerImpl::OnNanPublishTerminated(guint public_id, gchar * reason) -{ - ChipLogProgress(Controller, "WiFi-PAF: Publish terminated (%u, %s)", public_id, reason); - WiFiPAFSession sessionInfo = { .id = public_id }; - WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); - WiFiPafLayer.RmPafSession(PafInfoAccess::kAccSessionId, sessionInfo); -} - -void ConnectivityManagerImpl::OnNanSubscribeTerminated(guint subscribe_id, gchar * reason) -{ - ChipLogProgress(Controller, "WiFi-PAF: Subscription terminated (%u, %s)", subscribe_id, reason); - WiFiPAFSession sessionInfo = { .id = subscribe_id }; - WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); - WiFiPafLayer.RmPafSession(PafInfoAccess::kAccSessionId, sessionInfo); - /* - Indicate the connection event - */ - ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFCancelConnect }; - PlatformMgr().PostEventOrDie(&event); -} +#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFSubscribe(const uint16_t & connDiscriminator, void * appState, OnConnectionCompleteFunct onSuccess, OnConnectionErrorFunct onError) { +#if !CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_HOSTAPD CHIP_ERROR result = StartWiFiManagementSync(); VerifyOrReturnError(result == CHIP_NO_ERROR, result); +#endif - ChipLogProgress(Controller, "WiFi-PAF: Try to subscribe the NAN-USD devices"); - - guint subscribe_id; - GAutoPtr err; - enum nan_service_protocol_type srv_proto_type = nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER; - uint8_t is_active = 1; - unsigned int ttl = CHIP_DEVICE_CONFIG_WIFIPAF_DISCOVERY_TIMEOUT_SECS; - unsigned int freq = (mApFreq == 0) ? CHIP_DEVICE_CONFIG_WIFIPAF_24G_DEFAUTL_CHNL : mApFreq; - unsigned int ssi_len = sizeof(struct PAFPublishSSI); - struct PAFPublishSSI PafPublish_ssi; - - mAppState = appState; - PafPublish_ssi.DevOpCode = 0; - PafPublish_ssi.DevInfo = connDiscriminator; - if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(PafPublish_ssi.ProductId) != CHIP_NO_ERROR) - { - PafPublish_ssi.ProductId = 0; - } - if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(PafPublish_ssi.VendorId) != CHIP_NO_ERROR) - { - PafPublish_ssi.VendorId = 0; - } - GVariant * ssi_array_variant = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &PafPublish_ssi, ssi_len, sizeof(guint8)); - if (ssi_array_variant == nullptr) + if (mWiFiPAFDriver == nullptr) { - ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL "); - return CHIP_ERROR_INTERNAL; +#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_CTRL_IFACE + mWiFiPAFDriver = std::make_unique(); +#else + mWiFiPAFDriver = std::make_unique(&mWpaSupplicant, &mWpaSupplicantMutex); +#endif + mWiFiPAFDriver->Initialize(); } - std::lock_guard lock(mWpaSupplicantMutex); - GVariantBuilder builder; - GVariant * args = nullptr; - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add(&builder, "{sv}", "srv_name", g_variant_new_string(srv_name)); - g_variant_builder_add(&builder, "{sv}", "srv_proto_type", g_variant_new_byte(srv_proto_type)); - g_variant_builder_add(&builder, "{sv}", "active", g_variant_new_boolean(is_active)); - g_variant_builder_add(&builder, "{sv}", "ttl", g_variant_new_uint16(ttl)); - g_variant_builder_add(&builder, "{sv}", "freq", g_variant_new_uint16(freq)); - g_variant_builder_add(&builder, "{sv}", "ssi", ssi_array_variant); - args = g_variant_builder_end(&builder); - wpa_supplicant_1_interface_call_nansubscribe_sync(mWpaSupplicant.iface.get(), args, &subscribe_id, nullptr, &err.GetReceiver()); - - ChipLogProgress(DeviceLayer, "WiFi-PAF: subscribe_id: [%u], freq: %u", subscribe_id, freq); + mAppState = appState; mOnPafSubscribeComplete = onSuccess; mOnPafSubscribeError = onError; - WiFiPAFSession sessionInfo = { .discriminator = PafPublish_ssi.DevInfo }; - WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); - auto pPafInfo = WiFiPafLayer.GetPAFInfo(PafInfoAccess::kAccDisc, sessionInfo); - if (pPafInfo != nullptr) - { - pPafInfo->id = subscribe_id; - pPafInfo->role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber; - } - - g_signal_connect(mWpaSupplicant.iface.get(), "nandiscovery-result", - G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, ConnectivityManagerImpl * self) { - return self->OnDiscoveryResult(obj); - }), - this); - - g_signal_connect(mWpaSupplicant.iface.get(), "nanreceive", - G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, ConnectivityManagerImpl * self) { - return self->OnNanReceive(obj); - }), - this); - - g_signal_connect( - mWpaSupplicant.iface.get(), "nansubscribe-terminated", - G_CALLBACK(+[](WpaSupplicant1Interface * proxy, guint term_subscribe_id, gchar * reason, ConnectivityManagerImpl * self) { - return self->OnNanSubscribeTerminated(term_subscribe_id, reason); - }), - this); - - return CHIP_NO_ERROR; + return mWiFiPAFDriver->Subscribe(connDiscriminator, mApFreq); } CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFCancelSubscribe(uint32_t SubscribeId) { - GAutoPtr err; - - ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel subscribe_id: %d ! ", SubscribeId); - std::lock_guard lock(mWpaSupplicantMutex); - wpa_supplicant_1_interface_call_nancancel_subscribe_sync(mWpaSupplicant.iface.get(), SubscribeId, nullptr, &err.GetReceiver()); + if (mWiFiPAFDriver != nullptr) + { + return mWiFiPAFDriver->CancelSubscribe(SubscribeId); + } return CHIP_NO_ERROR; } @@ -1588,78 +1193,20 @@ CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFCancelIncompleteSubscribe() CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFSend(const WiFiPAF::WiFiPAFSession & TxInfo, System::PacketBufferHandle && msgBuf) { - ChipLogProgress(Controller, "WiFi-PAF: sending PAF Follow-up packets, (%lu)", msgBuf->DataLength()); - CHIP_ERROR ret = CHIP_NO_ERROR; - - if (msgBuf.IsNull()) - { - ChipLogError(Controller, "WiFi-PAF: Invalid Packet (%lu)", msgBuf->DataLength()); - return CHIP_ERROR_INVALID_ARGUMENT; - } - - // Ensure outgoing message fits in a single contiguous packet buffer, as currently required by the - // message fragmentation and reassembly engine. - if (msgBuf->HasChainedBuffer()) - { - msgBuf->CompactHead(); - - if (msgBuf->HasChainedBuffer()) - { - ret = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG; - ChipLogError(Controller, "WiFi-PAF: Outbound message too big (%lu), skip temporally", msgBuf->DataLength()); - return ret; - } - } - - // Send the packets - GAutoPtr err; - gchar peer_mac[18]; - - snprintf(peer_mac, sizeof(peer_mac), "%02x:%02x:%02x:%02x:%02x:%02x", TxInfo.peer_addr[0], TxInfo.peer_addr[1], - TxInfo.peer_addr[2], TxInfo.peer_addr[3], TxInfo.peer_addr[4], TxInfo.peer_addr[5]); - GVariant * ssi_array_variant = - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, msgBuf->Start(), msgBuf->DataLength(), sizeof(guint8)); - if (ssi_array_variant == nullptr) - { - ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL "); - return CHIP_ERROR_INTERNAL; - } - std::lock_guard lock(mWpaSupplicantMutex); - - GVariantBuilder builder; - GVariant * args = nullptr; - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add(&builder, "{sv}", "handle", g_variant_new_uint32(TxInfo.id)); - g_variant_builder_add(&builder, "{sv}", "req_instance_id", g_variant_new_uint32(TxInfo.peer_id)); - g_variant_builder_add(&builder, "{sv}", "peer_addr", g_variant_new_string(peer_mac)); - g_variant_builder_add(&builder, "{sv}", "ssi", ssi_array_variant); - args = g_variant_builder_end(&builder); - gboolean result = - wpa_supplicant_1_interface_call_nantransmit_sync(mWpaSupplicant.iface.get(), args, nullptr, &err.GetReceiver()); - if (!result) + if (mWiFiPAFDriver != nullptr) { - ChipLogError(DeviceLayer, "WiFi-PAF: Failed to send message: %s", err == nullptr ? "unknown error" : err->message); + return mWiFiPAFDriver->Send(TxInfo, std::move(msgBuf)); } - ChipLogProgress(Controller, "WiFi-PAF: Outbound message (%lu) done", msgBuf->DataLength()); - - // Post an event to the Chip queue to deliver the data into the Chip stack. - ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFWriteDone }; - memcpy(&event.CHIPoWiFiPAFReceived.SessionInfo, &TxInfo, sizeof(chip::WiFiPAF::WiFiPAFSession)); - event.CHIPoWiFiPAFReceived.result = result; - PlatformMgr().PostEventOrDie(&event); - return ret; + return CHIP_NO_ERROR; } CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFShutdown(uint32_t id, WiFiPAF::WiFiPafRole role) { - switch (role) + if (mWiFiPAFDriver != nullptr) { - case WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher: - return _WiFiPAFCancelPublish(id); - case WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber: - return _WiFiPAFCancelSubscribe(id); + return mWiFiPAFDriver->Shutdown(id, role); } - return CHIP_ERROR_INTERNAL; + return CHIP_NO_ERROR; } #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF diff --git a/src/platform/Linux/ConnectivityManagerImpl.h b/src/platform/Linux/ConnectivityManagerImpl.h index e3d8d952a60700..96fb79a8192227 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.h +++ b/src/platform/Linux/ConnectivityManagerImpl.h @@ -41,15 +41,12 @@ #endif #if CHIP_DEVICE_CONFIG_ENABLE_WPA -#include -#include -#include -#include -#include +#include #include #include #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF +#include #include #include #endif @@ -60,47 +57,8 @@ #include namespace chip { - -#if CHIP_DEVICE_CONFIG_ENABLE_WPA - -template <> -struct GAutoPtrDeleter -{ - using deleter = GObjectDeleter; -}; - -template <> -struct GAutoPtrDeleter -{ - using deleter = GObjectDeleter; -}; - -template <> -struct GAutoPtrDeleter -{ - using deleter = GObjectDeleter; -}; - -template <> -struct GAutoPtrDeleter -{ - using deleter = GObjectDeleter; -}; - -#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA - namespace DeviceLayer { -#if CHIP_DEVICE_CONFIG_ENABLE_WPA -struct GDBusWpaSupplicant -{ - GAutoPtr proxy; - GAutoPtr iface; - GAutoPtr interfacePath; - GAutoPtr networkPath; -}; -#endif - /** * Concrete implementation of the ConnectivityManager singleton object for Linux platforms. */ @@ -144,11 +102,6 @@ class ConnectivityManagerImpl final : public ConnectivityManager, OnConnectionErrorFunct onError); CHIP_ERROR _WiFiPAFCancelSubscribe(uint32_t SubscribeId); CHIP_ERROR _WiFiPAFCancelIncompleteSubscribe(); - void OnDiscoveryResult(GVariant * obj); - void OnReplied(GVariant * obj); - void OnNanReceive(GVariant * obj); - void OnNanPublishTerminated(guint public_id, gchar * reason); - void OnNanSubscribeTerminated(guint subscribe_id, gchar * reason); CHIP_ERROR _WiFiPAFSend(const WiFiPAF::WiFiPAFSession & TxInfo, chip::System::PacketBufferHandle && msgBuf); void _WiFiPafSetApFreq(const uint16_t freq) { mApFreq = freq; } CHIP_ERROR _WiFiPAFShutdown(uint32_t id, WiFiPAF::WiFiPafRole role); @@ -249,6 +202,7 @@ class ConnectivityManagerImpl final : public ConnectivityManager, bool _WiFiPAFResourceAvailable() { return mPafChannelAvailable; }; // The resource checking is needed right before sending data packets that they are initialized and connected. bool mPafChannelAvailable = true; + std::unique_ptr mWiFiPAFDriver; #endif bool _GetBssInfo(const gchar * bssPath, NetworkCommissioning::WiFiScanResponse & result); diff --git a/src/platform/Linux/WiFiPAFDriver.cpp b/src/platform/Linux/WiFiPAFDriver.cpp new file mode 100644 index 00000000000000..7432c7195fc4ac --- /dev/null +++ b/src/platform/Linux/WiFiPAFDriver.cpp @@ -0,0 +1,246 @@ +/* + * + * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * Copyright (c) 2025 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#include +#include +#include +#endif + +#include +#include + +using namespace ::chip::DeviceLayer; +using namespace ::chip::WiFiPAF; + +namespace chip { +namespace DeviceLayer { + +PAFPublishSSI WiFiPAFDriver::BuildSSI() +{ + PAFPublishSSI PafPublish_ssi; + + PafPublish_ssi.DevOpCode = 0; + if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(PafPublish_ssi.ProductId) != CHIP_NO_ERROR) + { + PafPublish_ssi.ProductId = 0; + } + if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(PafPublish_ssi.VendorId) != CHIP_NO_ERROR) + { + PafPublish_ssi.VendorId = 0; + } + + return PafPublish_ssi; +} + +CHIP_ERROR WiFiPAFDriver::_Publish(uint32_t publish_id) +{ + WiFiPAFSession sessionInfo = { .role = WiFiPafRole::kWiFiPafRole_Publisher, .id = publish_id }; + WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); + ReturnErrorOnFailure(WiFiPafLayer.AddPafSession(PafInfoAccess::kAccSessionId, sessionInfo)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiPAFDriver::_Subscribe(uint32_t subscribe_id, uint16_t discriminator) +{ + WiFiPAFSession sessionInfo = { .discriminator = discriminator }; + WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); + auto pPafInfo = WiFiPafLayer.GetPAFInfo(PafInfoAccess::kAccDisc, sessionInfo); + if (pPafInfo != nullptr) + { + pPafInfo->id = subscribe_id; + pPafInfo->role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber; + } + return CHIP_NO_ERROR; +} + +void WiFiPAFDriver::_OnDiscoveryResult(uint32_t subscribe_id, uint32_t peer_publish_id, uint32_t srv_proto_type, + std::array peer_addr, const PAFPublishSSI * pPublishSSI) +{ + DeviceLayer::ConnectivityMgr().GetWiFiPAF()->SetWiFiPAFState(WiFiPAF::State::kConnected); + + /* + Error Checking + */ + WiFiPAFSession sessionInfo = { .discriminator = pPublishSSI->DevInfo }; + WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); + auto pPafInfo = WiFiPafLayer.GetPAFInfo(PafInfoAccess::kAccDisc, sessionInfo); + if (pPafInfo == nullptr) + { + ChipLogError(DeviceLayer, "WiFi-PAF: DiscoveryResult, no valid session with discriminator: %u", pPublishSSI->DevInfo); + return; + } + if ((pPafInfo->id == subscribe_id) && (pPafInfo->peer_id != UINT32_MAX)) + { + // Reentrance, depends on wpa_supplicant behaviors + ChipLogError(DeviceLayer, "WiFi-PAF: DiscoveryResult, reentrance, subscribe_id: %u ", subscribe_id); + return; + } + if (srv_proto_type != nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER) + { + ChipLogError(DeviceLayer, "WiFi-PAF: DiscoveryResult, Incorrect Protocol Type: %u, exp: %u", srv_proto_type, + nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER); + return; + } + + /* + Set the PAF session information + */ + ChipLogProgress(DeviceLayer, "WiFi-PAF: DiscoveryResult, set PafInfo, whose nodeId: %lu", pPafInfo->nodeId); + ChipLogProgress(DeviceLayer, "\t (subscribe_id, peer_publish_id): (%u, %u)", subscribe_id, peer_publish_id); + ChipLogProgress(DeviceLayer, "\t peer_addr: [%02x:%02x:%02x:%02x:%02x:%02x]", peer_addr[0], peer_addr[1], peer_addr[2], + peer_addr[3], peer_addr[4], peer_addr[5]); + ChipLogProgress(DeviceLayer, "\t DevInfo: %x", pPublishSSI->DevInfo); + + pPafInfo->role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber; + pPafInfo->id = subscribe_id; + pPafInfo->peer_id = peer_publish_id; + memcpy(pPafInfo->peer_addr, peer_addr.data(), sizeof(uint8_t) * 6); + /* + Indicate the connection event + */ + ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFConnected }; + memcpy(&event.CHIPoWiFiPAFReceived.SessionInfo, pPafInfo, sizeof(chip::WiFiPAF::WiFiPAFSession)); + PlatformMgr().PostEventOrDie(&event); +} + +void WiFiPAFDriver::_OnReplied(uint32_t peer_subscribe_id, uint32_t publish_id, uint32_t srv_proto_type, + std::array peer_addr, const PAFPublishSSI * pPublishSSI) +{ + /* + Error Checking + */ + uint16_t SetupDiscriminator; + DeviceLayer::GetCommissionableDataProvider()->GetSetupDiscriminator(SetupDiscriminator); + if ((pPublishSSI->DevInfo != SetupDiscriminator) || (srv_proto_type != nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER)) + { + ChipLogProgress(DeviceLayer, "WiFi-PAF: OnReplied, mismatched discriminator, got %u, ours: %u", pPublishSSI->DevInfo, + SetupDiscriminator); + return; + } + WiFiPAFSession sessionInfo = { .id = publish_id }; + WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); + auto pPafInfo = WiFiPafLayer.GetPAFInfo(PafInfoAccess::kAccSessionId, sessionInfo); + if (pPafInfo == nullptr) + { + ChipLogError(DeviceLayer, "WiFi-PAF: OnReplied, no valid session with publish_id: %d", publish_id); + return; + } + if ((pPafInfo->role == WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher) && (pPafInfo->peer_id == peer_subscribe_id) && + !memcmp(pPafInfo->peer_addr, peer_addr.data(), sizeof(uint8_t) * 6)) + { + ChipLogError(DeviceLayer, "WiFi-PAF: OnReplied, reentrance, publish_id: %u ", publish_id); + return; + } + /* + Set the PAF session information + */ + ChipLogProgress(DeviceLayer, "WiFi-PAF: OnReplied, set PafInfo, whose nodeId: %lu", pPafInfo->nodeId); + ChipLogProgress(DeviceLayer, "\t (publish_id, peer_subscribe_id): (%u, %u)", publish_id, peer_subscribe_id); + ChipLogProgress(DeviceLayer, "\t peer_addr: [%02x:%02x:%02x:%02x:%02x:%02x]", peer_addr[0], peer_addr[1], peer_addr[2], + peer_addr[3], peer_addr[4], peer_addr[5]); + ChipLogProgress(DeviceLayer, "\t DevInfo: %x", pPublishSSI->DevInfo); + + pPafInfo->role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher; + pPafInfo->id = publish_id; + pPafInfo->peer_id = peer_subscribe_id; + memcpy(pPafInfo->peer_addr, peer_addr.data(), sizeof(uint8_t) * 6); + WiFiPafLayer.HandleTransportConnectionInitiated(*pPafInfo); +} + +void WiFiPAFDriver::_OnNanReceive(const WiFiPAF::WiFiPAFSession & rxInfo, System::PacketBufferHandle rxData) +{ + ChipLogProgress(DeviceLayer, "WiFi-PAF: wpa_supplicant: nan-rx: [len: %lu]", rxData->DataLength()); + + // Post an event to the Chip queue to deliver the data into the Chip stack. + ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFReceived, + .CHIPoWiFiPAFReceived = { .Data = std::move(rxData).UnsafeRelease() } }; + memcpy(&event.CHIPoWiFiPAFReceived.SessionInfo, &rxInfo, sizeof(WiFiPAF::WiFiPAFSession)); + PlatformMgr().PostEventOrDie(&event); +} + +void WiFiPAFDriver::_OnNanPublishTerminated(uint32_t publish_id, const char * reason) +{ + ChipLogProgress(Controller, "WiFi-PAF: Publish terminated (%u, %s)", publish_id, reason); + + WiFiPAFSession sessionInfo = { .id = publish_id }; + WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); + WiFiPafLayer.RmPafSession(PafInfoAccess::kAccSessionId, sessionInfo); +} + +void WiFiPAFDriver::_OnNanSubscribeTerminated(uint32_t subscribe_id, const char * reason) +{ + ChipLogProgress(Controller, "WiFi-PAF: Subscription terminated (%u, %s)", subscribe_id, reason); + WiFiPAFSession sessionInfo = { .id = subscribe_id }; + WiFiPAFLayer & WiFiPafLayer = WiFiPAFLayer::GetWiFiPAFLayer(); + WiFiPafLayer.RmPafSession(PafInfoAccess::kAccSessionId, sessionInfo); + /* + Indicate the connection event + */ + ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFCancelConnect }; + PlatformMgr().PostEventOrDie(&event); +} + +CHIP_ERROR WiFiPAFDriver::_Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role) +{ + switch (role) + { + case WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher: + return CancelPublish(id); + case WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber: + return CancelSubscribe(id); + } + return CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR WiFiPAFDriver::_Send(const WiFiPAF::WiFiPAFSession & TxInfo, bool result) +{ + // Post an event to the Chip queue to deliver the data into the Chip stack. + ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFWriteDone }; + memcpy(&event.CHIPoWiFiPAFReceived.SessionInfo, &TxInfo, sizeof(chip::WiFiPAF::WiFiPAFSession)); + event.CHIPoWiFiPAFReceived.result = result; + PlatformMgr().PostEventOrDie(&event); + return CHIP_NO_ERROR; +} +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Linux/WiFiPAFDriver.h b/src/platform/Linux/WiFiPAFDriver.h new file mode 100644 index 00000000000000..1ee322b33c88ab --- /dev/null +++ b/src/platform/Linux/WiFiPAFDriver.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace DeviceLayer { + +const char srv_name[] = "_matterc._udp"; +/* + NAN-USD Service Protocol Type: ref: Table 58 of Wi-Fi Aware Specificaiton +*/ +#define NAN_PUBLISH_SSI_TAG " ssi=" + +#pragma pack(push, 1) +struct PAFPublishSSI +{ + uint8_t DevOpCode; + uint16_t DevInfo; + uint16_t ProductId; + uint16_t VendorId; +}; + +enum nan_service_protocol_type +{ + NAN_SRV_PROTO_BONJOUR = 1, + NAN_SRV_PROTO_GENERIC = 2, + NAN_SRV_PROTO_CSA_MATTER = 3, +}; +#pragma pack(pop) + +class WiFiPAFDriver +{ +public: + virtual ~WiFiPAFDriver() {} + virtual CHIP_ERROR Initialize() = 0; + virtual CHIP_ERROR Publish(std::unique_ptr freq_list, uint16_t freq_list_len) = 0; + virtual CHIP_ERROR CancelPublish(uint32_t PublishId) = 0; + virtual CHIP_ERROR Subscribe(const uint16_t & connDiscriminator, uint16_t mApFreq) = 0; + virtual CHIP_ERROR CancelSubscribe(uint32_t SubscribeId) = 0; + virtual CHIP_ERROR Send(const WiFiPAF::WiFiPAFSession & TxInfo, chip::System::PacketBufferHandle && msgBuf) = 0; + virtual CHIP_ERROR Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role) = 0; + +protected: + static PAFPublishSSI BuildSSI(); + CHIP_ERROR _Publish(uint32_t publish_id); + CHIP_ERROR _Subscribe(uint32_t subscribe_id, uint16_t discriminator); + void _OnDiscoveryResult(uint32_t subscribe_id, uint32_t peer_publish_id, uint32_t srv_proto_type, + std::array peer_addr, const PAFPublishSSI * pPublishSSI); + void _OnReplied(uint32_t peer_subscribe_id, uint32_t publish_id, uint32_t srv_proto_type, std::array peer_addr, + const PAFPublishSSI * pPublishSSI); + void _OnNanReceive(const WiFiPAF::WiFiPAFSession & rxInfo, System::PacketBufferHandle rxData); + void _OnNanPublishTerminated(uint32_t publish_id, const char * reason); + void _OnNanSubscribeTerminated(uint32_t subscribe_id, const char * reason); + CHIP_ERROR _Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role); + CHIP_ERROR _Send(const WiFiPAF::WiFiPAFSession & TxInfo, bool result); +}; +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Linux/WiFiPAFDriverCtrlIface.cpp b/src/platform/Linux/WiFiPAFDriverCtrlIface.cpp new file mode 100644 index 00000000000000..824341633d7f88 --- /dev/null +++ b/src/platform/Linux/WiFiPAFDriverCtrlIface.cpp @@ -0,0 +1,516 @@ +/* + * + * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * Copyright (c) 2025 NXP + * Copyright (c) 2025 Cable Television Laboratories, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern "C" { +#include "wpa_ctrl.h" +} + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#include +#include +#include +#endif + +#include +#include +#include + +using namespace ::chip::DeviceLayer; +using namespace ::chip::WiFiPAF; + +namespace chip { +namespace DeviceLayer { + +CHIP_ERROR StringToUInt32(std::string input, uint32_t & output) +{ + auto [ptr, ec] = std::from_chars(input.data(), input.data() + input.size(), output); + + if (ec != std::errc()) + { + ChipLogError(DeviceLayer, "Error converting std::string %s to uint32_t", input.c_str()); + return CHIP_ERROR_INTERNAL; + } + return CHIP_NO_ERROR; +} + +std::string GetEventType(const std::string & reply) +{ + auto pos = reply.find('>'); + if (pos == std::string::npos) + { + return ""; + } + + auto space = reply.find(' ', pos + 1); + + std::string event; + if (space == std::string::npos) + { + event = reply.substr(pos + 1); + } + else + { + event = reply.substr(pos + 1, space - (pos + 1)); + } + + return event; +} + +std::unordered_map GetKeyValueFromWpaCtrlReply(const std::string & reply) +{ + std::regex re(R"((\w+)=([^\s]+))"); + std::smatch match; + + std::unordered_map kv; + + auto begin = std::sregex_iterator(reply.begin(), reply.end(), re); + auto end = std::sregex_iterator(); + + for (auto it = begin; it != end; ++it) + { + kv[(*it)[1]] = (*it)[2]; + } + + return kv; +} + +gboolean WiFiPAFDriverCtrlIface::OnWiFiManagerFdActivity(GIOChannel * source, GIOCondition condition, gpointer data) +{ + ChipLogProgress(DeviceLayer, "Activity on WiFiPAFDriver file descriptor"); + + auto self = static_cast(data); + + while (wpa_ctrl_pending(self->ctrl) != 0) + { + char reply[4096]; + size_t reply_len = sizeof(reply); + if (wpa_ctrl_recv(self->ctrl, reply, &reply_len) != 0) + { + ChipLogProgress(DeviceLayer, "Error on wpa_ctrl_recv"); + continue; + } + auto reply_str = std::string(reply, reply_len); + ChipLogProgress(DeviceLayer, "Received: %s", reply_str.c_str()); + + auto event_str = GetEventType(reply_str); + if ("NAN-DISCOVERY-RESULT" == event_str) + { + self->OnDiscoveryResult(GetKeyValueFromWpaCtrlReply(reply_str)); + } + else if ("NAN-REPLIED" == event_str) + { + self->OnReplied(GetKeyValueFromWpaCtrlReply(reply_str)); + } + else if ("NAN-RECEIVE" == event_str) + { + self->OnNanReceive(GetKeyValueFromWpaCtrlReply(reply_str)); + } + else if ("NAN-PUBLISH-TERMINATED" == event_str) + { + self->OnNanPublishTerminated(GetKeyValueFromWpaCtrlReply(reply_str)); + } + else if ("NAN-SUBSCRIBE-TERMINATED" == event_str) + { + self->OnNanSubscribeTerminated(GetKeyValueFromWpaCtrlReply(reply_str)); + } + else + { + ChipLogProgress(Controller, "Unknown wpa_ctrl event: %s", event_str.c_str()); + } + } + return TRUE; +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::Initialize() +{ + ChipLogProgress(DeviceLayer, "Using iface path: %s", kCtrlIfacePath.c_str()); + ctrl = wpa_ctrl_open(kCtrlIfacePath.c_str()); + + auto fd = wpa_ctrl_get_fd(ctrl); + GIOChannel * ch = g_io_channel_unix_new(fd); + GSource * watchSource = g_io_create_watch(ch, G_IO_IN); + g_source_set_callback(watchSource, G_SOURCE_FUNC(OnWiFiManagerFdActivity), (gpointer) this, nullptr); + g_io_channel_set_close_on_unref(ch, TRUE); + g_io_channel_set_encoding(ch, nullptr, nullptr); + PlatformMgrImpl().GLibMatterContextAttachSource(watchSource); + + gio_channel = ch; + gsource = watchSource; + + if (wpa_ctrl_attach(ctrl) != 0) + { + ChipLogProgress(DeviceLayer, "Error attaching to control interface"); + return CHIP_ERROR_INTERNAL; + } + + cmd_ctrl = wpa_ctrl_open(kCtrlIfacePath.c_str()); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::Publish(std::unique_ptr freq_list, uint16_t freq_list_len) +{ + enum nan_service_protocol_type srv_proto_type = nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER; + unsigned int ttl = CHIP_DEVICE_CONFIG_WIFIPAF_MAX_ADVERTISING_TIMEOUT_SECS; + unsigned int freq = CHIP_DEVICE_CONFIG_WIFIPAF_24G_DEFAUTL_CHNL; + + // Construct the SSI + PAFPublishSSI PafPublish_ssi = BuildSSI(); + VerifyOrDie(DeviceLayer::GetCommissionableDataProvider()->GetSetupDiscriminator(PafPublish_ssi.DevInfo) == CHIP_NO_ERROR); + + std::ostringstream oss; + oss << "NAN_PUBLISH " + << "srv_name=" << srv_name << " srv_proto_type=" << srv_proto_type << " ttl=" << ttl << " freq=" << freq + << " ssi=" << std::hex << std::setfill('0') // hex output, zero-padded + << std::setw(2) << static_cast(PafPublish_ssi.DevOpCode) << std::setw(4) << htons(PafPublish_ssi.DevInfo) + << std::setw(4) << htons(PafPublish_ssi.ProductId) << std::setw(4) << htons(PafPublish_ssi.VendorId) << " freq_list="; + + for (size_t i = 0; i < freq_list_len; ++i) + { + if (i > 0) + { + oss << ","; + } + oss << freq_list[i]; + } + + std::string cmd_str = oss.str(); + const char * cmd = cmd_str.c_str(); + size_t cmd_len = std::strlen(cmd); + + char reply[4096]; + size_t reply_len = sizeof(reply); + + std::lock_guard lock(mCtrlIfaceCmdMutex); + if (wpa_ctrl_request(cmd_ctrl, cmd, cmd_len, reply, &reply_len, nullptr) != 0) + { + ChipLogError(DeviceLayer, "WiFi-PAF: error sending NAN-PUBLISH"); + return CHIP_ERROR_INTERNAL; + } + + uint32_t publish_id; + ReturnErrorOnFailure(StringToUInt32(reply, publish_id)); + + ChipLogProgress(DeviceLayer, "WiFi-PAF: publish_id: [%u], freq: %u", publish_id, freq); + + CHIP_ERROR ret = _Publish(publish_id); + + return ret; +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::CancelPublish(uint32_t PublishId) +{ + ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel publish_id: %d ! ", PublishId); + + std::ostringstream oss; + oss << "NAN_CANCEL_PUBLISH id=" << PublishId; + std::string cmd_str = oss.str(); + const char * cmd = cmd_str.c_str(); + size_t cmd_len = std::strlen(cmd); + + char reply[4096]; + size_t reply_len = sizeof(reply); + + std::lock_guard lock(mCtrlIfaceCmdMutex); + if (wpa_ctrl_request(cmd_ctrl, cmd, cmd_len, reply, &reply_len, nullptr) != 0) + { + ChipLogError(DeviceLayer, "WiFi-PAF: Failed to send message"); + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +/* + NAN-USD Service Protocol Type: ref: Table 58 of Wi-Fi Aware Specificaiton +*/ +void WiFiPAFDriverCtrlIface::OnDiscoveryResult(std::unordered_map discov_info) +{ + ChipLogProgress(Controller, "WiFi-PAF: OnDiscoveryResult"); + + uint32_t subscribe_id; + uint32_t peer_publish_id; + uint32_t srv_proto_type; + + ReturnOnFailure(StringToUInt32(discov_info["subscribe_id"], subscribe_id)); + ReturnOnFailure(StringToUInt32(discov_info["publish_id"], peer_publish_id)); + ReturnOnFailure(StringToUInt32(discov_info["srv_proto_type"], srv_proto_type)); + + std::string peer_addr_str = discov_info["address"]; + uint8_t peer_addr[6]; + sscanf(peer_addr_str.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &peer_addr[0], &peer_addr[1], &peer_addr[2], &peer_addr[3], + &peer_addr[4], &peer_addr[5]); + std::array peer_addr_array = { peer_addr[0], peer_addr[1], peer_addr[2], peer_addr[3], peer_addr[4], peer_addr[5] }; + + std::string ssi_str = discov_info["ssi"]; + size_t ssi_buf_len = ssi_str.size() / 2; + std::vector ssi_buf; + ssi_buf.resize(ssi_buf_len); + if (chip::Encoding::HexToBytes(ssi_str.c_str(), ssi_str.size(), ssi_buf.data(), ssi_buf_len) != ssi_buf_len) + { + ChipLogError(DeviceLayer, "WiFi-PAF: error converting SSI to byte array"); + return; + } + auto pPublishSSI = reinterpret_cast(ssi_buf.data()); + + _OnDiscoveryResult(subscribe_id, peer_publish_id, srv_proto_type, peer_addr_array, pPublishSSI); +} + +void WiFiPAFDriverCtrlIface::OnReplied(std::unordered_map reply_info) +{ + ChipLogProgress(Controller, "WiFi-PAF: OnReplied"); + + uint32_t peer_subscribe_id; + uint32_t publish_id; + uint32_t srv_proto_type; + + ReturnOnFailure(StringToUInt32(reply_info["subscribe_id"], peer_subscribe_id)); + ReturnOnFailure(StringToUInt32(reply_info["publish_id"], publish_id)); + ReturnOnFailure(StringToUInt32(reply_info["srv_proto_type"], srv_proto_type)); + + std::string peer_addr_str = reply_info["address"]; + uint8_t peer_addr[6]; + sscanf(peer_addr_str.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &peer_addr[0], &peer_addr[1], &peer_addr[2], &peer_addr[3], + &peer_addr[4], &peer_addr[5]); + + std::string ssi_str = reply_info["ssi"]; + size_t ssi_buf_len = ssi_str.size() / 2; + std::vector ssi_buf; + ssi_buf.resize(ssi_buf_len); + if (chip::Encoding::HexToBytes(ssi_str.c_str(), ssi_str.size(), ssi_buf.data(), ssi_buf_len) != ssi_buf_len) + { + ChipLogError(DeviceLayer, "WiFi-PAF: error converting SSI to byte array"); + return; + } + auto pPublishSSI = reinterpret_cast(ssi_buf.data()); + + std::array peer_addr_array = { peer_addr[0], peer_addr[1], peer_addr[2], peer_addr[3], peer_addr[4], peer_addr[5] }; + + _OnReplied(peer_subscribe_id, publish_id, srv_proto_type, peer_addr_array, pPublishSSI); +} + +void WiFiPAFDriverCtrlIface::OnNanReceive(std::unordered_map received_data) +{ + ChipLogProgress(Controller, "WiFi-PAF: OnNanReceive"); + + WiFiPAF::WiFiPAFSession RxInfo; + ReturnOnFailure(StringToUInt32(received_data["id"], RxInfo.id)); + ReturnOnFailure(StringToUInt32(received_data["peer_instance_id"], RxInfo.peer_id)); + + std::string peer_addr_str = received_data["address"]; + sscanf(peer_addr_str.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &RxInfo.peer_addr[0], &RxInfo.peer_addr[1], &RxInfo.peer_addr[2], + &RxInfo.peer_addr[3], &RxInfo.peer_addr[4], &RxInfo.peer_addr[5]); + + std::string ssi_str = received_data["ssi"]; + size_t ssi_buf_len = ssi_str.size() / 2; + std::vector ssi_buf; + ssi_buf.resize(ssi_buf_len); + if (chip::Encoding::HexToBytes(ssi_str.c_str(), ssi_str.size(), ssi_buf.data(), ssi_buf_len) != ssi_buf_len) + { + ChipLogError(DeviceLayer, "WiFi-PAF: error converting SSI to byte array"); + return; + } + + System::PacketBufferHandle buf = System::PacketBufferHandle::NewWithData(ssi_buf.data(), ssi_buf_len); + + _OnNanReceive(RxInfo, std::move(buf)); +} + +void WiFiPAFDriverCtrlIface::OnNanPublishTerminated(std::unordered_map publish_terminated_data) +{ + uint32_t publish_id; + ReturnOnFailure(StringToUInt32(publish_terminated_data["publish_id"], publish_id)); + + _OnNanPublishTerminated(publish_id, publish_terminated_data["reason"].c_str()); +} + +void WiFiPAFDriverCtrlIface::OnNanSubscribeTerminated(std::unordered_map subscribe_terminated_data) +{ + uint32_t subscribe_id; + ReturnOnFailure(StringToUInt32(subscribe_terminated_data["subscribe_id"], subscribe_id)); + + _OnNanSubscribeTerminated(subscribe_id, subscribe_terminated_data["reason"].c_str()); +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::Subscribe(const uint16_t & connDiscriminator, uint16_t mApFreq) +{ + ChipLogProgress(Controller, "WiFi-PAF: Try to subscribe the NAN-USD devices"); + + enum nan_service_protocol_type srv_proto_type = nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER; + uint32_t is_active = 1; + unsigned int ttl = CHIP_DEVICE_CONFIG_WIFIPAF_DISCOVERY_TIMEOUT_SECS; + unsigned int freq = (mApFreq == 0) ? CHIP_DEVICE_CONFIG_WIFIPAF_24G_DEFAUTL_CHNL : mApFreq; + PAFPublishSSI PafPublish_ssi = BuildSSI(); + PafPublish_ssi.DevInfo = connDiscriminator; + + std::ostringstream oss; + + oss << "NAN_SUBSCRIBE " + << "service_name=" << srv_name << " srv_proto_type=" << srv_proto_type << " active=" << is_active << " ttl=" << ttl +#if !CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_HOSTAPD + << " freq=" << freq +#endif + << " ssi=" << std::hex << std::setfill('0') // hex output, zero-padded + << std::setw(2) << static_cast(PafPublish_ssi.DevOpCode) << std::setw(4) << htons(PafPublish_ssi.DevInfo) + << std::setw(4) << htons(PafPublish_ssi.ProductId) << std::setw(4) << htons(PafPublish_ssi.VendorId); + + std::string cmd_str = oss.str(); + const char * cmd = cmd_str.c_str(); + size_t cmd_len = std::strlen(cmd); + + char reply[4096]; + size_t reply_len = sizeof(reply); + + std::lock_guard lock(mCtrlIfaceCmdMutex); + + if (wpa_ctrl_request(cmd_ctrl, cmd, cmd_len, reply, &reply_len, nullptr) != 0) + { + ChipLogError(DeviceLayer, "WiFi-PAF: error sending NAN-SUBSCRIBE"); + return CHIP_ERROR_INTERNAL; + } + + uint32_t subscribe_id; + ReturnErrorOnFailure(StringToUInt32(reply, subscribe_id)); + + ChipLogProgress(DeviceLayer, "WiFi-PAF: subscribe_id: [%u], freq: %u", subscribe_id, freq); + + return _Subscribe(subscribe_id, connDiscriminator); +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::CancelSubscribe(uint32_t SubscribeId) +{ + ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel subscribe_id: %d ! ", SubscribeId); + + std::ostringstream oss; + oss << "NAN_CANCEL_SUBSCRIBE id=" << SubscribeId; + std::string cmd_str = oss.str(); + const char * cmd = cmd_str.c_str(); + size_t cmd_len = std::strlen(cmd); + + char reply[4096]; + size_t reply_len = sizeof(reply); + + std::lock_guard lock(mCtrlIfaceCmdMutex); + if (wpa_ctrl_request(cmd_ctrl, cmd, cmd_len, reply, &reply_len, nullptr) != 0) + { + ChipLogError(DeviceLayer, "WiFi-PAF: Failed to send message"); + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::Send(const WiFiPAF::WiFiPAFSession & TxInfo, System::PacketBufferHandle && msgBuf) +{ + ChipLogProgress(Controller, "WiFi-PAF: sending PAF Follow-up packets, (%lu)", msgBuf->DataLength()); + + if (msgBuf.IsNull()) + { + ChipLogError(Controller, "WiFi-PAF: Invalid Packet (%lu)", msgBuf->DataLength()); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Ensure outgoing message fits in a single contiguous packet buffer, as currently required by the + // message fragmentation and reassembly engine. + if (msgBuf->HasChainedBuffer()) + { + msgBuf->CompactHead(); + if (msgBuf->HasChainedBuffer()) + { + ChipLogError(Controller, "WiFi-PAF: Outbound message too big (%lu), skip temporally", msgBuf->DataLength()); + return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG; + } + } + + // Send the packets + char peer_mac[18]; + snprintf(peer_mac, sizeof(peer_mac), "%02x:%02x:%02x:%02x:%02x:%02x", TxInfo.peer_addr[0], TxInfo.peer_addr[1], + TxInfo.peer_addr[2], TxInfo.peer_addr[3], TxInfo.peer_addr[4], TxInfo.peer_addr[5]); + + std::ostringstream oss_ssi; + for (size_t i = 0; i < msgBuf->DataLength(); ++i) + { + oss_ssi << std::hex << std::setw(2) << std::setfill('0') << static_cast(msgBuf->Start()[i]); + } + auto ssi_str = oss_ssi.str(); + + std::ostringstream oss; + oss << "NAN_TRANSMIT " + << "handle=" << TxInfo.id << " req_instance_id=" << TxInfo.peer_id << " address=" << peer_mac << " ssi=" << ssi_str; + + std::string cmd_str = oss.str(); + const char * cmd = cmd_str.c_str(); + size_t cmd_len = std::strlen(cmd); + + char reply[4096]; + size_t reply_len = sizeof(reply); + + std::lock_guard lock(mCtrlIfaceCmdMutex); + bool result = wpa_ctrl_request(cmd_ctrl, cmd, cmd_len, reply, &reply_len, nullptr) == 0; + + if (!result) + { + ChipLogError(DeviceLayer, "WiFi-PAF: Failed to send message"); + } + ChipLogProgress(Controller, "WiFi-PAF: Outbound message (%lu) done", msgBuf->DataLength()); + + CHIP_ERROR ret = _Send(TxInfo, result); + + return ret; +} + +CHIP_ERROR WiFiPAFDriverCtrlIface::Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role) +{ + wpa_ctrl_close(ctrl); + wpa_ctrl_close(cmd_ctrl); + return _Shutdown(id, role); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Linux/WiFiPAFDriverCtrlIface.h b/src/platform/Linux/WiFiPAFDriverCtrlIface.h new file mode 100644 index 00000000000000..5a8bc658cccfaa --- /dev/null +++ b/src/platform/Linux/WiFiPAFDriverCtrlIface.h @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2025 Cable Television Laboratories, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF_HOSTAPD +#define WIFIPAF_CTRL_IFACE_PATH_PREFIX "/var/run/hostapd/" +#else +#define WIFIPAF_CTRL_IFACE_PATH_PREFIX "/var/run/wpa_supplicant/" +#endif + +#define WIFIPAF_CTRL_IFACE_PATH WIFIPAF_CTRL_IFACE_PATH_PREFIX CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME + +struct wpa_ctrl; + +namespace chip { +namespace DeviceLayer { + +class WiFiPAFDriverCtrlIface : public WiFiPAFDriver +{ +public: + ~WiFiPAFDriverCtrlIface() override {} + CHIP_ERROR Initialize() override; + CHIP_ERROR Publish(std::unique_ptr freq_list, uint16_t freq_list_len) override; + CHIP_ERROR CancelPublish(uint32_t PublishId) override; + CHIP_ERROR Subscribe(const uint16_t & connDiscriminator, uint16_t mApFreq) override; + CHIP_ERROR CancelSubscribe(uint32_t SubscribeId) override; + CHIP_ERROR Send(const WiFiPAF::WiFiPAFSession & TxInfo, chip::System::PacketBufferHandle && msgBuf) override; + CHIP_ERROR Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role) override; + +private: + const std::string kCtrlIfacePath = std::string(WIFIPAF_CTRL_IFACE_PATH); + struct wpa_ctrl * ctrl; + struct wpa_ctrl * cmd_ctrl; + std::mutex mCtrlIfaceCmdMutex; + GIOChannel * gio_channel; + GSource * gsource; + static gboolean OnWiFiManagerFdActivity(GIOChannel * source, GIOCondition condition, gpointer data); + void OnDiscoveryResult(std::unordered_map discov_info); + void OnReplied(std::unordered_map reply_info); + void OnNanReceive(std::unordered_map received_data); + void OnNanPublishTerminated(std::unordered_map publish_terminated_data); + void OnNanSubscribeTerminated(std::unordered_map subscribe_terminated_data); +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Linux/WiFiPAFDriverDbus.cpp b/src/platform/Linux/WiFiPAFDriverDbus.cpp new file mode 100644 index 00000000000000..55adf157b8d25d --- /dev/null +++ b/src/platform/Linux/WiFiPAFDriverDbus.cpp @@ -0,0 +1,430 @@ +/* + * + * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * Copyright (c) 2025 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#include +#include +#include +#endif + +#include +#include +#include + +using namespace ::chip::DeviceLayer; +using namespace ::chip::WiFiPAF; + +namespace chip { +namespace DeviceLayer { + +CHIP_ERROR WiFiPAFDriverDbus::Publish(std::unique_ptr freq_list, uint16_t freq_list_len) +{ + GAutoPtr err; + guint publish_id; + enum nan_service_protocol_type srv_proto_type = nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER; + unsigned int ttl = CHIP_DEVICE_CONFIG_WIFIPAF_MAX_ADVERTISING_TIMEOUT_SECS; + unsigned int freq = CHIP_DEVICE_CONFIG_WIFIPAF_24G_DEFAUTL_CHNL; + unsigned int ssi_len = sizeof(struct PAFPublishSSI); + + // Add the freq_list: + GVariant * freq_array_variant = + g_variant_new_fixed_array(G_VARIANT_TYPE_UINT16, freq_list.get(), freq_list_len, sizeof(guint16)); + if (freq_array_variant == nullptr) + { + ChipLogError(DeviceLayer, "WiFi-PAF: freq_array_variant is NULL "); + return CHIP_ERROR_INTERNAL; + } + + // Construct the SSI + PAFPublishSSI PafPublish_ssi = BuildSSI(); + VerifyOrDie(DeviceLayer::GetCommissionableDataProvider()->GetSetupDiscriminator(PafPublish_ssi.DevInfo) == CHIP_NO_ERROR); + + GVariant * ssi_array_variant = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &PafPublish_ssi, ssi_len, sizeof(guint8)); + if (ssi_array_variant == nullptr) + { + ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL "); + return CHIP_ERROR_INTERNAL; + } + GVariantBuilder builder; + GVariant * args = nullptr; + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add(&builder, "{sv}", "srv_name", g_variant_new_string(srv_name)); + g_variant_builder_add(&builder, "{sv}", "srv_proto_type", g_variant_new_byte(srv_proto_type)); + g_variant_builder_add(&builder, "{sv}", "ttl", g_variant_new_uint16(ttl)); + g_variant_builder_add(&builder, "{sv}", "freq", g_variant_new_uint16(freq)); + g_variant_builder_add(&builder, "{sv}", "ssi", ssi_array_variant); + g_variant_builder_add(&builder, "{sv}", "freq_list", freq_array_variant); + args = g_variant_builder_end(&builder); + std::lock_guard lock(*mWpaSupplicantMutex); + wpa_supplicant_1_interface_call_nanpublish_sync(mWpaSupplicant->iface.get(), args, &publish_id, nullptr, &err.GetReceiver()); + + g_signal_connect( + mWpaSupplicant->iface.get(), "nanreplied", + G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, WiFiPAFDriverDbus * self) { return self->OnReplied(obj); }), + this); + + g_signal_connect(mWpaSupplicant->iface.get(), "nanreceive", + G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, WiFiPAFDriverDbus * self) { + return self->OnNanReceive(obj); + }), + this); + g_signal_connect(mWpaSupplicant->iface.get(), "nanpublish-terminated", + G_CALLBACK(+[](WpaSupplicant1Interface * proxy, guint term_publish_id, gchar * reason, + WiFiPAFDriverDbus * self) { return self->OnNanPublishTerminated(term_publish_id, reason); }), + this); + + ChipLogProgress(DeviceLayer, "WiFi-PAF: publish_id: [%u], freq: %u", publish_id, freq); + + return _Publish(publish_id); +} + +CHIP_ERROR WiFiPAFDriverDbus::CancelPublish(uint32_t PublishId) +{ + GAutoPtr err; + + ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel publish_id: %d ! ", PublishId); + std::lock_guard lock(*mWpaSupplicantMutex); + + VerifyOrReturnError(mWpaSupplicant->iface, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "WiFi-PAF: Skip D-Bus 'cancel publish' call since wpa_supplicant is not ready")); + + gboolean result = + wpa_supplicant_1_interface_call_nancancel_publish_sync(mWpaSupplicant->iface.get(), PublishId, nullptr, &err.GetReceiver()); + + // TODO #40814: make sure that the callers do check the return values. This doesn't seem to be happening now. + VerifyOrReturnError( + result, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "WiFi-PAF: Failed to Cancel Publish with Error: %s", err ? err->message : "unknown error")); + + return CHIP_NO_ERROR; +} + +/* + NAN-USD Service Protocol Type: ref: Table 58 of Wi-Fi Aware Specificaiton +*/ +void WiFiPAFDriverDbus::OnDiscoveryResult(GVariant * discov_info) +{ + ChipLogProgress(Controller, "WiFi-PAF: OnDiscoveryResult"); + uint32_t subscribe_id; + uint32_t peer_publish_id; + uint8_t peer_addr[6]; + uint32_t srv_proto_type; + + std::lock_guard lock(*mWpaSupplicantMutex); + if (g_variant_n_children(discov_info) == 0) + { + return; + } + + /* + Read the data from dbus + */ + GAutoPtr dataValue; + GVariant * value; + + value = g_variant_lookup_value(discov_info, "subscribe_id", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &subscribe_id); + value = g_variant_lookup_value(discov_info, "publish_id", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &peer_publish_id); + + char addr_str[20]; + char * paddr; + value = g_variant_lookup_value(discov_info, "peer_addr", G_VARIANT_TYPE_STRING); + dataValue.reset(value); + g_variant_get(dataValue.get(), "&s", &paddr); + strncpy(addr_str, paddr, sizeof(addr_str)); + sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &peer_addr[0], &peer_addr[1], &peer_addr[2], &peer_addr[3], + &peer_addr[4], &peer_addr[5]); + + value = g_variant_lookup_value(discov_info, "srv_proto_type", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &srv_proto_type); + + // Read the ssi + size_t bufferLen; + value = g_variant_lookup_value(discov_info, "ssi", G_VARIANT_TYPE_BYTESTRING); + dataValue.reset(value); + auto ssibuf = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); + auto pPublishSSI = reinterpret_cast(ssibuf); + + std::array peer_addr_array = { peer_addr[0], peer_addr[1], peer_addr[2], peer_addr[3], peer_addr[4], peer_addr[5] }; + + _OnDiscoveryResult(subscribe_id, peer_publish_id, srv_proto_type, peer_addr_array, pPublishSSI); +} + +void WiFiPAFDriverDbus::OnReplied(GVariant * reply_info) +{ + ChipLogProgress(Controller, "WiFi-PAF: OnReplied"); + uint32_t publish_id; + uint32_t peer_subscribe_id; + uint8_t peer_addr[6]; + uint32_t srv_proto_type; + + std::lock_guard lock(*mWpaSupplicantMutex); + if (g_variant_n_children(reply_info) == 0) + { + return; + } + + /* + Read the data from dbus + */ + GAutoPtr dataValue; + GVariant * value; + + value = g_variant_lookup_value(reply_info, "publish_id", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &publish_id); + value = g_variant_lookup_value(reply_info, "subscribe_id", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &peer_subscribe_id); + + char addr_str[20]; + char * paddr; + value = g_variant_lookup_value(reply_info, "peer_addr", G_VARIANT_TYPE_STRING); + dataValue.reset(value); + g_variant_get(dataValue.get(), "&s", &paddr); + strncpy(addr_str, paddr, sizeof(addr_str)); + sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &peer_addr[0], &peer_addr[1], &peer_addr[2], &peer_addr[3], + &peer_addr[4], &peer_addr[5]); + + value = g_variant_lookup_value(reply_info, "srv_proto_type", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &srv_proto_type); + + // Read the ssi + size_t bufferLen; + value = g_variant_lookup_value(reply_info, "ssi", G_VARIANT_TYPE_BYTESTRING); + dataValue.reset(value); + auto ssibuf = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); + auto pPublishSSI = reinterpret_cast(ssibuf); + + std::array peer_addr_array = { peer_addr[0], peer_addr[1], peer_addr[2], peer_addr[3], peer_addr[4], peer_addr[5] }; + + _OnReplied(peer_subscribe_id, publish_id, srv_proto_type, peer_addr_array, pPublishSSI); +} + +void WiFiPAFDriverDbus::OnNanReceive(GVariant * obj) +{ + if (g_variant_n_children(obj) == 0) + { + return; + } + // Read the rx_info + WiFiPAF::WiFiPAFSession RxInfo; + GAutoPtr dataValue; + GVariant * value; + value = g_variant_lookup_value(obj, "id", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &RxInfo.id); + + value = g_variant_lookup_value(obj, "peer_id", G_VARIANT_TYPE_UINT32); + dataValue.reset(value); + g_variant_get(dataValue.get(), "u", &RxInfo.peer_id); + + char addr_str[20]; + char * paddr; + value = g_variant_lookup_value(obj, "peer_addr", G_VARIANT_TYPE_STRING); + dataValue.reset(value); + g_variant_get(dataValue.get(), "&s", &paddr); + strncpy(addr_str, paddr, sizeof(addr_str)); + sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &RxInfo.peer_addr[0], &RxInfo.peer_addr[1], &RxInfo.peer_addr[2], + &RxInfo.peer_addr[3], &RxInfo.peer_addr[4], &RxInfo.peer_addr[5]); + + // Read the rx_data + value = g_variant_lookup_value(obj, "ssi", G_VARIANT_TYPE_BYTESTRING); + dataValue.reset(value); + + size_t bufferLen; + auto rxbuf = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); + + System::PacketBufferHandle buf = System::PacketBufferHandle::NewWithData(rxbuf, bufferLen); + + _OnNanReceive(RxInfo, std::move(buf)); +} + +void WiFiPAFDriverDbus::OnNanPublishTerminated(guint public_id, gchar * reason) +{ + _OnNanPublishTerminated(public_id, reason); +} + +void WiFiPAFDriverDbus::OnNanSubscribeTerminated(guint subscribe_id, gchar * reason) +{ + _OnNanSubscribeTerminated(subscribe_id, reason); +} + +CHIP_ERROR WiFiPAFDriverDbus::Subscribe(const uint16_t & connDiscriminator, uint16_t mApFreq) +{ + ChipLogProgress(Controller, "WiFi-PAF: Try to subscribe the NAN-USD devices"); + + guint subscribe_id; + GAutoPtr err; + enum nan_service_protocol_type srv_proto_type = nan_service_protocol_type::NAN_SRV_PROTO_CSA_MATTER; + uint8_t is_active = 1; + unsigned int ttl = CHIP_DEVICE_CONFIG_WIFIPAF_DISCOVERY_TIMEOUT_SECS; + unsigned int freq = (mApFreq == 0) ? CHIP_DEVICE_CONFIG_WIFIPAF_24G_DEFAUTL_CHNL : mApFreq; + unsigned int ssi_len = sizeof(struct PAFPublishSSI); + + PAFPublishSSI PafPublish_ssi = BuildSSI(); + PafPublish_ssi.DevInfo = connDiscriminator; + + GVariant * ssi_array_variant = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &PafPublish_ssi, ssi_len, sizeof(guint8)); + if (ssi_array_variant == nullptr) + { + ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL "); + return CHIP_ERROR_INTERNAL; + } + + std::lock_guard lock(*mWpaSupplicantMutex); + GVariantBuilder builder; + GVariant * args = nullptr; + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add(&builder, "{sv}", "srv_name", g_variant_new_string(srv_name)); + g_variant_builder_add(&builder, "{sv}", "srv_proto_type", g_variant_new_byte(srv_proto_type)); + g_variant_builder_add(&builder, "{sv}", "active", g_variant_new_boolean(is_active)); + g_variant_builder_add(&builder, "{sv}", "ttl", g_variant_new_uint16(ttl)); + g_variant_builder_add(&builder, "{sv}", "freq", g_variant_new_uint16(freq)); + g_variant_builder_add(&builder, "{sv}", "ssi", ssi_array_variant); + args = g_variant_builder_end(&builder); + wpa_supplicant_1_interface_call_nansubscribe_sync(mWpaSupplicant->iface.get(), args, &subscribe_id, nullptr, + &err.GetReceiver()); + + g_signal_connect(mWpaSupplicant->iface.get(), "nandiscovery-result", + G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, WiFiPAFDriverDbus * self) { + return self->OnDiscoveryResult(obj); + }), + this); + + g_signal_connect(mWpaSupplicant->iface.get(), "nanreceive", + G_CALLBACK(+[](WpaSupplicant1Interface * proxy, GVariant * obj, WiFiPAFDriverDbus * self) { + return self->OnNanReceive(obj); + }), + this); + + g_signal_connect( + mWpaSupplicant->iface.get(), "nansubscribe-terminated", + G_CALLBACK(+[](WpaSupplicant1Interface * proxy, guint term_subscribe_id, gchar * reason, WiFiPAFDriverDbus * self) { + return self->OnNanSubscribeTerminated(term_subscribe_id, reason); + }), + this); + + ChipLogProgress(DeviceLayer, "WiFi-PAF: subscribe_id: [%u], freq: %u", subscribe_id, freq); + + return _Subscribe(subscribe_id, connDiscriminator); +} + +CHIP_ERROR WiFiPAFDriverDbus::CancelSubscribe(uint32_t SubscribeId) +{ + GAutoPtr err; + + ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel subscribe_id: %d ! ", SubscribeId); + std::lock_guard lock(*mWpaSupplicantMutex); + wpa_supplicant_1_interface_call_nancancel_subscribe_sync(mWpaSupplicant->iface.get(), SubscribeId, nullptr, &err.GetReceiver()); + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiPAFDriverDbus::Send(const WiFiPAF::WiFiPAFSession & TxInfo, System::PacketBufferHandle && msgBuf) +{ + ChipLogProgress(Controller, "WiFi-PAF: sending PAF Follow-up packets, (%lu)", msgBuf->DataLength()); + + if (msgBuf.IsNull()) + { + ChipLogError(Controller, "WiFi-PAF: Invalid Packet (%lu)", msgBuf->DataLength()); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Ensure outgoing message fits in a single contiguous packet buffer, as currently required by the + // message fragmentation and reassembly engine. + if (msgBuf->HasChainedBuffer()) + { + msgBuf->CompactHead(); + if (msgBuf->HasChainedBuffer()) + { + ChipLogError(Controller, "WiFi-PAF: Outbound message too big (%lu), skip temporally", msgBuf->DataLength()); + return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG; + } + } + + // Send the packets + GAutoPtr err; + gchar peer_mac[18]; + + snprintf(peer_mac, sizeof(peer_mac), "%02x:%02x:%02x:%02x:%02x:%02x", TxInfo.peer_addr[0], TxInfo.peer_addr[1], + TxInfo.peer_addr[2], TxInfo.peer_addr[3], TxInfo.peer_addr[4], TxInfo.peer_addr[5]); + GVariant * ssi_array_variant = + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, msgBuf->Start(), msgBuf->DataLength(), sizeof(guint8)); + if (ssi_array_variant == nullptr) + { + ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL "); + return CHIP_ERROR_INTERNAL; + } + std::lock_guard lock(*mWpaSupplicantMutex); + + GVariantBuilder builder; + GVariant * args = nullptr; + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add(&builder, "{sv}", "handle", g_variant_new_uint32(TxInfo.id)); + g_variant_builder_add(&builder, "{sv}", "req_instance_id", g_variant_new_uint32(TxInfo.peer_id)); + g_variant_builder_add(&builder, "{sv}", "peer_addr", g_variant_new_string(peer_mac)); + g_variant_builder_add(&builder, "{sv}", "ssi", ssi_array_variant); + args = g_variant_builder_end(&builder); + gboolean result = + wpa_supplicant_1_interface_call_nantransmit_sync(mWpaSupplicant->iface.get(), args, nullptr, &err.GetReceiver()); + if (!result) + { + ChipLogError(DeviceLayer, "WiFi-PAF: Failed to send message: %s", err == nullptr ? "unknown error" : err->message); + } + ChipLogProgress(Controller, "WiFi-PAF: Outbound message (%lu) done", msgBuf->DataLength()); + + return _Send(TxInfo, result); +} + +CHIP_ERROR WiFiPAFDriverDbus::Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role) +{ + return _Shutdown(id, role); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Linux/WiFiPAFDriverDbus.h b/src/platform/Linux/WiFiPAFDriverDbus.h new file mode 100644 index 00000000000000..d961c508d6de4f --- /dev/null +++ b/src/platform/Linux/WiFiPAFDriverDbus.h @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#include +#include +#endif + +#include +#include + +#include + +namespace chip { +namespace DeviceLayer { + +class WiFiPAFDriverDbus : public WiFiPAFDriver +{ +public: + WiFiPAFDriverDbus(GDBusWpaSupplicant * WpaSupplicant, std::mutex * WpaSupplicantMutex) : + mWpaSupplicant(WpaSupplicant), mWpaSupplicantMutex(WpaSupplicantMutex) + {} + ~WiFiPAFDriverDbus() override {} + CHIP_ERROR Initialize() override { return CHIP_NO_ERROR; }; + CHIP_ERROR Publish(std::unique_ptr freq_list, uint16_t freq_list_len) override; + CHIP_ERROR CancelPublish(uint32_t PublishId) override; + CHIP_ERROR Subscribe(const uint16_t & connDiscriminator, uint16_t mApFreq) override; + CHIP_ERROR CancelSubscribe(uint32_t SubscribeId) override; + CHIP_ERROR Send(const WiFiPAF::WiFiPAFSession & TxInfo, chip::System::PacketBufferHandle && msgBuf) override; + CHIP_ERROR Shutdown(uint32_t id, WiFiPAF::WiFiPafRole role) override; + +private: + GDBusWpaSupplicant * mWpaSupplicant; + std::mutex * mWpaSupplicantMutex; + void OnDiscoveryResult(GVariant * obj); + void OnReplied(GVariant * obj); + void OnNanReceive(GVariant * obj); + void OnNanPublishTerminated(guint public_id, gchar * reason); + void OnNanSubscribeTerminated(guint subscribe_id, gchar * reason); +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Linux/WpaDbusDefs.h b/src/platform/Linux/WpaDbusDefs.h new file mode 100644 index 00000000000000..3f6e7a8d70b137 --- /dev/null +++ b/src/platform/Linux/WpaDbusDefs.h @@ -0,0 +1,71 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#include +#include +#include +#include +#include +#endif + +namespace chip { + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA + +template <> +struct GAutoPtrDeleter +{ + using deleter = GObjectDeleter; +}; + +template <> +struct GAutoPtrDeleter +{ + using deleter = GObjectDeleter; +}; + +template <> +struct GAutoPtrDeleter +{ + using deleter = GObjectDeleter; +}; + +template <> +struct GAutoPtrDeleter +{ + using deleter = GObjectDeleter; +}; + +#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA + +namespace DeviceLayer { + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA +struct GDBusWpaSupplicant +{ + GAutoPtr proxy; + GAutoPtr iface; + GAutoPtr interfacePath; + GAutoPtr networkPath; +}; +#endif + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/device.gni b/src/platform/device.gni index fcb60bd4a6f138..d8c20eef0c31a4 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -130,6 +130,9 @@ declare_args() { # and the supplicant can support. chip_device_config_enable_wifipaf = chip_enable_wifi && chip_device_platform == "linux" + + chip_device_config_enable_wifipaf_ctrl_iface = false + chip_device_config_enable_wifipaf_hostapd = false } declare_args() { diff --git a/third_party/hostap/repo b/third_party/hostap/repo new file mode 160000 index 00000000000000..38e3a7c57db442 --- /dev/null +++ b/third_party/hostap/repo @@ -0,0 +1 @@ +Subproject commit 38e3a7c57db442b6bd3377b15b7e611297dac1ec