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