Home | History | Annotate | Download | only in bnep
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2001-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 the BNEP API code
     22  *
     23  ******************************************************************************/
     24 
     25 #include "bnep_api.h"
     26 #include <string.h>
     27 #include "bnep_int.h"
     28 
     29 /*******************************************************************************
     30  *
     31  * Function         BNEP_Init
     32  *
     33  * Description      This function initializes the BNEP unit. It should be called
     34  *                  before accessing any other APIs to initialize the control
     35  *                  block.
     36  *
     37  * Returns          void
     38  *
     39  ******************************************************************************/
     40 void BNEP_Init(void) {
     41   memset(&bnep_cb, 0, sizeof(tBNEP_CB));
     42 
     43 #if defined(BNEP_INITIAL_TRACE_LEVEL)
     44   bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL;
     45 #else
     46   bnep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
     47 #endif
     48 }
     49 
     50 /*******************************************************************************
     51  *
     52  * Function         BNEP_Register
     53  *
     54  * Description      This function is called by the upper layer to register
     55  *                  its callbacks with BNEP
     56  *
     57  * Parameters:      p_reg_info - contains all callback function pointers
     58  *
     59  *
     60  * Returns          BNEP_SUCCESS        if registered successfully
     61  *                  BNEP_FAILURE        if connection state callback is missing
     62  *
     63  ******************************************************************************/
     64 tBNEP_RESULT BNEP_Register(tBNEP_REGISTER* p_reg_info) {
     65   /* There should be connection state call back registered */
     66   if ((!p_reg_info) || (!(p_reg_info->p_conn_state_cb)))
     67     return BNEP_SECURITY_FAIL;
     68 
     69   bnep_cb.p_conn_ind_cb = p_reg_info->p_conn_ind_cb;
     70   bnep_cb.p_conn_state_cb = p_reg_info->p_conn_state_cb;
     71   bnep_cb.p_data_ind_cb = p_reg_info->p_data_ind_cb;
     72   bnep_cb.p_data_buf_cb = p_reg_info->p_data_buf_cb;
     73   bnep_cb.p_filter_ind_cb = p_reg_info->p_filter_ind_cb;
     74   bnep_cb.p_mfilter_ind_cb = p_reg_info->p_mfilter_ind_cb;
     75   bnep_cb.p_tx_data_flow_cb = p_reg_info->p_tx_data_flow_cb;
     76 
     77   if (bnep_register_with_l2cap()) return BNEP_SECURITY_FAIL;
     78 
     79   bnep_cb.profile_registered = true;
     80   return BNEP_SUCCESS;
     81 }
     82 
     83 /*******************************************************************************
     84  *
     85  * Function         BNEP_Deregister
     86  *
     87  * Description      This function is called by the upper layer to de-register
     88  *                  its callbacks.
     89  *
     90  * Parameters:      void
     91  *
     92  *
     93  * Returns          void
     94  *
     95  ******************************************************************************/
     96 void BNEP_Deregister(void) {
     97   /* Clear all the call backs registered */
     98   bnep_cb.p_conn_ind_cb = NULL;
     99   bnep_cb.p_conn_state_cb = NULL;
    100   bnep_cb.p_data_ind_cb = NULL;
    101   bnep_cb.p_data_buf_cb = NULL;
    102   bnep_cb.p_filter_ind_cb = NULL;
    103   bnep_cb.p_mfilter_ind_cb = NULL;
    104 
    105   bnep_cb.profile_registered = false;
    106   L2CA_Deregister(BT_PSM_BNEP);
    107 }
    108 
    109 /*******************************************************************************
    110  *
    111  * Function         BNEP_Connect
    112  *
    113  * Description      This function creates a BNEP connection to a remote
    114  *                  device.
    115  *
    116  * Parameters:      p_rem_addr  - BD_ADDR of the peer
    117  *                  src_uuid    - source uuid for the connection
    118  *                  dst_uuid    - destination uuid for the connection
    119  *                  p_handle    - pointer to return the handle for the
    120  *                                connection
    121  *
    122  * Returns          BNEP_SUCCESS                if connection started
    123  *                  BNEP_NO_RESOURCES           if no resources
    124  *
    125  ******************************************************************************/
    126 tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda, tBT_UUID* src_uuid,
    127                           tBT_UUID* dst_uuid, uint16_t* p_handle) {
    128   uint16_t cid;
    129   tBNEP_CONN* p_bcb = bnepu_find_bcb_by_bd_addr(p_rem_bda);
    130 
    131   VLOG(0) << __func__ << " BDA:" << p_rem_bda;
    132 
    133   if (!bnep_cb.profile_registered) return BNEP_WRONG_STATE;
    134 
    135   /* Both source and destination UUID lengths should be same */
    136   if (src_uuid->len != dst_uuid->len) return BNEP_CONN_FAILED_UUID_SIZE;
    137 
    138   if (!p_bcb) {
    139     p_bcb = bnepu_allocate_bcb(p_rem_bda);
    140     if (p_bcb == NULL) return (BNEP_NO_RESOURCES);
    141   } else if (p_bcb->con_state != BNEP_STATE_CONNECTED)
    142     return BNEP_WRONG_STATE;
    143   else {
    144     /* Backup current UUID values to restore if role change fails */
    145     memcpy((uint8_t*)&(p_bcb->prv_src_uuid), (uint8_t*)&(p_bcb->src_uuid),
    146            sizeof(tBT_UUID));
    147     memcpy((uint8_t*)&(p_bcb->prv_dst_uuid), (uint8_t*)&(p_bcb->dst_uuid),
    148            sizeof(tBT_UUID));
    149   }
    150 
    151   /* We are the originator of this connection */
    152   p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG;
    153 
    154   memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)src_uuid, sizeof(tBT_UUID));
    155   memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)dst_uuid, sizeof(tBT_UUID));
    156 
    157   if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
    158     /* Transition to the next appropriate state, waiting for connection confirm.
    159      */
    160     p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
    161 
    162     BNEP_TRACE_API("BNEP initiating security procedures for src uuid 0x%x",
    163                    p_bcb->src_uuid.uu.uuid16);
    164 
    165 #if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE)
    166     btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
    167                               BTM_SEC_PROTO_BNEP, bnep_get_uuid32(src_uuid),
    168                               &bnep_sec_check_complete, p_bcb);
    169 #else
    170     bnep_sec_check_complete(p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
    171 #endif
    172 
    173   } else {
    174     /* Transition to the next appropriate state, waiting for connection confirm.
    175      */
    176     p_bcb->con_state = BNEP_STATE_CONN_START;
    177 
    178     cid = L2CA_ConnectReq(BT_PSM_BNEP, p_bcb->rem_bda);
    179     if (cid != 0) {
    180       p_bcb->l2cap_cid = cid;
    181 
    182     } else {
    183       BNEP_TRACE_ERROR("BNEP - Originate failed");
    184       if (bnep_cb.p_conn_state_cb)
    185         (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
    186                                    BNEP_CONN_FAILED, false);
    187       bnepu_release_bcb(p_bcb);
    188       return BNEP_CONN_FAILED;
    189     }
    190 
    191     /* Start timer waiting for connect */
    192     alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
    193                        bnep_conn_timer_timeout, p_bcb);
    194   }
    195 
    196   *p_handle = p_bcb->handle;
    197   return (BNEP_SUCCESS);
    198 }
    199 
    200 /*******************************************************************************
    201  *
    202  * Function         BNEP_ConnectResp
    203  *
    204  * Description      This function is called in responce to connection indication
    205  *
    206  *
    207  * Parameters:      handle  - handle given in the connection indication
    208  *                  resp    - responce for the connection indication
    209  *
    210  * Returns          BNEP_SUCCESS                if connection started
    211  *                  BNEP_WRONG_HANDLE           if the connection is not found
    212  *                  BNEP_WRONG_STATE            if the responce is not expected
    213  *
    214  ******************************************************************************/
    215 tBNEP_RESULT BNEP_ConnectResp(uint16_t handle, tBNEP_RESULT resp) {
    216   tBNEP_CONN* p_bcb;
    217   uint16_t resp_code = BNEP_SETUP_CONN_OK;
    218 
    219   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
    220 
    221   p_bcb = &(bnep_cb.bcb[handle - 1]);
    222 
    223   if (p_bcb->con_state != BNEP_STATE_CONN_SETUP ||
    224       (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)))
    225     return (BNEP_WRONG_STATE);
    226 
    227   BNEP_TRACE_API("BNEP_ConnectResp()  for handle %d, responce %d", handle,
    228                  resp);
    229 
    230   /* Form appropriate responce based on profile responce */
    231   if (resp == BNEP_CONN_FAILED_SRC_UUID)
    232     resp_code = BNEP_SETUP_INVALID_SRC_UUID;
    233   else if (resp == BNEP_CONN_FAILED_DST_UUID)
    234     resp_code = BNEP_SETUP_INVALID_DEST_UUID;
    235   else if (resp == BNEP_CONN_FAILED_UUID_SIZE)
    236     resp_code = BNEP_SETUP_INVALID_UUID_SIZE;
    237   else if (resp == BNEP_SUCCESS)
    238     resp_code = BNEP_SETUP_CONN_OK;
    239   else
    240     resp_code = BNEP_SETUP_CONN_NOT_ALLOWED;
    241 
    242   bnep_send_conn_responce(p_bcb, resp_code);
    243   p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
    244 
    245   if (resp == BNEP_SUCCESS)
    246     bnep_connected(p_bcb);
    247   else if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) {
    248     /* Restore the original parameters */
    249     p_bcb->con_state = BNEP_STATE_CONNECTED;
    250     p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
    251 
    252     memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
    253            sizeof(tBT_UUID));
    254     memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
    255            sizeof(tBT_UUID));
    256   }
    257 
    258   /* Process remaining part of the setup message (extension headers) */
    259   if (p_bcb->p_pending_data) {
    260     uint8_t extension_present = true, *p, ext_type;
    261     uint16_t rem_len;
    262 
    263     rem_len = p_bcb->p_pending_data->len;
    264     p = (uint8_t*)(p_bcb->p_pending_data + 1) + p_bcb->p_pending_data->offset;
    265     while (extension_present && p && rem_len) {
    266       ext_type = *p++;
    267       extension_present = ext_type >> 7;
    268       ext_type &= 0x7F;
    269 
    270       /* if unknown extension present stop processing */
    271       if (ext_type) break;
    272 
    273       p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
    274     }
    275 
    276     osi_free_and_reset((void**)&p_bcb->p_pending_data);
    277   }
    278   return (BNEP_SUCCESS);
    279 }
    280 
    281 /*******************************************************************************
    282  *
    283  * Function         BNEP_Disconnect
    284  *
    285  * Description      This function is called to close the specified connection.
    286  *
    287  * Parameters:      handle   - handle of the connection
    288  *
    289  * Returns          BNEP_SUCCESS                if connection is disconnected
    290  *                  BNEP_WRONG_HANDLE           if no connection is not found
    291  *
    292  ******************************************************************************/
    293 tBNEP_RESULT BNEP_Disconnect(uint16_t handle) {
    294   tBNEP_CONN* p_bcb;
    295 
    296   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
    297 
    298   p_bcb = &(bnep_cb.bcb[handle - 1]);
    299 
    300   if (p_bcb->con_state == BNEP_STATE_IDLE) return (BNEP_WRONG_HANDLE);
    301 
    302   BNEP_TRACE_API("BNEP_Disconnect()  for handle %d", handle);
    303 
    304   L2CA_DisconnectReq(p_bcb->l2cap_cid);
    305 
    306   bnepu_release_bcb(p_bcb);
    307 
    308   return (BNEP_SUCCESS);
    309 }
    310 
    311 /*******************************************************************************
    312  *
    313  * Function         BNEP_WriteBuf
    314  *
    315  * Description      This function sends data in a GKI buffer on BNEP connection
    316  *
    317  * Parameters:      handle       - handle of the connection to write
    318  *                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
    319  *                  p_buf        - pointer to address of buffer with data
    320  *                  protocol     - protocol type of the packet
    321  *                  p_src_addr   - (optional) BD_ADDR/ethernet address of the
    322  *                                 source
    323  *                                 (should be NULL if it is local BD Addr)
    324  *                  fw_ext_present - forwarded extensions present
    325  *
    326  * Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
    327  *                  BNEP_MTU_EXCEDED        - If the data length is greater than
    328  *                                            the MTU
    329  *                  BNEP_IGNORE_CMD         - If the packet is filtered out
    330  *                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
    331  *                  BNEP_SUCCESS            - If written successfully
    332  *
    333  ******************************************************************************/
    334 tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, const RawAddress& p_dest_addr,
    335                            BT_HDR* p_buf, uint16_t protocol,
    336                            const RawAddress* p_src_addr, bool fw_ext_present) {
    337   tBNEP_CONN* p_bcb;
    338   uint8_t* p_data;
    339 
    340   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) {
    341     osi_free(p_buf);
    342     return (BNEP_WRONG_HANDLE);
    343   }
    344 
    345   p_bcb = &(bnep_cb.bcb[handle - 1]);
    346   /* Check MTU size */
    347   if (p_buf->len > BNEP_MTU_SIZE) {
    348     BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", p_buf->len,
    349                      BNEP_MTU_SIZE);
    350     osi_free(p_buf);
    351     return (BNEP_MTU_EXCEDED);
    352   }
    353 
    354   /* Check if the packet should be filtered out */
    355   p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
    356   if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
    357                              p_data) != BNEP_SUCCESS) {
    358     /*
    359     ** If packet is filtered and ext headers are present
    360     ** drop the data and forward the ext headers
    361     */
    362     if (fw_ext_present) {
    363       uint8_t ext, length;
    364       uint16_t org_len, new_len;
    365       /* parse the extension headers and findout the new packet len */
    366       org_len = p_buf->len;
    367       new_len = 0;
    368       do {
    369         ext = *p_data++;
    370         length = *p_data++;
    371         p_data += length;
    372 
    373         new_len += (length + 2);
    374 
    375         if (new_len > org_len) {
    376           osi_free(p_buf);
    377           return BNEP_IGNORE_CMD;
    378         }
    379 
    380       } while (ext & 0x80);
    381 
    382       if (protocol != BNEP_802_1_P_PROTOCOL)
    383         protocol = 0;
    384       else {
    385         new_len += 4;
    386         p_data[2] = 0;
    387         p_data[3] = 0;
    388       }
    389       p_buf->len = new_len;
    390     } else {
    391       osi_free(p_buf);
    392       return BNEP_IGNORE_CMD;
    393     }
    394   }
    395 
    396   /* Check transmit queue */
    397   if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH) {
    398     osi_free(p_buf);
    399     return (BNEP_Q_SIZE_EXCEEDED);
    400   }
    401 
    402   /* Build the BNEP header */
    403   bnepu_build_bnep_hdr(p_bcb, p_buf, protocol, p_src_addr, &p_dest_addr,
    404                        fw_ext_present);
    405 
    406   /* Send the data or queue it up */
    407   bnepu_check_send_packet(p_bcb, p_buf);
    408 
    409   return (BNEP_SUCCESS);
    410 }
    411 
    412 /*******************************************************************************
    413  *
    414  * Function         BNEP_Write
    415  *
    416  * Description      This function sends data over a BNEP connection
    417  *
    418  * Parameters:      handle       - handle of the connection to write
    419  *                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
    420  *                  p_data       - pointer to data start
    421  *                  protocol     - protocol type of the packet
    422  *                  p_src_addr   - (optional) BD_ADDR/ethernet address of the
    423  *                                 source
    424  *                                 (should be NULL if it is local BD Addr)
    425  *                  fw_ext_present - forwarded extensions present
    426  *
    427  * Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
    428  *                  BNEP_MTU_EXCEDED        - If the data length is greater than
    429  *                                            the MTU
    430  *                  BNEP_IGNORE_CMD         - If the packet is filtered out
    431  *                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
    432  *                  BNEP_NO_RESOURCES       - If not able to allocate a buffer
    433  *                  BNEP_SUCCESS            - If written successfully
    434  *
    435  ******************************************************************************/
    436 tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr,
    437                         uint8_t* p_data, uint16_t len, uint16_t protocol,
    438                         const RawAddress* p_src_addr, bool fw_ext_present) {
    439   tBNEP_CONN* p_bcb;
    440   uint8_t* p;
    441 
    442   /* Check MTU size. Consider the possibility of having extension headers */
    443   if (len > BNEP_MTU_SIZE) {
    444     BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", len,
    445                      BNEP_MTU_SIZE);
    446     return (BNEP_MTU_EXCEDED);
    447   }
    448 
    449   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
    450 
    451   p_bcb = &(bnep_cb.bcb[handle - 1]);
    452 
    453   /* Check if the packet should be filtered out */
    454   if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
    455                              p_data) != BNEP_SUCCESS) {
    456     /*
    457     ** If packet is filtered and ext headers are present
    458     ** drop the data and forward the ext headers
    459     */
    460     if (fw_ext_present) {
    461       uint8_t ext, length;
    462       uint16_t org_len, new_len;
    463       /* parse the extension headers and findout the new packet len */
    464       org_len = len;
    465       new_len = 0;
    466       p = p_data;
    467       do {
    468         ext = *p_data++;
    469         length = *p_data++;
    470         p_data += length;
    471 
    472         new_len += (length + 2);
    473 
    474         if (new_len > org_len) return BNEP_IGNORE_CMD;
    475 
    476       } while (ext & 0x80);
    477 
    478       if (protocol != BNEP_802_1_P_PROTOCOL)
    479         protocol = 0;
    480       else {
    481         new_len += 4;
    482         p_data[2] = 0;
    483         p_data[3] = 0;
    484       }
    485       len = new_len;
    486       p_data = p;
    487     } else
    488       return BNEP_IGNORE_CMD;
    489   }
    490 
    491   /* Check transmit queue */
    492   if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH)
    493     return (BNEP_Q_SIZE_EXCEEDED);
    494 
    495   /* Get a buffer to copy the data into */
    496   BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
    497 
    498   p_buf->len = len;
    499   p_buf->offset = BNEP_MINIMUM_OFFSET;
    500   p = (uint8_t*)(p_buf + 1) + BNEP_MINIMUM_OFFSET;
    501 
    502   memcpy(p, p_data, len);
    503 
    504   /* Build the BNEP header */
    505   bnepu_build_bnep_hdr(p_bcb, p_buf, protocol, p_src_addr, &p_dest_addr,
    506                        fw_ext_present);
    507 
    508   /* Send the data or queue it up */
    509   bnepu_check_send_packet(p_bcb, p_buf);
    510 
    511   return (BNEP_SUCCESS);
    512 }
    513 
    514 /*******************************************************************************
    515  *
    516  * Function         BNEP_SetProtocolFilters
    517  *
    518  * Description      This function sets the protocol filters on peer device
    519  *
    520  * Parameters:      handle        - Handle for the connection
    521  *                  num_filters   - total number of filter ranges
    522  *                  p_start_array - Array of beginings of all protocol ranges
    523  *                  p_end_array   - Array of ends of all protocol ranges
    524  *
    525  * Returns          BNEP_WRONG_HANDLE           - if the connection handle is
    526  *                                                not valid
    527  *                  BNEP_SET_FILTER_FAIL        - if the connection is in wrong
    528  *                                                state
    529  *                  BNEP_TOO_MANY_FILTERS       - if too many filters
    530  *                  BNEP_SUCCESS                - if request sent successfully
    531  *
    532  ******************************************************************************/
    533 tBNEP_RESULT BNEP_SetProtocolFilters(uint16_t handle, uint16_t num_filters,
    534                                      uint16_t* p_start_array,
    535                                      uint16_t* p_end_array) {
    536   uint16_t xx;
    537   tBNEP_CONN* p_bcb;
    538 
    539   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
    540 
    541   p_bcb = &(bnep_cb.bcb[handle - 1]);
    542 
    543   /* Check the connection state */
    544   if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
    545       (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
    546     return (BNEP_WRONG_STATE);
    547 
    548   /* Validate the parameters */
    549   if (num_filters && (!p_start_array || !p_end_array))
    550     return (BNEP_SET_FILTER_FAIL);
    551 
    552   if (num_filters > BNEP_MAX_PROT_FILTERS) return (BNEP_TOO_MANY_FILTERS);
    553 
    554   /* Fill the filter values in connnection block */
    555   for (xx = 0; xx < num_filters; xx++) {
    556     p_bcb->sent_prot_filter_start[xx] = *p_start_array++;
    557     p_bcb->sent_prot_filter_end[xx] = *p_end_array++;
    558   }
    559 
    560   p_bcb->sent_num_filters = num_filters;
    561 
    562   bnepu_send_peer_our_filters(p_bcb);
    563 
    564   return (BNEP_SUCCESS);
    565 }
    566 
    567 /*******************************************************************************
    568  *
    569  * Function         BNEP_SetMulticastFilters
    570  *
    571  * Description      This function sets the filters for multicast addresses for
    572  *                  BNEP.
    573  *
    574  * Parameters:      handle        - Handle for the connection
    575  *                  num_filters   - total number of filter ranges
    576  *                  p_start_array - Pointer to sequence of beginings of all
    577  *                                         multicast address ranges
    578  *                  p_end_array   - Pointer to sequence of ends of all
    579  *                                         multicast address ranges
    580  *
    581  * Returns          BNEP_WRONG_HANDLE           - if the connection handle is
    582  *                                                not valid
    583  *                  BNEP_SET_FILTER_FAIL        - if the connection is in wrong
    584  *                                                state
    585  *                  BNEP_TOO_MANY_FILTERS       - if too many filters
    586  *                  BNEP_SUCCESS                - if request sent successfully
    587  *
    588  ******************************************************************************/
    589 tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t handle, uint16_t num_filters,
    590                                       uint8_t* p_start_array,
    591                                       uint8_t* p_end_array) {
    592   uint16_t xx;
    593   tBNEP_CONN* p_bcb;
    594 
    595   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
    596 
    597   p_bcb = &(bnep_cb.bcb[handle - 1]);
    598 
    599   /* Check the connection state */
    600   if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
    601       (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
    602     return (BNEP_WRONG_STATE);
    603 
    604   /* Validate the parameters */
    605   if (num_filters && (!p_start_array || !p_end_array))
    606     return (BNEP_SET_FILTER_FAIL);
    607 
    608   if (num_filters > BNEP_MAX_MULTI_FILTERS) return (BNEP_TOO_MANY_FILTERS);
    609 
    610   /* Fill the multicast filter values in connnection block */
    611   for (xx = 0; xx < num_filters; xx++) {
    612     memcpy(p_bcb->sent_mcast_filter_start[xx].address, p_start_array,
    613            BD_ADDR_LEN);
    614     memcpy(p_bcb->sent_mcast_filter_end[xx].address, p_end_array, BD_ADDR_LEN);
    615 
    616     p_start_array += BD_ADDR_LEN;
    617     p_end_array += BD_ADDR_LEN;
    618   }
    619 
    620   p_bcb->sent_mcast_filters = num_filters;
    621 
    622   bnepu_send_peer_our_multi_filters(p_bcb);
    623 
    624   return (BNEP_SUCCESS);
    625 }
    626 
    627 /*******************************************************************************
    628  *
    629  * Function         BNEP_SetTraceLevel
    630  *
    631  * Description      This function sets the trace level for BNEP. If called with
    632  *                  a value of 0xFF, it simply reads the current trace level.
    633  *
    634  * Returns          the new (current) trace level
    635  *
    636  ******************************************************************************/
    637 uint8_t BNEP_SetTraceLevel(uint8_t new_level) {
    638   if (new_level != 0xFF) bnep_cb.trace_level = new_level;
    639 
    640   return (bnep_cb.trace_level);
    641 }
    642 
    643 /*******************************************************************************
    644  *
    645  * Function         BNEP_GetStatus
    646  *
    647  * Description      This function gets the status information for BNEP
    648  *                  connection
    649  *
    650  * Returns          BNEP_SUCCESS            - if the status is available
    651  *                  BNEP_NO_RESOURCES       - if no structure is passed for
    652  *                                            output
    653  *                  BNEP_WRONG_HANDLE       - if the handle is invalid
    654  *                  BNEP_WRONG_STATE        - if not in connected state
    655  *
    656  ******************************************************************************/
    657 tBNEP_RESULT BNEP_GetStatus(uint16_t handle, tBNEP_STATUS* p_status) {
    658 #if (BNEP_SUPPORTS_STATUS_API == TRUE)
    659   tBNEP_CONN* p_bcb;
    660 
    661   if (!p_status) return BNEP_NO_RESOURCES;
    662 
    663   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
    664 
    665   p_bcb = &(bnep_cb.bcb[handle - 1]);
    666 
    667   memset(p_status, 0, sizeof(tBNEP_STATUS));
    668   if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
    669       (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
    670     return BNEP_WRONG_STATE;
    671 
    672   /* Read the status parameters from the connection control block */
    673   p_status->con_status = BNEP_STATUS_CONNECTED;
    674   p_status->l2cap_cid = p_bcb->l2cap_cid;
    675   p_status->rem_mtu_size = p_bcb->rem_mtu_size;
    676   p_status->xmit_q_depth = fixed_queue_length(p_bcb->xmit_q);
    677   p_status->sent_num_filters = p_bcb->sent_num_filters;
    678   p_status->sent_mcast_filters = p_bcb->sent_mcast_filters;
    679   p_status->rcvd_num_filters = p_bcb->rcvd_num_filters;
    680   p_status->rcvd_mcast_filters = p_bcb->rcvd_mcast_filters;
    681 
    682   p_status->rem_bda = p_bcb->rem_bda;
    683   memcpy(&(p_status->src_uuid), &(p_bcb->src_uuid), sizeof(tBT_UUID));
    684   memcpy(&(p_status->dst_uuid), &(p_bcb->dst_uuid), sizeof(tBT_UUID));
    685 
    686   return BNEP_SUCCESS;
    687 #else
    688   return (BNEP_IGNORE_CMD);
    689 #endif
    690 }
    691