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