1 /******************************************************************************
2 *
3 * Copyright 1999-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * This file contains functions for the SMP L2Cap interface
22 *
23 ******************************************************************************/
24
25 #define LOG_TAG "bluetooth"
26
27 #include "bt_target.h"
28
29 #include <string.h>
30 #include "btm_ble_api.h"
31 #include "common/metrics.h"
32 #include "l2c_api.h"
33 #include "main/shim/dumpsys.h"
34 #include "osi/include/log.h"
35 #include "osi/include/osi.h" // UNUSED_ATTR
36 #include "smp_int.h"
37
38 static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr,
39 bool connected, uint16_t reason,
40 tBT_TRANSPORT transport);
41 static void smp_data_received(uint16_t channel, const RawAddress& bd_addr,
42 BT_HDR* p_buf);
43
44 static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr,
45 bool connected, uint16_t reason,
46 tBT_TRANSPORT transport);
47 static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr,
48 BT_HDR* p_buf);
49
50 /*******************************************************************************
51 *
52 * Function smp_l2cap_if_init
53 *
54 * Description This function is called during the SMP task startup
55 * to register interface functions with L2CAP.
56 *
57 ******************************************************************************/
smp_l2cap_if_init(void)58 void smp_l2cap_if_init(void) {
59 tL2CAP_FIXED_CHNL_REG fixed_reg;
60 SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
61
62 fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
63 fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
64
65 fixed_reg.pL2CA_FixedCong_Cb =
66 NULL; /* do not handle congestion on this channel */
67 fixed_reg.default_idle_tout =
68 60; /* set 60 seconds timeout, 0xffff default idle timeout */
69
70 L2CA_RegisterFixedChannel(L2CAP_SMP_CID, &fixed_reg);
71
72 fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
73 fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
74
75 L2CA_RegisterFixedChannel(L2CAP_SMP_BR_CID, &fixed_reg);
76 }
77
78 /*******************************************************************************
79 *
80 * Function smp_connect_callback
81 *
82 * Description This callback function is called by L2CAP to indicate that
83 * SMP channel is
84 * connected (conn = true)/disconnected (conn = false).
85 *
86 ******************************************************************************/
smp_connect_callback(UNUSED_ATTR uint16_t channel,const RawAddress & bd_addr,bool connected,UNUSED_ATTR uint16_t reason,tBT_TRANSPORT transport)87 static void smp_connect_callback(UNUSED_ATTR uint16_t channel,
88 const RawAddress& bd_addr, bool connected,
89 UNUSED_ATTR uint16_t reason,
90 tBT_TRANSPORT transport) {
91 tSMP_CB* p_cb = &smp_cb;
92 tSMP_INT_DATA int_data;
93
94 if (bd_addr.IsEmpty()) {
95 LOG_WARN("Received unexpected callback for empty address");
96 return;
97 }
98
99 if (transport == BT_TRANSPORT_BR_EDR) {
100 LOG_WARN("Received unexpected callback on classic channel peer:%s",
101 PRIVATE_ADDRESS(bd_addr));
102 return;
103 }
104
105 if (connected) {
106 LOG_DEBUG("SMP Received connect callback bd_addr:%s transport:%s",
107 PRIVATE_ADDRESS(bd_addr), bt_transport_text(transport).c_str());
108 } else {
109 LOG_DEBUG("SMP Received disconnect callback bd_addr:%s transport:%s",
110 PRIVATE_ADDRESS(bd_addr), bt_transport_text(transport).c_str());
111 }
112
113 if (bd_addr == p_cb->pairing_bda) {
114 LOG_DEBUG("Received callback for device in pairing process:%s state:%s",
115 PRIVATE_ADDRESS(bd_addr),
116 (connected) ? "connected" : "disconnected");
117
118 if (connected) {
119 if (!p_cb->connect_initialized) {
120 p_cb->connect_initialized = true;
121 /* initiating connection established */
122 p_cb->role = L2CA_GetBleConnRole(bd_addr);
123
124 /* initialize local i/r key to be default keys */
125 p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY;
126 p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
127 p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
128 smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
129 }
130 } else {
131 /* Disconnected while doing security */
132 smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
133 }
134 }
135 }
136
137 /*******************************************************************************
138 *
139 * Function smp_data_received
140 *
141 * Description This function is called when data is received from L2CAP on
142 * SMP channel.
143 *
144 *
145 * Returns void
146 *
147 ******************************************************************************/
smp_data_received(uint16_t channel,const RawAddress & bd_addr,BT_HDR * p_buf)148 static void smp_data_received(uint16_t channel, const RawAddress& bd_addr,
149 BT_HDR* p_buf) {
150 tSMP_CB* p_cb = &smp_cb;
151 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
152 uint8_t cmd;
153
154 if (p_buf->len < 1) {
155 android_errorWriteLog(0x534e4554, "111215315");
156 SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1",
157 __func__, p_buf->len);
158 osi_free(p_buf);
159 return;
160 }
161
162 STREAM_TO_UINT8(cmd, p);
163
164 SMP_TRACE_EVENT("%s: SMDBG l2c, cmd=0x%x", __func__, cmd);
165
166 /* sanity check */
167 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
168 SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
169 osi_free(p_buf);
170 return;
171 }
172
173 /* reject the pairing request if there is an on-going SMP pairing */
174 if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) {
175 if ((p_cb->state == SMP_STATE_IDLE) &&
176 (p_cb->br_state == SMP_BR_STATE_IDLE) &&
177 !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
178 p_cb->role = L2CA_GetBleConnRole(bd_addr);
179 p_cb->pairing_bda = bd_addr;
180 } else if (bd_addr != p_cb->pairing_bda) {
181 osi_free(p_buf);
182 smp_reject_unexpected_pairing_command(bd_addr);
183 return;
184 }
185 /* else, out of state pairing request/security request received, passed into
186 * SM */
187 }
188
189 if (bd_addr == p_cb->pairing_bda) {
190 alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
191 smp_rsp_timeout, NULL);
192
193 smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
194 p_buf->data + p_buf->offset, p_buf->len);
195
196 if (cmd == SMP_OPCODE_CONFIRM) {
197 SMP_TRACE_DEBUG(
198 "in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
199 "loc_auth_req = 0x%02x",
200 __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
201
202 if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
203 (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
204 cmd = SMP_OPCODE_PAIR_COMMITM;
205 }
206 }
207
208 p_cb->rcvd_cmd_code = cmd;
209 p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
210 tSMP_INT_DATA smp_int_data;
211 smp_int_data.p_data = p;
212 smp_sm_event(p_cb, static_cast<tSMP_EVENT>(cmd), &smp_int_data);
213 }
214
215 osi_free(p_buf);
216 }
217
218 /*******************************************************************************
219 *
220 * Function smp_br_connect_callback
221 *
222 * Description This callback function is called by L2CAP to indicate that
223 * SMP BR channel is
224 * connected (conn = true)/disconnected (conn = false).
225 *
226 ******************************************************************************/
smp_br_connect_callback(uint16_t channel,const RawAddress & bd_addr,bool connected,uint16_t reason,tBT_TRANSPORT transport)227 static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr,
228 bool connected, uint16_t reason,
229 tBT_TRANSPORT transport) {
230 tSMP_CB* p_cb = &smp_cb;
231 tSMP_INT_DATA int_data;
232
233 SMP_TRACE_EVENT("%s", __func__);
234
235 if (transport != BT_TRANSPORT_BR_EDR) {
236 SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__,
237 transport);
238 return;
239 }
240
241 VLOG(1) << __func__ << " for pairing BDA: " << bd_addr
242 << ", pairing_bda:" << p_cb->pairing_bda
243 << " Event: " << ((connected) ? "connected" : "disconnected");
244
245 if (bd_addr != p_cb->pairing_bda) return;
246
247 if (connected) {
248 if (!p_cb->connect_initialized) {
249 p_cb->connect_initialized = true;
250 /* initialize local i/r key to be default keys */
251 p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY;
252 p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
253 p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
254 smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
255 }
256 } else {
257 /* Disconnected while doing security */
258 smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
259 }
260 }
261
262 /*******************************************************************************
263 *
264 * Function smp_br_data_received
265 *
266 * Description This function is called when data is received from L2CAP on
267 * SMP BR channel.
268 *
269 * Returns void
270 *
271 ******************************************************************************/
smp_br_data_received(uint16_t channel,const RawAddress & bd_addr,BT_HDR * p_buf)272 static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr,
273 BT_HDR* p_buf) {
274 tSMP_CB* p_cb = &smp_cb;
275 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
276 uint8_t cmd;
277 SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
278
279 if (p_buf->len < 1) {
280 android_errorWriteLog(0x534e4554, "111215315");
281 SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1",
282 __func__, p_buf->len);
283 osi_free(p_buf);
284 return;
285 }
286
287 STREAM_TO_UINT8(cmd, p);
288
289 /* sanity check */
290 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
291 SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
292 osi_free(p_buf);
293 return;
294 }
295
296 /* reject the pairing request if there is an on-going SMP pairing */
297 if (SMP_OPCODE_PAIRING_REQ == cmd) {
298 if ((p_cb->state == SMP_STATE_IDLE) &&
299 (p_cb->br_state == SMP_BR_STATE_IDLE)) {
300 p_cb->role = HCI_ROLE_PERIPHERAL;
301 p_cb->smp_over_br = true;
302 p_cb->pairing_bda = bd_addr;
303 } else if (bd_addr != p_cb->pairing_bda) {
304 osi_free(p_buf);
305 smp_reject_unexpected_pairing_command(bd_addr);
306 return;
307 }
308 /* else, out of state pairing request received, passed into State Machine */
309 }
310
311 if (bd_addr == p_cb->pairing_bda) {
312 alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
313 smp_rsp_timeout, NULL);
314
315 smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
316 p_buf->data + p_buf->offset, p_buf->len);
317
318 p_cb->rcvd_cmd_code = cmd;
319 p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
320 tSMP_INT_DATA smp_int_data;
321 smp_int_data.p_data = p;
322 smp_br_state_machine_event(p_cb, static_cast<tSMP_EVENT>(cmd),
323 &smp_int_data);
324 }
325
326 osi_free(p_buf);
327 }
328