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