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