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 static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt);
     34 
     35 static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr,
     36                                  bool connected, uint16_t reason,
     37                                  tBT_TRANSPORT transport);
     38 static void smp_data_received(uint16_t channel, const RawAddress& bd_addr,
     39                               BT_HDR* p_buf);
     40 
     41 static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr,
     42                                     bool connected, uint16_t reason,
     43                                     tBT_TRANSPORT transport);
     44 static 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  ******************************************************************************/
     55 void 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  ******************************************************************************/
     91 static 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  ******************************************************************************/
    136 static 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  ******************************************************************************/
    199 static 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  ******************************************************************************/
    225 static 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  ******************************************************************************/
    270 static 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