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#include <string.h> 28#include "btm_ble_api.h" 29#include "l2c_api.h" 30 31#include "smp_int.h" 32 33static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt); 34 35static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr, 36 bool connected, uint16_t reason, 37 tBT_TRANSPORT transport); 38static void smp_data_received(uint16_t channel, const RawAddress& bd_addr, 39 BT_HDR* p_buf); 40 41static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr, 42 bool connected, uint16_t reason, 43 tBT_TRANSPORT transport); 44static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr, 45 BT_HDR* p_buf); 46 47/******************************************************************************* 48 * 49 * Function smp_l2cap_if_init 50 * 51 * Description This function is called during the SMP task startup 52 * to register interface functions with L2CAP. 53 * 54 ******************************************************************************/ 55void smp_l2cap_if_init(void) { 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 = 70 NULL; /* do not handle congestion on this channel */ 71 fixed_reg.default_idle_tout = 72 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 ******************************************************************************/ 91static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr, 92 bool connected, uint16_t reason, 93 tBT_TRANSPORT transport) { 94 tSMP_CB* p_cb = &smp_cb; 95 tSMP_INT_DATA int_data; 96 97 SMP_TRACE_EVENT("SMDBG l2c %s", __func__); 98 99 if (transport == BT_TRANSPORT_BR_EDR || bd_addr.IsEmpty()) return; 100 101 if (bd_addr == p_cb->pairing_bda) { 102 VLOG(2) << __func__ << " for pairing BDA: " << bd_addr 103 << " Event: " << ((connected) ? "connected" : "disconnected"); 104 105 if (connected) { 106 if (!p_cb->connect_initialized) { 107 p_cb->connect_initialized = true; 108 /* initiating connection established */ 109 p_cb->role = L2CA_GetBleConnRole(bd_addr); 110 111 /* initialize local i/r key to be default keys */ 112 p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY; 113 p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ; 114 p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; 115 smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL); 116 } 117 } else { 118 int_data.reason = reason; 119 /* Disconnected while doing security */ 120 smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data); 121 } 122 } 123} 124 125/******************************************************************************* 126 * 127 * Function smp_data_received 128 * 129 * Description This function is called when data is received from L2CAP on 130 * SMP channel. 131 * 132 * 133 * Returns void 134 * 135 ******************************************************************************/ 136static void smp_data_received(uint16_t channel, const RawAddress& bd_addr, 137 BT_HDR* p_buf) { 138 tSMP_CB* p_cb = &smp_cb; 139 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset; 140 uint8_t cmd; 141 SMP_TRACE_EVENT("SMDBG l2c %s", __func__); 142 143 STREAM_TO_UINT8(cmd, p); 144 145 /* sanity check */ 146 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { 147 SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd); 148 osi_free(p_buf); 149 return; 150 } 151 152 /* reject the pairing request if there is an on-going SMP pairing */ 153 if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) { 154 if ((p_cb->state == SMP_STATE_IDLE) && 155 (p_cb->br_state == SMP_BR_STATE_IDLE) && 156 !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { 157 p_cb->role = L2CA_GetBleConnRole(bd_addr); 158 p_cb->pairing_bda = bd_addr; 159 } else if (bd_addr != p_cb->pairing_bda) { 160 osi_free(p_buf); 161 smp_reject_unexpected_pairing_command(bd_addr); 162 return; 163 } 164 /* else, out of state pairing request/security request received, passed into 165 * SM */ 166 } 167 168 if (bd_addr == p_cb->pairing_bda) { 169 alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS, 170 smp_rsp_timeout, NULL); 171 172 if (cmd == SMP_OPCODE_CONFIRM) { 173 SMP_TRACE_DEBUG( 174 "in %s cmd = 0x%02x, peer_auth_req = 0x%02x," 175 "loc_auth_req = 0x%02x", 176 __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req); 177 178 if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && 179 (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { 180 cmd = SMP_OPCODE_PAIR_COMMITM; 181 } 182 } 183 184 p_cb->rcvd_cmd_code = cmd; 185 p_cb->rcvd_cmd_len = (uint8_t)p_buf->len; 186 smp_sm_event(p_cb, cmd, p); 187 } 188 189 osi_free(p_buf); 190} 191 192/******************************************************************************* 193 * 194 * Function smp_tx_complete_callback 195 * 196 * Description SMP channel tx complete callback 197 * 198 ******************************************************************************/ 199static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt) { 200 tSMP_CB* p_cb = &smp_cb; 201 202 if (p_cb->total_tx_unacked >= num_pkt) 203 p_cb->total_tx_unacked -= num_pkt; 204 else 205 SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt); 206 207 uint8_t reason = SMP_SUCCESS; 208 if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) { 209 if (cid == L2CAP_SMP_CID) 210 smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); 211 else 212 smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); 213 } 214} 215 216/******************************************************************************* 217 * 218 * Function smp_br_connect_callback 219 * 220 * Description This callback function is called by L2CAP to indicate that 221 * SMP BR channel is 222 * connected (conn = true)/disconnected (conn = false). 223 * 224 ******************************************************************************/ 225static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr, 226 bool connected, uint16_t reason, 227 tBT_TRANSPORT transport) { 228 tSMP_CB* p_cb = &smp_cb; 229 tSMP_INT_DATA int_data; 230 231 SMP_TRACE_EVENT("%s", __func__); 232 233 if (transport != BT_TRANSPORT_BR_EDR) { 234 SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__, 235 transport); 236 return; 237 } 238 239 if (bd_addr != p_cb->pairing_bda) return; 240 241 VLOG(1) << __func__ << " for pairing BDA: " << bd_addr 242 << " Event: " << ((connected) ? "connected" : "disconnected"); 243 244 if (connected) { 245 if (!p_cb->connect_initialized) { 246 p_cb->connect_initialized = true; 247 /* initialize local i/r key to be default keys */ 248 p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY; 249 p_cb->loc_auth_req = p_cb->peer_auth_req = 0; 250 p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; 251 smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL); 252 } 253 } else { 254 int_data.reason = reason; 255 /* Disconnected while doing security */ 256 smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data); 257 } 258} 259 260/******************************************************************************* 261 * 262 * Function smp_br_data_received 263 * 264 * Description This function is called when data is received from L2CAP on 265 * SMP BR channel. 266 * 267 * Returns void 268 * 269 ******************************************************************************/ 270static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr, 271 BT_HDR* p_buf) { 272 tSMP_CB* p_cb = &smp_cb; 273 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset; 274 uint8_t cmd; 275 SMP_TRACE_EVENT("SMDBG l2c %s", __func__); 276 277 STREAM_TO_UINT8(cmd, p); 278 279 /* sanity check */ 280 if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { 281 SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd); 282 osi_free(p_buf); 283 return; 284 } 285 286 /* reject the pairing request if there is an on-going SMP pairing */ 287 if (SMP_OPCODE_PAIRING_REQ == cmd) { 288 if ((p_cb->state == SMP_STATE_IDLE) && 289 (p_cb->br_state == SMP_BR_STATE_IDLE)) { 290 p_cb->role = HCI_ROLE_SLAVE; 291 p_cb->smp_over_br = true; 292 p_cb->pairing_bda = bd_addr; 293 } else if (bd_addr != p_cb->pairing_bda) { 294 osi_free(p_buf); 295 smp_reject_unexpected_pairing_command(bd_addr); 296 return; 297 } 298 /* else, out of state pairing request received, passed into State Machine */ 299 } 300 301 if (bd_addr == p_cb->pairing_bda) { 302 alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS, 303 smp_rsp_timeout, NULL); 304 305 p_cb->rcvd_cmd_code = cmd; 306 p_cb->rcvd_cmd_len = (uint8_t)p_buf->len; 307 smp_br_state_machine_event(p_cb, cmd, p); 308 } 309 310 osi_free(p_buf); 311} 312