1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "pbap_pce_connecting_state.h"
17 #include <cstring>
18 #include <vector>
19 #include "../obex/obex_utils.h"
20 #include "pbap_pce_service.h"
21 #include "power_manager.h"
22 #include "securec.h"
23
24 namespace OHOS {
25 namespace bluetooth {
PceConnectingState(const std::string & name,PbapPceStateMachine & stm,BaseObserverList<IPbapPceObserver> & observerMgrList)26 PceConnectingState::PceConnectingState(
27 const std::string &name, PbapPceStateMachine &stm, BaseObserverList<IPbapPceObserver> &observerMgrList)
28 : PceBaseState(name, stm, observerMgrList),
29 authDescription_(),
30 authNonce_(),
31 authUserCharset_(0),
32 authFullAccess_(false),
33 authNeedUser_(false),
34 authChallenge_(false),
35 header_(nullptr)
36 {}
37
Entry()38 void PceConnectingState::Entry()
39 {
40 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
41
42 PBAP_PCE_LOG_INFO("observerMgrList_ -> CONNECTING");
43 auto device = stm_.GetDevice();
44 observerMgrList_.ForEach([device](IPbapPceObserver &observer) {
45 observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::CONNECTING));
46 });
47 int retVal = stm_.GetSdp().SdpSearch(stm_.GetDevice());
48 if (retVal != BT_SUCCESS) {
49 PBAP_PCE_LOG_ERROR("%{public}s end, pce client Call SDP_ServiceSearchAttribute Error", __PRETTY_FUNCTION__);
50 Transition(PCE_DISCONNECTING_STATE);
51 Transition(PCE_DISCONNECTED_STATE);
52 }
53 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
54 }
55
Exit()56 void PceConnectingState::Exit()
57 {}
58
RegGap(const PbapPceHeaderSdpMsg & sdpMsg) const59 void PceConnectingState::RegGap(const PbapPceHeaderSdpMsg &sdpMsg) const
60 {
61 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
62
63 const auto &obexClientConfig = sdpMsg.GetObexClientConfig();
64 bool isGoepL2capPSM = obexClientConfig.isGoepL2capPSM_;
65 GapSecChannel gapSecChannel;
66 if (isGoepL2capPSM) {
67 gapSecChannel.l2capPsm = obexClientConfig.scn_;
68 } else {
69 gapSecChannel.rfcommChannel = obexClientConfig.scn_;
70 }
71 auto gap = std::make_unique<PbapPceGap>(stm_.GetPceService(), stm_.GetDevice(), gapSecChannel, isGoepL2capPSM);
72 int retVal = gap->Register();
73 if (retVal != BT_SUCCESS) {
74 PBAP_PCE_LOG_ERROR("%{public}s end, GAP_RegisterServiceSecurity() error", __PRETTY_FUNCTION__);
75 return;
76 }
77
78 stm_.SetGap(*(gap.release()));
79
80 stm_.SetGapSecChannel(gapSecChannel);
81 stm_.SetGoepL2capPSM(isGoepL2capPSM);
82 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
83 }
84
ObexConnect(const PbapPceHeaderSdpMsg & sdpMsg)85 int PceConnectingState::ObexConnect(const PbapPceHeaderSdpMsg &sdpMsg)
86 {
87 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
88 // regisger gap
89 RegGap(sdpMsg);
90
91 // set version, repository, feature to stm
92 stm_.SetVersionNumber(sdpMsg.GetVersionNumber());
93 stm_.SetSupportedRes(sdpMsg.GetSupportedRes());
94 stm_.SetSupportedFeature(sdpMsg.GetSupportedFeature());
95 stm_.SetFeatureFlag(sdpMsg.GetFeatureFlag());
96
97 obexConfig_ = sdpMsg.GetObexClientConfig();
98 SetObexClientConfigDetail(obexConfig_);
99 stm_.CreatePceObexClient(obexConfig_);
100 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
101 return stm_.GetGap()->RequestSecurity();
102 }
103
InitAuth()104 void PceConnectingState::InitAuth()
105 {
106 authDescription_.clear();
107 authChallenge_ = true;
108 authFullAccess_ = true;
109 authNeedUser_ = false;
110 authNonce_.clear();
111 }
112
SaveObexDigestChallenge(const ObexDigestChallenge & digestChallenge)113 int PceConnectingState::SaveObexDigestChallenge(const ObexDigestChallenge &digestChallenge)
114 {
115 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
116 auto nonceTlv = digestChallenge.GetNonce();
117 if (nonceTlv == nullptr) { // nonce is required, but not found
118 PBAP_PCE_LOG_ERROR("%{public}s end, header is not contained nonce", __PRETTY_FUNCTION__);
119 return RET_NO_SUPPORT;
120 }
121
122 authNonce_.insert(authNonce_.end(), nonceTlv->GetVal(), nonceTlv->GetVal() + nonceTlv->GetLen());
123 auto optionsTlv = digestChallenge.GetOptions();
124 if (optionsTlv != nullptr) {
125 uint8_t option = optionsTlv->GetVal()[0];
126 // When set, the User Id must be sent in the authenticate response.
127 if ((option & 0x01) != 0) {
128 authNeedUser_ = true;
129 }
130 // Access mode: Read Only when set, otherwise Full access is permitted.
131 if ((option & 0x02) != 0) {
132 authFullAccess_ = false;
133 }
134 }
135
136 auto realmTlv = digestChallenge.GetRealm();
137 if (realmTlv != nullptr) {
138 if (realmTlv->GetLen() > 0) {
139 authUserCharset_ = realmTlv->GetVal()[0];
140 if (realmTlv->GetLen() > 1) {
141 authDescription_.insert(
142 authDescription_.end(), realmTlv->GetVal() + 1, realmTlv->GetVal() + realmTlv->GetLen());
143 }
144 }
145 }
146 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
147 return BT_SUCCESS;
148 }
149
ObexReconnect(const PbapPceObexMessage & obexMsg)150 int PceConnectingState::ObexReconnect(const PbapPceObexMessage &obexMsg)
151 {
152 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
153 int ret = RET_BAD_STATUS;
154 const ObexHeader *header = obexMsg.GetObexHeader();
155 ObexClient *client = obexMsg.GetObexClient();
156 header_ = std::make_unique<ObexHeader>(*header);
157 if (header->GetFieldCode() != static_cast<uint8_t>(ObexRspCode::UNAUTHORIZED)) {
158 if (client != nullptr) {
159 client->Disconnect(false);
160 PBAP_PCE_LOG_ERROR("%{public}s end, response is not UNAUTHORIZED Disconnect(not withObexReq)",
161 __PRETTY_FUNCTION__);
162 }
163 return ret;
164 }
165 auto tvlHeader = header->GetItemAuthChallenges();
166 if (tvlHeader == nullptr) {
167 PBAP_PCE_LOG_ERROR("%{public}s end, returned header from pse not contain challenge parameter",
168 __PRETTY_FUNCTION__);
169 return RET_NO_SUPPORT;
170 }
171
172 InitAuth();
173
174 auto authChallenges = header->GetItemAuthChallenges();
175 auto digestChallenge = static_cast<ObexDigestChallenge *>(authChallenges->GetTlvParamters().get());
176 ret = SaveObexDigestChallenge(*digestChallenge);
177 if (ret != BT_SUCCESS) {
178 PBAP_PCE_LOG_ERROR("%{public}s end, SaveObexDigestChallenge error, ret=%{public}d!",
179 __PRETTY_FUNCTION__, ret);
180 return ret;
181 }
182
183 auto &device = stm_.GetDevice();
184 auto &authDescription = authDescription_;
185 auto &authUserCharset = authUserCharset_;
186 auto &authFullAccess = authFullAccess_;
187 observerMgrList_.ForEach([device, authDescription, authUserCharset, authFullAccess](IPbapPceObserver &observer) {
188 observer.OnServicePasswordRequired(device, authDescription, authUserCharset, authFullAccess);
189 });
190
191 return BT_SUCCESS;
192 }
193
SetObexClientConfigDetail(ObexClientConfig & obexConfig) const194 void PceConnectingState::SetObexClientConfigDetail(ObexClientConfig &obexConfig) const
195 {
196 obexConfig.isSupportReliableSession_ = false;
197 if (obexConfig.isGoepL2capPSM_) {
198 obexConfig.mtu_ = stm_.GetPceService().GetPceConfig().l2capMtu_;
199 } else {
200 obexConfig.mtu_ = stm_.GetPceService().GetPceConfig().rfcommMtu_;
201 }
202 const int len = PBAP_PCE_SERVICE_UUID_LEN;
203 (void)memcpy_s(&obexConfig.serviceUUID_.uuid128, len, PBAP_PCE_SERVICE_UUID, len);
204 }
205
ProcessObexConnected(const utility::Message & msg)206 void PceConnectingState::ProcessObexConnected(const utility::Message &msg)
207 {
208 PBAP_PCE_LOG_INFO("%{public}s start, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
209 auto obexMsg = static_cast<PbapPceObexMessage *>(msg.arg2_);
210 if ((obexMsg != nullptr) && (obexMsg->GetObexHeader() != nullptr)) {
211 auto connectId = obexMsg->GetObexHeader()->GetItemConnectionId();
212 if (connectId != nullptr) {
213 stm_.SetConnectId(connectId->GetWord());
214 }
215 }
216 Transition(PCE_CONNECTED_STATE);
217 PBAP_PCE_LOG_INFO("%{public}s end, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
218 }
219
ProcessSdpFinish(const utility::Message & msg)220 void PceConnectingState::ProcessSdpFinish(const utility::Message &msg)
221 {
222 PBAP_PCE_LOG_INFO("%{public}s start, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
223 std::unique_ptr<PbapPceHeaderSdpMsg> sdpMsg(static_cast<PbapPceHeaderSdpMsg *>(msg.arg2_));
224 if (sdpMsg != nullptr) {
225 if (ObexConnect(*sdpMsg) != BT_SUCCESS) {
226 Transition(PCE_DISCONNECTING_STATE);
227 Transition(PCE_DISCONNECTED_STATE);
228 }
229 }
230 PBAP_PCE_LOG_INFO("%{public}s end, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
231 }
232
ProcessGapFinish(const utility::Message & msg) const233 void PceConnectingState::ProcessGapFinish(const utility::Message &msg) const
234 {
235 PBAP_PCE_LOG_INFO("%{public}s start, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
236 stm_.GetObexClient().Connect(stm_.GetFeatureFlag());
237 PBAP_PCE_LOG_INFO("%{public}s end, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
238 }
239
ProcessObexConnectFailed(const utility::Message & msg)240 void PceConnectingState::ProcessObexConnectFailed(const utility::Message &msg)
241 {
242 PBAP_PCE_LOG_INFO("%{public}s start, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
243 auto obexMsg = static_cast<PbapPceObexMessage *>(msg.arg2_);
244 if ((obexMsg != nullptr) && ObexReconnect(*obexMsg) != BT_SUCCESS) {
245 Transition(PCE_DISCONNECTING_STATE);
246 }
247 PBAP_PCE_LOG_INFO("%{public}s end, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
248 }
249
ProcessObexTransportFailed(const utility::Message & msg)250 void PceConnectingState::ProcessObexTransportFailed(const utility::Message &msg)
251 {
252 PBAP_PCE_LOG_INFO("%{public}s start, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
253 if (msg.what_ == PCE_TRANSPORT_FAILED) {
254 if (msg.arg1_ == CONNECT_COLLISION) {
255 // re gap request security and reconnect
256 stm_.GetGap()->RequestSecurity();
257 } else {
258 Transition(PCE_DISCONNECTING_STATE);
259 Transition(PCE_DISCONNECTED_STATE);
260 }
261 }
262 PBAP_PCE_LOG_INFO("%{public}s end, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
263 }
264
ProcessPasswordInput(const utility::Message & msg) const265 void PceConnectingState::ProcessPasswordInput(const utility::Message &msg) const
266 {
267 std::unique_ptr<PbapPcePasswordInputMsg> pwdInputMsg(static_cast<PbapPcePasswordInputMsg *>(msg.arg2_));
268 PasswordInput(*pwdInputMsg);
269 }
270
Dispatch(const utility::Message & msg)271 bool PceConnectingState::Dispatch(const utility::Message &msg)
272 {
273 PBAP_PCE_LOG_INFO("%{public}s start, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
274 switch (msg.what_) {
275 case PCE_SDP_FINISH:
276 ProcessSdpFinish(msg);
277 break;
278 case PCE_GAP_FINISH:
279 ProcessGapFinish(msg);
280 break;
281 case PCE_REQ_DISCONNECTED:
282 Transition(PCE_DISCONNECTED_STATE);
283 break;
284 case PCE_OBEX_CONNECTED:
285 ProcessObexConnected(msg);
286 break;
287 case PCE_SDP_FAILED:
288 case PCE_GAP_FAILED:
289 Transition(PCE_DISCONNECTING_STATE);
290 Transition(PCE_DISCONNECTED_STATE);
291 break;
292 case PCE_OBEX_CONNECT_FAILED:
293 ProcessObexConnectFailed(msg);
294 break;
295 case PCE_REQ_SET_TARGET_STATE:
296 stm_.SetTargetState(msg.arg1_);
297 break;
298 case PCE_REQ_TRANSIT_TARGET_STATE:
299 stm_.TransitTargetState();
300 break;
301 case PCE_OBEX_DISCONNECTED:
302 Transition(PCE_DISCONNECTING_STATE);
303 Transition(PCE_DISCONNECTED_STATE);
304 break;
305 case PCE_TRANSPORT_FAILED:
306 ProcessObexTransportFailed(msg);
307 break;
308 case PCE_PASSWORD_INPUT:
309 ProcessPasswordInput(msg);
310 break;
311 default:
312 return false;
313 }
314
315 PBAP_PCE_LOG_INFO("%{public}s end, msg.what_=[%{public}d]", __PRETTY_FUNCTION__, msg.what_);
316 return true;
317 }
318
PasswordInput(const PbapPcePasswordInputMsg & pwdInputMsg) const319 void PceConnectingState::PasswordInput(const PbapPcePasswordInputMsg &pwdInputMsg) const
320 {
321 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
322 if (!authChallenge_) {
323 return;
324 }
325 if (pwdInputMsg.GetPassword() == "") {
326 return;
327 }
328 stm_.SetPassword(pwdInputMsg.GetPassword());
329 stm_.SetUserId(pwdInputMsg.GetUserId());
330
331 SendRequest();
332 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
333 }
334
SendRequest() const335 void PceConnectingState::SendRequest() const
336 {
337 PBAP_PCE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
338 if (header_ == nullptr) {
339 PBAP_PCE_LOG_ERROR("%{public}s end, header_ is nullptr", __PRETTY_FUNCTION__);
340 return;
341 }
342 // get challenge
343 auto tvlHeader = header_->GetItemAuthChallenges();
344 auto &tvlParam = tvlHeader->GetTlvParamters();
345 auto challenge = static_cast<ObexDigestChallenge *>(tvlParam.get());
346
347 // Authenticate Response
348 // Carries the digest-response string. This is the response to the challenge from the Client.
349 ObexDigestResponse response;
350 std::vector<uint8_t> requestDigest =
351 ObexUtils::MakeRequestDigest(authNonce_.data(), authNonce_.size(), stm_.GetPassword());
352 response.AppendRequestDigest(requestDigest.data(), requestDigest.size());
353 if (authNeedUser_ && stm_.GetUserId().size() > 0) {
354 const uint8_t *userId = reinterpret_cast<const uint8_t *>(stm_.GetUserId().c_str());
355 response.AppendUserId(userId, stm_.GetUserId().size());
356 }
357 response.AppendNonce(authNonce_.data(), authNonce_.size());
358
359 stm_.GetObexClient().Reconnect(*challenge, response);
360 PBAP_PCE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
361 }
362 } // namespace bluetooth
363 } // namespace OHOS