• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright (C) 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 "common/bt_target.h"
26 #include "osi/allocator.h"
27 
28 #if SMP_INCLUDED == 1
29 
30 #include <string.h>
31 #include "stack/btm_ble_api.h"
32 #include "stack/l2c_api.h"
33 
34 #include "smp_int.h"
35 
36 
37 static void smp_tx_complete_callback(UINT16 cid, UINT16 num_pkt);
38 #if (BLE_INCLUDED == 1)
39 
40 static void smp_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
41                                  tBT_TRANSPORT transport);
42 static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf);
43 #endif  ///BLE_INCLUDED == 1
44 #if (CLASSIC_BT_INCLUDED == 1)
45 static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
46                                     tBT_TRANSPORT transport);
47 static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf);
48 #endif  ///CLASSIC_BT_INCLUDED == 1
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 {
60     tL2CAP_FIXED_CHNL_REG  fixed_reg;
61     SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
62     fixed_reg.fixed_chnl_opts.mode         = L2CAP_FCR_BASIC_MODE;
63     fixed_reg.fixed_chnl_opts.max_transmit = 0;
64     fixed_reg.fixed_chnl_opts.rtrans_tout  = 0;
65     fixed_reg.fixed_chnl_opts.mon_tout     = 0;
66     fixed_reg.fixed_chnl_opts.mps          = 0;
67     fixed_reg.fixed_chnl_opts.tx_win_sz    = 0;
68 
69     fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback;
70 
71     fixed_reg.pL2CA_FixedCong_Cb = NULL;    /* do not handle congestion on this channel */
72     fixed_reg.default_idle_tout  = 0;       /* set 0 seconds timeout, 0xffff default idle timeout.
73                                             This timeout is used to wait for the end of the pairing
74                                             and then make a disconnect request, setting a larger value
75                                             will cause the disconnect event to go back up for a long time.
76                                             Set to 0 will be disconnected directly, and it will come up
77                                             pairing failure, so it will not cause adverse effects. */
78 #if (BLE_INCLUDED == 1)
79     fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
80     fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
81     L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg);
82 #endif  ///BLE_INCLUDED == 1
83 
84 #if (CLASSIC_BT_INCLUDED == 1)
85     fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
86     fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
87 
88     L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg);
89 #endif  ///CLASSIC_BT_INCLUDED == 1
90 }
91 
92 #if (BLE_INCLUDED == 1)
93 /*******************************************************************************
94 **
95 ** Function         smp_connect_callback
96 **
97 ** Description      This callback function is called by L2CAP to indicate that
98 **                  SMP channel is
99 **                      connected (conn = 1)/disconnected (conn = 0).
100 **
101 *******************************************************************************/
smp_connect_callback(UINT16 channel,BD_ADDR bd_addr,BOOLEAN connected,UINT16 reason,tBT_TRANSPORT transport)102 static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
103                                   tBT_TRANSPORT transport)
104 {
105     tSMP_CB   *p_cb = &smp_cb;
106     tSMP_INT_DATA   int_data;
107     BD_ADDR dummy_bda = {0};
108 
109     SMP_TRACE_EVENT ("SMDBG l2c %s\n", __FUNCTION__);
110 
111     if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) {
112         return;
113     }
114     if(!connected && &p_cb->rsp_timer_ent) {
115         //free timer
116         btu_free_timer(&p_cb->rsp_timer_ent);
117     }
118     if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
119         SMP_TRACE_EVENT ("%s()  for pairing BDA: %08x%04x  Event: %s\n",
120                          __FUNCTION__,
121                          (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
122                          (bd_addr[4] << 8) + bd_addr[5],
123                          (connected) ? "connected" : "disconnected");
124 
125         if (connected) {
126             if (!p_cb->connect_initialized) {
127                 p_cb->connect_initialized = 1;
128                 /* initiating connection established */
129                 p_cb->role = L2CA_GetBleConnRole(bd_addr);
130 
131                 /* initialize local i/r key to be default keys */
132                 p_cb->local_r_key = p_cb->local_i_key =  SMP_SEC_DEFAULT_KEY;
133                 p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
134                 p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
135                 smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
136             }
137         } else {
138             int_data.reason = reason;
139             /* Disconnected while doing security */
140             smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
141         }
142     }
143 }
144 
145 /*******************************************************************************
146 **
147 ** Function         smp_data_received
148 **
149 ** Description      This function is called when data is received from L2CAP on
150 **                  SMP channel.
151 **
152 **
153 ** Returns          void
154 **
155 *******************************************************************************/
smp_data_received(UINT16 channel,BD_ADDR bd_addr,BT_HDR * p_buf)156 static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
157 {
158     tSMP_CB *p_cb = &smp_cb;
159     UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
160     UINT8   cmd ;
161     SMP_TRACE_EVENT ("\nSMDBG l2c %s\n", __FUNCTION__);
162 
163     STREAM_TO_UINT8(cmd, p);
164 
165     /* sanity check */
166     if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
167         SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x\n", cmd);
168         osi_free (p_buf);
169         return;
170     }
171 
172     /* reject the pairing request if there is an on-going SMP pairing */
173     if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) {
174         if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) &&
175             !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
176             p_cb->role = L2CA_GetBleConnRole(bd_addr);
177             memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
178         } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
179             osi_free (p_buf);
180             smp_reject_unexpected_pairing_command(bd_addr);
181             return;
182         }
183         /* else, out of state pairing request/security request received, passed into SM */
184     }
185 
186     if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
187         btu_stop_timer (&p_cb->rsp_timer_ent);
188         btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
189                          SMP_WAIT_FOR_RSP_TOUT);
190 
191         if (cmd == SMP_OPCODE_CONFIRM) {
192             SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
193                              "loc_auth_req = 0x%02x\n",
194                              __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
195 
196             if ((p_cb->peer_auth_req  & SMP_SC_SUPPORT_BIT) &&
197                     (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
198                 cmd = SMP_OPCODE_PAIR_COMMITM;
199             }
200         }
201 
202         p_cb->rcvd_cmd_code = cmd;
203         p_cb->rcvd_cmd_len = (UINT8) p_buf->len;
204         smp_sm_event(p_cb, cmd, p);
205     }
206 
207     osi_free (p_buf);
208 }
209 #endif  ///BLE_INCLUDED == 1
210 
211 /*******************************************************************************
212 **
213 ** Function         smp_tx_complete_callback
214 **
215 ** Description      SMP channel tx complete callback
216 **
217 *******************************************************************************/
smp_tx_complete_callback(UINT16 cid,UINT16 num_pkt)218 static void smp_tx_complete_callback (UINT16 cid, UINT16 num_pkt)
219 {
220     tSMP_CB *p_cb = &smp_cb;
221 
222     if (p_cb->total_tx_unacked >= num_pkt) {
223         p_cb->total_tx_unacked -= num_pkt;
224     } else {
225         SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt);
226     }
227 
228     UINT8 reason = SMP_SUCCESS;
229     if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) {
230         if (cid == L2CAP_SMP_CID) {
231             smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
232         } else {
233 #if (CLASSIC_BT_INCLUDED == 1)
234             smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
235 #endif  ///CLASSIC_BT_INCLUDED == 1
236         }
237     }
238 }
239 
240 /*******************************************************************************
241 **
242 ** Function         smp_br_connect_callback
243 **
244 ** Description      This callback function is called by L2CAP to indicate that
245 **                  SMP BR channel is
246 **                      connected (conn = 1)/disconnected (conn = 0).
247 **
248 *******************************************************************************/
249 #if (CLASSIC_BT_INCLUDED == 1)
smp_br_connect_callback(UINT16 channel,BD_ADDR bd_addr,BOOLEAN connected,UINT16 reason,tBT_TRANSPORT transport)250 static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected,
251                                     UINT16 reason, tBT_TRANSPORT transport)
252 {
253     tSMP_CB *p_cb = &smp_cb;
254     tSMP_INT_DATA int_data;
255 
256     SMP_TRACE_EVENT ("%s", __func__);
257 
258     if (transport != BT_TRANSPORT_BR_EDR) {
259         SMP_TRACE_EVENT ("%s is called on unexpected transport %d\n",
260                           __func__, transport);
261         return;
262     }
263 
264     if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) {
265         return;
266     }
267 
268     SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x  Event: %s\n",
269                      __func__,
270                      (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
271                      (bd_addr[4] << 8) + bd_addr[5],
272                      (connected) ? "connected" : "disconnected");
273 
274     if (connected) {
275         if (!p_cb->connect_initialized) {
276             p_cb->connect_initialized = 1;
277             /* initialize local i/r key to be default keys */
278             p_cb->local_r_key = p_cb->local_i_key =  SMP_BR_SEC_DEFAULT_KEY;
279             p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
280             p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
281             smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
282         }
283     } else {
284         int_data.reason = reason;
285         /* Disconnected while doing security */
286         smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
287     }
288 }
289 
290 /*******************************************************************************
291 **
292 ** Function         smp_br_data_received
293 **
294 ** Description      This function is called when data is received from L2CAP on
295 **                  SMP BR channel.
296 **
297 ** Returns          void
298 **
299 *******************************************************************************/
smp_br_data_received(UINT16 channel,BD_ADDR bd_addr,BT_HDR * p_buf)300 static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
301 {
302     tSMP_CB *p_cb = &smp_cb;
303     UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
304     UINT8   cmd ;
305     SMP_TRACE_EVENT ("SMDBG l2c %s\n", __func__);
306 
307     STREAM_TO_UINT8(cmd, p);
308 
309     /* sanity check */
310     if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
311         SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
312         osi_free(p_buf);
313         return;
314     }
315 
316     /* reject the pairing request if there is an on-going SMP pairing */
317     if (SMP_OPCODE_PAIRING_REQ == cmd) {
318         if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) {
319             p_cb->role = HCI_ROLE_SLAVE;
320             p_cb->smp_over_br = 1;
321             memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
322         } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
323             osi_free (p_buf);
324             smp_reject_unexpected_pairing_command(bd_addr);
325             return;
326         }
327         /* else, out of state pairing request received, passed into State Machine */
328     }
329 
330     if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
331         btu_stop_timer (&p_cb->rsp_timer_ent);
332         btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
333                          SMP_WAIT_FOR_RSP_TOUT);
334 
335         p_cb->rcvd_cmd_code = cmd;
336         p_cb->rcvd_cmd_len = (UINT8) p_buf->len;
337         smp_br_state_machine_event(p_cb, cmd, p);
338     }
339 
340     osi_free (p_buf);
341 }
342 #endif  /* CLASSIC_BT_INCLUDED == 1 */
343 
344 #endif /* SMP_INCLUDED == 1 */
345