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