1 /*
2 * WPA Supplicant - Helper functions for USD
3 * Copyright (c) 2025, Google Inc. All rights reserved.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #ifndef MAINLINE_SUPPLICANT_USD_UTILS_H
10 #define MAINLINE_SUPPLICANT_USD_UTILS_H
11
12 #include "utils.h"
13
14 #include <aidl/android/system/wifi/mainline_supplicant/IStaInterface.h>
15 #include <aidl/android/system/wifi/mainline_supplicant/UsdServiceProtoType.h>
16
17 extern "C"
18 {
19 #include "utils/common.h"
20 #include "src/common/nan_de.h"
21 }
22
23 using ::aidl::android::system::wifi::mainline_supplicant::IStaInterface;
24 using ::aidl::android::system::wifi::mainline_supplicant::UsdServiceProtoType;
25
26 constexpr bool kIsUsdPublisherSupported = true;
27 constexpr bool kIsUsdSubscriberSupported = true;
28 constexpr int32_t kMaxUsdLocalSsiLengthBytes = 1400;
29 constexpr int32_t kMaxUsdServiceNameLengthBytes = 255;
30 constexpr int32_t kMaxUsdMatchFilterLengthBytes = 0;
31 constexpr int32_t kMaxNumUsdPublishSessions = NAN_DE_MAX_SERVICE;
32 constexpr int32_t kMaxNumUsdSubscribeSessions = NAN_DE_MAX_SERVICE;
33
validateUsdBaseConfig(IStaInterface::UsdBaseConfig baseConfig)34 static bool validateUsdBaseConfig(IStaInterface::UsdBaseConfig baseConfig) {
35 if (!isValidEnumValue(baseConfig.serviceProtoType,
36 UsdServiceProtoType::GENERIC, UsdServiceProtoType::CSA_MATTER)) {
37 wpa_printf(MSG_ERROR, "Unknown protocol type received: %d",
38 static_cast<int>(baseConfig.serviceProtoType));
39 return false;
40 }
41 if (!checkContainerSize(baseConfig.serviceName, kMaxUsdServiceNameLengthBytes)) {
42 wpa_printf(MSG_ERROR, "Service name of size %zu exceeds the supported size of %d",
43 baseConfig.serviceName.size(), kMaxUsdServiceNameLengthBytes);
44 return false;
45 }
46 if (!checkContainerSize(baseConfig.serviceSpecificInfo, kMaxUsdLocalSsiLengthBytes)) {
47 wpa_printf(MSG_ERROR, "Service specific info of size %zu exceeds"
48 " the supported size of %d", baseConfig.serviceSpecificInfo.size(),
49 kMaxUsdLocalSsiLengthBytes);
50 return false;
51 }
52 if (baseConfig.txMatchFilter.has_value() && !checkContainerSize(
53 baseConfig.txMatchFilter.value(), kMaxUsdMatchFilterLengthBytes)) {
54 wpa_printf(MSG_ERROR, "TX match filter of size %zu exceeds"
55 " the supported size of %d", baseConfig.txMatchFilter.value().size(),
56 kMaxUsdMatchFilterLengthBytes);
57 return false;
58 }
59 if (baseConfig.rxMatchFilter.has_value() && !checkContainerSize(
60 baseConfig.rxMatchFilter.value(), kMaxUsdMatchFilterLengthBytes)) {
61 wpa_printf(MSG_ERROR, "RX match filter of size %zu exceeds"
62 " the supported size of %d", baseConfig.rxMatchFilter.value().size(),
63 kMaxUsdMatchFilterLengthBytes);
64 return false;
65 }
66 return true;
67 }
68
validateUsdPublishConfig(IStaInterface::UsdPublishConfig publishConfig)69 static bool validateUsdPublishConfig(IStaInterface::UsdPublishConfig publishConfig) {
70 if (!validateUsdBaseConfig(publishConfig.baseConfig)) {
71 return false;
72 }
73 if (!isValidEnumValue(publishConfig.publishType,
74 IStaInterface::UsdPublishType::SOLICITED_ONLY,
75 IStaInterface::UsdPublishType::SOLICITED_AND_UNSOLICITED)) {
76 wpa_printf(MSG_ERROR, "Unknown publish type received: %d",
77 static_cast<int>(publishConfig.publishType));
78 return false;
79 }
80 if (!isValidEnumValue(publishConfig.transmissionType,
81 IStaInterface::UsdPublishTransmissionType::UNICAST,
82 IStaInterface::UsdPublishTransmissionType::MULTICAST)) {
83 wpa_printf(MSG_ERROR, "Unknown transmission type received: %d",
84 static_cast<int>(publishConfig.transmissionType));
85 return false;
86 }
87 return true;
88 }
89
validateUsdSubscribeConfig(IStaInterface::UsdSubscribeConfig subscribeConfig)90 static bool validateUsdSubscribeConfig(IStaInterface::UsdSubscribeConfig subscribeConfig) {
91 if (!validateUsdBaseConfig(subscribeConfig.baseConfig)) {
92 return false;
93 }
94 if (!isValidEnumValue(subscribeConfig.subscribeType,
95 IStaInterface::UsdSubscribeType::PASSIVE_MODE,
96 IStaInterface::UsdSubscribeType::ACTIVE_MODE)) {
97 wpa_printf(MSG_ERROR, "Unknown subscribe type received: %d",
98 static_cast<int>(subscribeConfig.subscribeType));
99 return false;
100 }
101 return true;
102 }
103
convertAidlUsdPublishConfigToInternal(IStaInterface::UsdPublishConfig publishConfig)104 static struct nan_publish_params convertAidlUsdPublishConfigToInternal(
105 IStaInterface::UsdPublishConfig publishConfig) {
106 struct nan_publish_params nanPublishParams;
107 nanPublishParams.unsolicited =
108 publishConfig.publishType == IStaInterface::UsdPublishType::SOLICITED_AND_UNSOLICITED
109 || publishConfig.publishType == IStaInterface::UsdPublishType::UNSOLICITED_ONLY;
110 nanPublishParams.solicited =
111 publishConfig.publishType == IStaInterface::UsdPublishType::SOLICITED_AND_UNSOLICITED
112 || publishConfig.publishType == IStaInterface::UsdPublishType::SOLICITED_ONLY;
113 nanPublishParams.solicited_multicast = nanPublishParams.solicited &&
114 publishConfig.transmissionType == IStaInterface::UsdPublishTransmissionType::MULTICAST;
115 nanPublishParams.ttl = publishConfig.baseConfig.ttlSec;
116 nanPublishParams.fsd = publishConfig.isFsd;
117 nanPublishParams.freq = publishConfig.baseConfig.defaultFreqMhz;
118 nanPublishParams.announcement_period = publishConfig.announcementPeriodMillis;
119 nanPublishParams.disable_events = !publishConfig.eventsEnabled;
120 // Pass the original pointer to the freq list, since the receiver will memcpy the data
121 nanPublishParams.freq_list = publishConfig.baseConfig.freqsMhz.empty()
122 ? NULL : publishConfig.baseConfig.freqsMhz.data();
123 return nanPublishParams;
124 }
125
convertAidlUsdSubscribeConfigToInternal(IStaInterface::UsdSubscribeConfig subscribeConfig)126 static struct nan_subscribe_params convertAidlUsdSubscribeConfigToInternal(
127 IStaInterface::UsdSubscribeConfig subscribeConfig) {
128 struct nan_subscribe_params nanSubscribeParams;
129 nanSubscribeParams.active =
130 subscribeConfig.subscribeType == IStaInterface::UsdSubscribeType::ACTIVE_MODE;
131 nanSubscribeParams.ttl = subscribeConfig.baseConfig.ttlSec;
132 nanSubscribeParams.freq = subscribeConfig.baseConfig.defaultFreqMhz;
133 nanSubscribeParams.query_period = subscribeConfig.queryPeriodMillis;
134 // Pass the original pointer to the freq list, since the receiver will memcpy the data
135 nanSubscribeParams.freq_list = subscribeConfig.baseConfig.freqsMhz.empty()
136 ? NULL : subscribeConfig.baseConfig.freqsMhz.data();
137 return nanSubscribeParams;
138 }
139
convertAidlServiceProtoTypeToInternal(UsdServiceProtoType serviceProtoType)140 static nan_service_protocol_type convertAidlServiceProtoTypeToInternal(
141 UsdServiceProtoType serviceProtoType) {
142 switch (serviceProtoType) {
143 case UsdServiceProtoType::GENERIC:
144 return NAN_SRV_PROTO_GENERIC;
145 case UsdServiceProtoType::CSA_MATTER:
146 return NAN_SRV_PROTO_CSA_MATTER;
147 default:
148 // Default case is not expected, due to the USD validation method
149 return NAN_SRV_PROTO_GENERIC;
150 };
151 }
152
convertInternalUsdServiceProtoTypeToAidl(nan_service_protocol_type protocolType)153 static UsdServiceProtoType convertInternalUsdServiceProtoTypeToAidl(
154 nan_service_protocol_type protocolType) {
155 switch (protocolType) {
156 case NAN_SRV_PROTO_GENERIC:
157 return UsdServiceProtoType::GENERIC;
158 case NAN_SRV_PROTO_CSA_MATTER:
159 return UsdServiceProtoType::CSA_MATTER;
160 default:
161 wpa_printf(MSG_ERROR, "Received invalid USD proto type %d from internal",
162 static_cast<int>(protocolType));
163 return UsdServiceProtoType::GENERIC;
164 }
165 }
166
createUsdServiceDiscoveryInfo(enum nan_service_protocol_type srv_proto_type,int own_id,int peer_id,const u8 * peer_addr,bool fsd,const u8 * ssi,size_t ssi_len)167 static IStaInterfaceCallback::UsdServiceDiscoveryInfo createUsdServiceDiscoveryInfo(
168 enum nan_service_protocol_type srv_proto_type,
169 int own_id, int peer_id, const u8 *peer_addr,
170 bool fsd, const u8 *ssi, size_t ssi_len) {
171 IStaInterfaceCallback::UsdServiceDiscoveryInfo discoveryInfo;
172 discoveryInfo.ownId = own_id;
173 discoveryInfo.peerId = peer_id;
174 // TODO: Fill the matchFilter field in the AIDL struct
175 discoveryInfo.matchFilter = std::vector<uint8_t>();
176 discoveryInfo.peerMacAddress = macAddrBytesToArray(peer_addr);
177 discoveryInfo.serviceProtoType = convertInternalUsdServiceProtoTypeToAidl(srv_proto_type);
178 discoveryInfo.serviceSpecificInfo = ssi ? byteArrToVec(ssi, ssi_len) : std::vector<uint8_t>();
179 discoveryInfo.isFsd = fsd;
180 return discoveryInfo;
181 }
182
convertInternalUsdTerminateReasonCodeToAidl(nan_de_reason terminateReason)183 static IStaInterfaceCallback::UsdTerminateReasonCode convertInternalUsdTerminateReasonCodeToAidl(
184 nan_de_reason terminateReason) {
185 switch (terminateReason) {
186 case NAN_DE_REASON_TIMEOUT:
187 return IStaInterfaceCallback::UsdTerminateReasonCode::TIMEOUT;
188 case NAN_DE_REASON_USER_REQUEST:
189 return IStaInterfaceCallback::UsdTerminateReasonCode::USER_REQUESTED;
190 case NAN_DE_REASON_FAILURE:
191 default:
192 return IStaInterfaceCallback::UsdTerminateReasonCode::FAILURE_UNKNOWN;
193 }
194 }
195
196 #endif // MAINLINE_SUPPLICANT_USD_UTILS_H
197