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