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