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 #include <cutils/log.h>
26 #include "bt_target.h"
27
28 #include <string.h>
29 #include "btm_ble_api.h"
30 #include "common/metrics.h"
31 #include "l2c_api.h"
32
33 #include "smp_int.h"
34
35 static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt);
36
37 static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr,
38 bool connected, uint16_t reason,
39 tBT_TRANSPORT transport);
40 static void smp_data_received(uint16_t channel, const RawAddress& bd_addr,
41 BT_HDR* p_buf);
42
43 static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr,
44 bool connected, uint16_t reason,
45 tBT_TRANSPORT transport);
46 static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr,
47 BT_HDR* p_buf);
48
49 /*******************************************************************************
50 *
51 * Function smp_l2cap_if_init
52 *
53 * Description This function is called during the SMP task startup
54 * to register interface functions with L2CAP.
55 *
56 ******************************************************************************/
smp_l2cap_if_init(void)57 void smp_l2cap_if_init(void) {
58 tL2CAP_FIXED_CHNL_REG fixed_reg;
59 SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
60
61 fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
62 fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
63 fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback;
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(uint16_t channel,const RawAddress & bd_addr,bool connected,uint16_t reason,tBT_TRANSPORT transport)87 static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr,
88 bool connected, uint16_t reason,
89 tBT_TRANSPORT transport) {
90 tSMP_CB* p_cb = &smp_cb;
91 tSMP_INT_DATA int_data;
92
93 SMP_TRACE_EVENT("%s: SMDBG l2c: bd_addr=%s, p_cb->pairing_bda=%s", __func__,
94 bd_addr.ToString().c_str(),
95 p_cb->pairing_bda.ToString().c_str());
96
97 if (transport == BT_TRANSPORT_BR_EDR || bd_addr.IsEmpty()) return;
98
99 if (bd_addr == p_cb->pairing_bda) {
100 VLOG(2) << __func__ << " for pairing BDA: " << bd_addr
101 << " Event: " << ((connected) ? "connected" : "disconnected");
102
103 if (connected) {
104 if (!p_cb->connect_initialized) {
105 p_cb->connect_initialized = true;
106 /* initiating connection established */
107 p_cb->role = L2CA_GetBleConnRole(bd_addr);
108
109 /* initialize local i/r key to be default keys */
110 p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY;
111 p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
112 p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
113 smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
114 }
115 } else {
116 int_data.reason = reason;
117 /* Disconnected while doing security */
118 smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
119 }
120 }
121 }
122
123 /*******************************************************************************
124 *
125 * Function smp_data_received
126 *
127 * Description This function is called when data is received from L2CAP on
128 * SMP channel.
129 *
130 *
131 * Returns void
132 *
133 ******************************************************************************/
smp_data_received(uint16_t channel,const RawAddress & bd_addr,BT_HDR * p_buf)134 static void smp_data_received(uint16_t channel, const RawAddress& bd_addr,
135 BT_HDR* p_buf) {
136 tSMP_CB* p_cb = &smp_cb;
137 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
138 uint8_t cmd;
139
140 if (p_buf->len < 1) {
141 android_errorWriteLog(0x534e4554, "111215315");
142 SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1",
143 __func__, p_buf->len);
144 osi_free(p_buf);
145 return;
146 }
147
148 STREAM_TO_UINT8(cmd, p);
149
150 SMP_TRACE_EVENT("%s: SMDBG l2c, cmd=0x%x", __func__, cmd);
151
152 /* sanity check */
153 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
154 SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
155 osi_free(p_buf);
156 return;
157 }
158
159 /* reject the pairing request if there is an on-going SMP pairing */
160 if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) {
161 if ((p_cb->state == SMP_STATE_IDLE) &&
162 (p_cb->br_state == SMP_BR_STATE_IDLE) &&
163 !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
164 p_cb->role = L2CA_GetBleConnRole(bd_addr);
165 p_cb->pairing_bda = bd_addr;
166 } else if (bd_addr != p_cb->pairing_bda) {
167 osi_free(p_buf);
168 smp_reject_unexpected_pairing_command(bd_addr);
169 return;
170 }
171 /* else, out of state pairing request/security request received, passed into
172 * SM */
173 }
174
175 if (bd_addr == p_cb->pairing_bda) {
176 alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
177 smp_rsp_timeout, NULL);
178
179 smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
180 p_buf->data + p_buf->offset, p_buf->len);
181
182 if (cmd == SMP_OPCODE_CONFIRM) {
183 SMP_TRACE_DEBUG(
184 "in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
185 "loc_auth_req = 0x%02x",
186 __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
187
188 if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
189 (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
190 cmd = SMP_OPCODE_PAIR_COMMITM;
191 }
192 }
193
194 p_cb->rcvd_cmd_code = cmd;
195 p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
196 tSMP_INT_DATA smp_int_data;
197 smp_int_data.p_data = p;
198 smp_sm_event(p_cb, cmd, &smp_int_data);
199 }
200
201 osi_free(p_buf);
202 }
203
204 /*******************************************************************************
205 *
206 * Function smp_tx_complete_callback
207 *
208 * Description SMP channel tx complete callback
209 *
210 ******************************************************************************/
smp_tx_complete_callback(uint16_t cid,uint16_t num_pkt)211 static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt) {
212 tSMP_CB* p_cb = &smp_cb;
213
214 if (p_cb->total_tx_unacked >= num_pkt)
215 p_cb->total_tx_unacked -= num_pkt;
216 else
217 SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt);
218
219 if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) {
220 tSMP_INT_DATA smp_int_data;
221 smp_int_data.status = SMP_SUCCESS;
222 if (cid == L2CAP_SMP_CID) {
223 smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
224 } else {
225 smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
226 }
227 }
228 }
229
230 /*******************************************************************************
231 *
232 * Function smp_br_connect_callback
233 *
234 * Description This callback function is called by L2CAP to indicate that
235 * SMP BR channel is
236 * connected (conn = true)/disconnected (conn = false).
237 *
238 ******************************************************************************/
smp_br_connect_callback(uint16_t channel,const RawAddress & bd_addr,bool connected,uint16_t reason,tBT_TRANSPORT transport)239 static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr,
240 bool connected, uint16_t reason,
241 tBT_TRANSPORT transport) {
242 tSMP_CB* p_cb = &smp_cb;
243 tSMP_INT_DATA int_data;
244
245 SMP_TRACE_EVENT("%s", __func__);
246
247 if (transport != BT_TRANSPORT_BR_EDR) {
248 SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__,
249 transport);
250 return;
251 }
252
253 VLOG(1) << __func__ << " for pairing BDA: " << bd_addr
254 << ", pairing_bda:" << p_cb->pairing_bda
255 << " Event: " << ((connected) ? "connected" : "disconnected");
256
257 if (bd_addr != p_cb->pairing_bda) return;
258
259 if (connected) {
260 if (!p_cb->connect_initialized) {
261 p_cb->connect_initialized = true;
262 /* initialize local i/r key to be default keys */
263 p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY;
264 p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
265 p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
266 smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
267 }
268 } else {
269 int_data.reason = reason;
270 /* Disconnected while doing security */
271 smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
272 }
273 }
274
275 /*******************************************************************************
276 *
277 * Function smp_br_data_received
278 *
279 * Description This function is called when data is received from L2CAP on
280 * SMP BR channel.
281 *
282 * Returns void
283 *
284 ******************************************************************************/
smp_br_data_received(uint16_t channel,const RawAddress & bd_addr,BT_HDR * p_buf)285 static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr,
286 BT_HDR* p_buf) {
287 tSMP_CB* p_cb = &smp_cb;
288 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
289 uint8_t cmd;
290 SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
291
292 if (p_buf->len < 1) {
293 android_errorWriteLog(0x534e4554, "111215315");
294 SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1",
295 __func__, p_buf->len);
296 osi_free(p_buf);
297 return;
298 }
299
300 STREAM_TO_UINT8(cmd, p);
301
302 /* sanity check */
303 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
304 SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
305 osi_free(p_buf);
306 return;
307 }
308
309 /* reject the pairing request if there is an on-going SMP pairing */
310 if (SMP_OPCODE_PAIRING_REQ == cmd) {
311 if ((p_cb->state == SMP_STATE_IDLE) &&
312 (p_cb->br_state == SMP_BR_STATE_IDLE)) {
313 p_cb->role = HCI_ROLE_SLAVE;
314 p_cb->smp_over_br = true;
315 p_cb->pairing_bda = bd_addr;
316 } else if (bd_addr != p_cb->pairing_bda) {
317 osi_free(p_buf);
318 smp_reject_unexpected_pairing_command(bd_addr);
319 return;
320 }
321 /* else, out of state pairing request received, passed into State Machine */
322 }
323
324 if (bd_addr == p_cb->pairing_bda) {
325 alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
326 smp_rsp_timeout, NULL);
327
328 smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
329 p_buf->data + p_buf->offset, p_buf->len);
330
331 p_cb->rcvd_cmd_code = cmd;
332 p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
333 tSMP_INT_DATA smp_int_data;
334 smp_int_data.p_data = p;
335 smp_br_state_machine_event(p_cb, cmd, &smp_int_data);
336 }
337
338 osi_free(p_buf);
339 }
340