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