blob: 8eb5df701361299a2eeb918418ca1314b37132a5 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2026 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 <mutex>
#include <stdint.h>
#include <glib.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/CommissionableDataProvider.h>
#include <platform/ConnectivityManager.h>
#include <platform/DeviceInstanceInfoProvider.h>
#include <platform/GLibTypeDeleter.h>
#include <platform/PlatformManager.h>
#include "ConnectivityManagerImpl.h"
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
using namespace ::chip::WiFiPAF;
#endif
namespace chip {
namespace DeviceLayer {
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
static 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<GError> 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;
SuccessOrDie(DeviceLayer::GetCommissionableDataProvider()->GetSetupDiscriminator(PafPublish_ssi.DevInfo));
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)
{
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<std::mutex> 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;
}
CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFCancelPublish(uint32_t PublishId)
{
GAutoPtr<GError> err;
ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel publish_id: %d ! ", PublishId);
std::lock_guard<std::mutex> 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 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<std::mutex> lock(mWpaSupplicantMutex);
if (g_variant_n_children(discov_info) == 0)
{
return;
}
/*
Read the data from dbus
*/
GAutoPtr<GVariant> 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
gsize 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<const PAFPublishSSI *>(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: %" PRIu64, 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<std::mutex> lock(mWpaSupplicantMutex);
if (g_variant_n_children(reply_info) == 0)
{
return;
}
/*
Read the data from dbus
*/
GAutoPtr<GVariant> 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
gsize 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<const PAFPublishSSI *>(ssibuf);
/*
Error Checking
*/
uint16_t SetupDiscriminator;
TEMPORARY_RETURN_IGNORED 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: %" PRIu64, 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);
TEMPORARY_RETURN_IGNORED WiFiPafLayer.HandleTransportConnectionInitiated(*pPafInfo);
}
void ConnectivityManagerImpl::OnNanReceive(GVariant * obj)
{
if (g_variant_n_children(obj) == 0)
{
return;
}
// Read the rx_info
WiFiPAF::WiFiPAFSession RxInfo;
GAutoPtr<GVariant> 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
gsize 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: %" G_GSIZE_FORMAT "]", 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();
TEMPORARY_RETURN_IGNORED 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();
TEMPORARY_RETURN_IGNORED WiFiPafLayer.RmPafSession(PafInfoAccess::kAccSessionId, sessionInfo);
/*
Indicate the connection event
*/
ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoWiFiPAFCancelConnect };
PlatformMgr().PostEventOrDie(&event);
}
CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFSubscribe(const uint16_t & connDiscriminator, void * appState,
OnConnectionCompleteFunct onSuccess, OnConnectionErrorFunct onError)
{
CHIP_ERROR result = StartWiFiManagementSync();
VerifyOrReturnError(result == CHIP_NO_ERROR, result);
ChipLogProgress(Controller, "WiFi-PAF: Try to subscribe the NAN-USD devices");
guint subscribe_id;
GAutoPtr<GError> 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)
{
ChipLogProgress(DeviceLayer, "WiFi-PAF: ssi_array_variant is NULL ");
return CHIP_ERROR_INTERNAL;
}
std::lock_guard<std::mutex> 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);
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;
}
CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFCancelSubscribe(uint32_t SubscribeId)
{
GAutoPtr<GError> err;
ChipLogProgress(DeviceLayer, "WiFi-PAF: cancel subscribe_id: %d ! ", SubscribeId);
std::lock_guard<std::mutex> lock(mWpaSupplicantMutex);
wpa_supplicant_1_interface_call_nancancel_subscribe_sync(mWpaSupplicant.iface.get(), SubscribeId, nullptr, &err.GetReceiver());
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFCancelIncompleteSubscribe()
{
mOnPafSubscribeComplete = nullptr;
mOnPafSubscribeError = nullptr;
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFSend(const WiFiPAF::WiFiPAFSession & TxInfo, System::PacketBufferHandle && msgBuf)
{
ChipLogProgress(Controller, "WiFi-PAF: sending PAF Follow-up packets, (%zu)", msgBuf->DataLength());
CHIP_ERROR ret = CHIP_NO_ERROR;
if (msgBuf.IsNull())
{
ChipLogError(Controller, "WiFi-PAF: Invalid Packet (%zu)", 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 (%zu), skip temporally", msgBuf->DataLength());
return ret;
}
}
// Send the packets
GAutoPtr<GError> 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<std::mutex> 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 (%zu) 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;
}
CHIP_ERROR ConnectivityManagerImpl::_WiFiPAFShutdown(uint32_t id, WiFiPAF::WiFiPafRole role)
{
switch (role)
{
case WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher:
return _WiFiPAFCancelPublish(id);
case WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber:
return _WiFiPAFCancelSubscribe(id);
}
return CHIP_ERROR_INTERNAL;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
} // namespace DeviceLayer
} // namespace chip