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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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