• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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