Home | History | Annotate | Download | only in smp
      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 
     33 extern fixed_queue_t* btu_general_alarm_queue;
     34 
     35 static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt);
     36 
     37 static void smp_connect_callback(uint16_t channel, BD_ADDR bd_addr,
     38                                  bool connected, uint16_t reason,
     39                                  tBT_TRANSPORT transport);
     40 static void smp_data_received(uint16_t channel, BD_ADDR bd_addr, BT_HDR* p_buf);
     41 
     42 static void smp_br_connect_callback(uint16_t channel, BD_ADDR bd_addr,
     43                                     bool connected, uint16_t reason,
     44                                     tBT_TRANSPORT transport);
     45 static void smp_br_data_received(uint16_t channel, BD_ADDR bd_addr,
     46                                  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   tL2CAP_FIXED_CHNL_REG fixed_reg;
     58   SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
     59   fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
     60   fixed_reg.fixed_chnl_opts.max_transmit = 0;
     61   fixed_reg.fixed_chnl_opts.rtrans_tout = 0;
     62   fixed_reg.fixed_chnl_opts.mon_tout = 0;
     63   fixed_reg.fixed_chnl_opts.mps = 0;
     64   fixed_reg.fixed_chnl_opts.tx_win_sz = 0;
     65 
     66   fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
     67   fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
     68   fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback;
     69 
     70   fixed_reg.pL2CA_FixedCong_Cb =
     71       NULL; /* do not handle congestion on this channel */
     72   fixed_reg.default_idle_tout =
     73       60; /* set 60 seconds timeout, 0xffff default idle timeout */
     74 
     75   L2CA_RegisterFixedChannel(L2CAP_SMP_CID, &fixed_reg);
     76 
     77   fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
     78   fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
     79 
     80   L2CA_RegisterFixedChannel(L2CAP_SMP_BR_CID, &fixed_reg);
     81 }
     82 
     83 /*******************************************************************************
     84  *
     85  * Function         smp_connect_callback
     86  *
     87  * Description      This callback function is called by L2CAP to indicate that
     88  *                  SMP channel is
     89  *                      connected (conn = true)/disconnected (conn = false).
     90  *
     91  ******************************************************************************/
     92 static void smp_connect_callback(uint16_t channel, BD_ADDR bd_addr,
     93                                  bool connected, uint16_t reason,
     94                                  tBT_TRANSPORT transport) {
     95   tSMP_CB* p_cb = &smp_cb;
     96   tSMP_INT_DATA int_data;
     97   BD_ADDR dummy_bda = {0};
     98 
     99   SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
    100 
    101   if (transport == BT_TRANSPORT_BR_EDR ||
    102       memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0)
    103     return;
    104 
    105   if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
    106     SMP_TRACE_EVENT("%s()  for pairing BDA: %08x%04x  Event: %s", __func__,
    107                     (bd_addr[0] << 24) + (bd_addr[1] << 16) +
    108                         (bd_addr[2] << 8) + bd_addr[3],
    109                     (bd_addr[4] << 8) + bd_addr[5],
    110                     (connected) ? "connected" : "disconnected");
    111 
    112     if (connected) {
    113       if (!p_cb->connect_initialized) {
    114         p_cb->connect_initialized = true;
    115         /* initiating connection established */
    116         p_cb->role = L2CA_GetBleConnRole(bd_addr);
    117 
    118         /* initialize local i/r key to be default keys */
    119         p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY;
    120         p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
    121         p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
    122         smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
    123       }
    124     } else {
    125       int_data.reason = reason;
    126       /* Disconnected while doing security */
    127       smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
    128     }
    129   }
    130 }
    131 
    132 /*******************************************************************************
    133  *
    134  * Function         smp_data_received
    135  *
    136  * Description      This function is called when data is received from L2CAP on
    137  *                  SMP channel.
    138  *
    139  *
    140  * Returns          void
    141  *
    142  ******************************************************************************/
    143 static void smp_data_received(uint16_t channel, BD_ADDR bd_addr,
    144                               BT_HDR* p_buf) {
    145   tSMP_CB* p_cb = &smp_cb;
    146   uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
    147   uint8_t cmd;
    148   SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
    149 
    150   STREAM_TO_UINT8(cmd, p);
    151 
    152   /* sanity check */
    153   if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
    154     SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
    155     osi_free(p_buf);
    156     return;
    157   }
    158 
    159   /* reject the pairing request if there is an on-going SMP pairing */
    160   if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) {
    161     if ((p_cb->state == SMP_STATE_IDLE) &&
    162         (p_cb->br_state == SMP_BR_STATE_IDLE) &&
    163         !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
    164       p_cb->role = L2CA_GetBleConnRole(bd_addr);
    165       memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
    166     } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
    167       osi_free(p_buf);
    168       smp_reject_unexpected_pairing_command(bd_addr);
    169       return;
    170     }
    171     /* else, out of state pairing request/security request received, passed into
    172      * SM */
    173   }
    174 
    175   if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
    176     alarm_set_on_queue(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
    177                        smp_rsp_timeout, NULL, btu_general_alarm_queue);
    178 
    179     if (cmd == SMP_OPCODE_CONFIRM) {
    180       SMP_TRACE_DEBUG(
    181           "in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
    182           "loc_auth_req = 0x%02x",
    183           __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
    184 
    185       if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
    186           (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
    187         cmd = SMP_OPCODE_PAIR_COMMITM;
    188       }
    189     }
    190 
    191     p_cb->rcvd_cmd_code = cmd;
    192     p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
    193     smp_sm_event(p_cb, cmd, p);
    194   }
    195 
    196   osi_free(p_buf);
    197 }
    198 
    199 /*******************************************************************************
    200  *
    201  * Function         smp_tx_complete_callback
    202  *
    203  * Description      SMP channel tx complete callback
    204  *
    205  ******************************************************************************/
    206 static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt) {
    207   tSMP_CB* p_cb = &smp_cb;
    208 
    209   if (p_cb->total_tx_unacked >= num_pkt)
    210     p_cb->total_tx_unacked -= num_pkt;
    211   else
    212     SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt);
    213 
    214   uint8_t reason = SMP_SUCCESS;
    215   if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) {
    216     if (cid == L2CAP_SMP_CID)
    217       smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
    218     else
    219       smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
    220   }
    221 }
    222 
    223 /*******************************************************************************
    224  *
    225  * Function         smp_br_connect_callback
    226  *
    227  * Description      This callback function is called by L2CAP to indicate that
    228  *                  SMP BR channel is
    229  *                      connected (conn = true)/disconnected (conn = false).
    230  *
    231  ******************************************************************************/
    232 static void smp_br_connect_callback(uint16_t channel, BD_ADDR bd_addr,
    233                                     bool connected, uint16_t reason,
    234                                     tBT_TRANSPORT transport) {
    235   tSMP_CB* p_cb = &smp_cb;
    236   tSMP_INT_DATA int_data;
    237 
    238   SMP_TRACE_EVENT("%s", __func__);
    239 
    240   if (transport != BT_TRANSPORT_BR_EDR) {
    241     SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__,
    242                       transport);
    243     return;
    244   }
    245 
    246   if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) return;
    247 
    248   SMP_TRACE_EVENT(
    249       "%s for pairing BDA: %08x%04x  Event: %s", __func__,
    250       (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
    251       (bd_addr[4] << 8) + bd_addr[5],
    252       (connected) ? "connected" : "disconnected");
    253 
    254   if (connected) {
    255     if (!p_cb->connect_initialized) {
    256       p_cb->connect_initialized = true;
    257       /* initialize local i/r key to be default keys */
    258       p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY;
    259       p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
    260       p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
    261       smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
    262     }
    263   } else {
    264     int_data.reason = reason;
    265     /* Disconnected while doing security */
    266     smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
    267   }
    268 }
    269 
    270 /*******************************************************************************
    271  *
    272  * Function         smp_br_data_received
    273  *
    274  * Description      This function is called when data is received from L2CAP on
    275  *                  SMP BR channel.
    276  *
    277  * Returns          void
    278  *
    279  ******************************************************************************/
    280 static void smp_br_data_received(uint16_t channel, BD_ADDR bd_addr,
    281                                  BT_HDR* p_buf) {
    282   tSMP_CB* p_cb = &smp_cb;
    283   uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
    284   uint8_t cmd;
    285   SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
    286 
    287   STREAM_TO_UINT8(cmd, p);
    288 
    289   /* sanity check */
    290   if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
    291     SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
    292     osi_free(p_buf);
    293     return;
    294   }
    295 
    296   /* reject the pairing request if there is an on-going SMP pairing */
    297   if (SMP_OPCODE_PAIRING_REQ == cmd) {
    298     if ((p_cb->state == SMP_STATE_IDLE) &&
    299         (p_cb->br_state == SMP_BR_STATE_IDLE)) {
    300       p_cb->role = HCI_ROLE_SLAVE;
    301       p_cb->smp_over_br = true;
    302       memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
    303     } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
    304       osi_free(p_buf);
    305       smp_reject_unexpected_pairing_command(bd_addr);
    306       return;
    307     }
    308     /* else, out of state pairing request received, passed into State Machine */
    309   }
    310 
    311   if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
    312     alarm_set_on_queue(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
    313                        smp_rsp_timeout, NULL, btu_general_alarm_queue);
    314 
    315     p_cb->rcvd_cmd_code = cmd;
    316     p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
    317     smp_br_state_machine_event(p_cb, cmd, p);
    318   }
    319 
    320   osi_free(p_buf);
    321 }
    322