1 /******************************************************************************
3 * Copyright (C) 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This file contains functions for the SMP L2Cap interface
23 ******************************************************************************/
25 #include "bt_target.h"
27 #if SMP_INCLUDED == TRUE
30 #include "btm_ble_api.h"
36 extern fixed_queue_t *btu_general_alarm_queue;
38 static void smp_tx_complete_callback(UINT16 cid, UINT16 num_pkt);
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);
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);
48 /*******************************************************************************
50 ** Function smp_l2cap_if_init
52 ** Description This function is called during the SMP task startup
53 ** to register interface functions with L2CAP.
55 *******************************************************************************/
56 void smp_l2cap_if_init (void)
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;
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;
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 */
74 L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg);
76 fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
77 fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
79 L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg);
82 /*******************************************************************************
84 ** Function smp_connect_callback
86 ** Description This callback function is called by L2CAP to indicate that
88 ** connected (conn = TRUE)/disconnected (conn = FALSE).
90 *******************************************************************************/
91 static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
92 tBT_TRANSPORT transport)
94 tSMP_CB *p_cb = &smp_cb;
95 tSMP_INT_DATA int_data;
96 BD_ADDR dummy_bda = {0};
98 SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__);
100 if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0)
103 if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)
105 SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s",
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");
113 if(!p_cb->connect_initialized)
115 p_cb->connect_initialized = TRUE;
116 /* initiating connection established */
117 p_cb->role = L2CA_GetBleConnRole(bd_addr);
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);
128 int_data.reason = reason;
129 /* Disconnected while doing security */
130 smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
135 /*******************************************************************************
137 ** Function smp_data_received
139 ** Description This function is called when data is received from L2CAP on
145 *******************************************************************************/
146 static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
148 tSMP_CB *p_cb = &smp_cb;
149 UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
151 SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__);
153 STREAM_TO_UINT8(cmd, p);
156 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd))
158 SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
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)
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))
169 p_cb->role = L2CA_GetBleConnRole(bd_addr);
170 memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
172 else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
175 smp_reject_unexpected_pairing_command(bd_addr);
178 /* else, out of state pairing request/security request received, passed into SM */
181 if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
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);
187 if (cmd == SMP_OPCODE_CONFIRM)
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);
193 if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
194 (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT))
196 cmd = SMP_OPCODE_PAIR_COMMITM;
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);
208 /*******************************************************************************
210 ** Function smp_tx_complete_callback
212 ** Description SMP channel tx complete callback
214 *******************************************************************************/
215 static void smp_tx_complete_callback (UINT16 cid, UINT16 num_pkt)
217 tSMP_CB *p_cb = &smp_cb;
219 if (p_cb->total_tx_unacked >= num_pkt)
220 p_cb->total_tx_unacked -= num_pkt;
222 SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__,num_pkt);
224 UINT8 reason = SMP_SUCCESS;
225 if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete)
227 if (cid == L2CAP_SMP_CID)
228 smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
230 smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
234 /*******************************************************************************
236 ** Function smp_br_connect_callback
238 ** Description This callback function is called by L2CAP to indicate that
240 ** connected (conn = TRUE)/disconnected (conn = FALSE).
242 *******************************************************************************/
243 static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected,
244 UINT16 reason, tBT_TRANSPORT transport)
246 tSMP_CB *p_cb = &smp_cb;
247 tSMP_INT_DATA int_data;
249 SMP_TRACE_EVENT ("%s", __func__);
251 if (transport != BT_TRANSPORT_BR_EDR)
253 SMP_TRACE_WARNING("%s is called on unexpected transport %d",
254 __func__, transport);
258 if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0))
261 SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x Event: %s",
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");
269 if(!p_cb->connect_initialized)
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);
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);
287 /*******************************************************************************
289 ** Function smp_br_data_received
291 ** Description This function is called when data is received from L2CAP on
296 *******************************************************************************/
297 static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
299 tSMP_CB *p_cb = &smp_cb;
300 UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
302 SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
304 STREAM_TO_UINT8(cmd, p);
307 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd))
309 SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
314 /* reject the pairing request if there is an on-going SMP pairing */
315 if (SMP_OPCODE_PAIRING_REQ == cmd)
317 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 = TRUE;
321 memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
323 else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
326 smp_reject_unexpected_pairing_command(bd_addr);
329 /* else, out of state pairing request received, passed into State Machine */
332 if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
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);
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);
345 #endif /* SMP_INCLUDED == TRUE */