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