1/******************************************************************************
2 *
3 *  Copyright (C) 2004-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 pan action functions for the state machine.
22 *
23 ******************************************************************************/
24
25#include "bt_target.h"
26
27#if (PAN_INCLUDED == TRUE)
28
29#include <string.h>
30
31#include "bt_common.h"
32#include "bta_api.h"
33#include "bta_pan_api.h"
34#include "bta_pan_co.h"
35#include "bta_pan_int.h"
36#include "bta_sys.h"
37#include "osi/include/osi.h"
38#include "pan_api.h"
39#include "utl.h"
40
41/* RX and TX data flow mask */
42#define BTA_PAN_RX_MASK 0x0F
43#define BTA_PAN_TX_MASK 0xF0
44
45/*******************************************************************************
46 *
47 * Function    bta_pan_pm_conn_busy
48 *
49 * Description set pan pm connection busy state
50 *
51 * Params      p_scb: state machine control block of pan connection
52 *
53 * Returns     void
54 *
55 ******************************************************************************/
56static void bta_pan_pm_conn_busy(tBTA_PAN_SCB* p_scb) {
57  if ((p_scb != NULL) && (p_scb->state != BTA_PAN_IDLE_ST))
58    bta_sys_busy(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
59}
60
61/*******************************************************************************
62 *
63 * Function    bta_pan_pm_conn_idle
64 *
65 * Description set pan pm connection idle state
66 *
67 * Params      p_scb: state machine control block of pan connection
68 *
69 * Returns     void
70 *
71 ******************************************************************************/
72static void bta_pan_pm_conn_idle(tBTA_PAN_SCB* p_scb) {
73  if ((p_scb != NULL) && (p_scb->state != BTA_PAN_IDLE_ST))
74    bta_sys_idle(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
75}
76
77/*******************************************************************************
78 *
79 * Function         bta_pan_conn_state_cback
80 *
81 * Description      Connection state callback from Pan profile
82 *
83 *
84 * Returns          void
85 *
86 ******************************************************************************/
87static void bta_pan_conn_state_cback(uint16_t handle, BD_ADDR bd_addr,
88                                     tPAN_RESULT state, bool is_role_change,
89                                     uint8_t src_role, uint8_t dst_role) {
90  tBTA_PAN_SCB* p_scb;
91  tBTA_PAN_CONN* p_buf = (tBTA_PAN_CONN*)osi_malloc(sizeof(tBTA_PAN_CONN));
92
93  if ((state == PAN_SUCCESS) && !is_role_change) {
94    p_buf->hdr.event = BTA_PAN_CONN_OPEN_EVT;
95    p_scb = bta_pan_scb_by_handle(handle);
96    if (p_scb == NULL) {
97      /* allocate an scb */
98      p_scb = bta_pan_scb_alloc();
99    }
100    /* we have exceeded maximum number of connections */
101    if (!p_scb) {
102      PAN_Disconnect(handle);
103      return;
104    }
105
106    p_scb->handle = handle;
107    p_scb->local_role = src_role;
108    p_scb->peer_role = dst_role;
109    p_scb->pan_flow_enable = true;
110    bdcpy(p_scb->bd_addr, bd_addr);
111    p_scb->data_queue = fixed_queue_new(SIZE_MAX);
112
113    if (src_role == PAN_ROLE_CLIENT)
114      p_scb->app_id = bta_pan_cb.app_id[0];
115    else if (src_role == PAN_ROLE_GN_SERVER)
116      p_scb->app_id = bta_pan_cb.app_id[1];
117    else if (src_role == PAN_ROLE_NAP_SERVER)
118      p_scb->app_id = bta_pan_cb.app_id[2];
119  } else if ((state != PAN_SUCCESS) && !is_role_change) {
120    p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
121  } else {
122    return;
123  }
124
125  p_buf->result = state;
126  p_buf->hdr.layer_specific = handle;
127
128  bta_sys_sendmsg(p_buf);
129}
130
131/*******************************************************************************
132 *
133 * Function         bta_pan_data_flow_cb
134 *
135 * Description      Data flow status callback from PAN
136 *
137 *
138 * Returns          void
139 *
140 ******************************************************************************/
141static void bta_pan_data_flow_cb(uint16_t handle, tPAN_RESULT result) {
142  tBTA_PAN_SCB* p_scb;
143
144  p_scb = bta_pan_scb_by_handle(handle);
145  if (p_scb == NULL) return;
146
147  if (result == PAN_TX_FLOW_ON) {
148    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
149    p_buf->layer_specific = handle;
150    p_buf->event = BTA_PAN_BNEP_FLOW_ENABLE_EVT;
151    bta_sys_sendmsg(p_buf);
152    bta_pan_co_rx_flow(handle, p_scb->app_id, true);
153  } else if (result == PAN_TX_FLOW_OFF) {
154    p_scb->pan_flow_enable = false;
155    bta_pan_co_rx_flow(handle, p_scb->app_id, false);
156  }
157}
158
159/*******************************************************************************
160 *
161 * Function         bta_pan_data_buf_ind_cback
162 *
163 * Description      data indication callback from pan profile
164 *
165 *
166 * Returns          void
167 *
168 ******************************************************************************/
169static void bta_pan_data_buf_ind_cback(uint16_t handle, BD_ADDR src,
170                                       BD_ADDR dst, uint16_t protocol,
171                                       BT_HDR* p_buf, bool ext, bool forward) {
172  tBTA_PAN_SCB* p_scb;
173  BT_HDR* p_new_buf;
174
175  if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
176    /* offset smaller than data structure in front of actual data */
177    p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
178    memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
179           (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
180    p_new_buf->len = p_buf->len;
181    p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
182    osi_free(p_buf);
183  } else {
184    p_new_buf = p_buf;
185  }
186  /* copy params into the space before the data */
187  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->src, src);
188  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->dst, dst);
189  ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->protocol = protocol;
190  ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->ext = ext;
191  ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->forward = forward;
192
193  p_scb = bta_pan_scb_by_handle(handle);
194  if (p_scb == NULL) {
195    osi_free(p_new_buf);
196    return;
197  }
198
199  fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
200  BT_HDR* p_event = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
201  p_event->layer_specific = handle;
202  p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
203  bta_sys_sendmsg(p_event);
204}
205
206/*******************************************************************************
207 *
208 * Function         bta_pan_pfilt_ind_cback
209 *
210 * Description
211 *
212 *
213 * Returns          void
214 *
215 ******************************************************************************/
216static void bta_pan_pfilt_ind_cback(uint16_t handle, bool indication,
217                                    tBNEP_RESULT result, uint16_t num_filters,
218                                    uint8_t* p_filters) {
219  bta_pan_co_pfilt_ind(
220      handle, indication,
221      (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS
222                                                 : BTA_PAN_FAIL),
223      num_filters, p_filters);
224}
225
226/*******************************************************************************
227 *
228 * Function         bta_pan_mfilt_ind_cback
229 *
230 * Description
231 *
232 *
233 * Returns          void
234 *
235 ******************************************************************************/
236static void bta_pan_mfilt_ind_cback(uint16_t handle, bool indication,
237                                    tBNEP_RESULT result, uint16_t num_mfilters,
238                                    uint8_t* p_mfilters) {
239  bta_pan_co_mfilt_ind(
240      handle, indication,
241      (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS
242                                                 : BTA_PAN_FAIL),
243      num_mfilters, p_mfilters);
244}
245
246/*******************************************************************************
247 *
248 * Function         bta_pan_has_multiple_connections
249 *
250 * Description      Check whether there are multiple GN/NAP connections to
251 *                  different devices
252 *
253 *
254 * Returns          bool
255 *
256 ******************************************************************************/
257static bool bta_pan_has_multiple_connections(uint8_t app_id) {
258  tBTA_PAN_SCB* p_scb = NULL;
259  bool found = false;
260  BD_ADDR bd_addr;
261
262  for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
263    p_scb = &bta_pan_cb.scb[index];
264    if (p_scb->in_use == true && app_id == p_scb->app_id) {
265      /* save temp bd_addr */
266      bdcpy(bd_addr, p_scb->bd_addr);
267      found = true;
268      break;
269    }
270  }
271
272  /* If cannot find a match then there is no connection at all */
273  if (found == false) return false;
274
275  /* Find whether there is another connection with different device other than
276     PANU.
277      Could be same service or different service */
278  for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
279    p_scb = &bta_pan_cb.scb[index];
280    if (p_scb->in_use == true && p_scb->app_id != bta_pan_cb.app_id[0] &&
281        bdcmp(bd_addr, p_scb->bd_addr)) {
282      return true;
283    }
284  }
285  return false;
286}
287
288/*******************************************************************************
289 *
290 * Function         bta_pan_enable
291 *
292 * Description
293 *
294 *
295 *
296 * Returns          void
297 *
298 ******************************************************************************/
299void bta_pan_enable(tBTA_PAN_DATA* p_data) {
300  tPAN_REGISTER reg_data;
301  uint16_t initial_discoverability;
302  uint16_t initial_connectability;
303  uint16_t d_window;
304  uint16_t d_interval;
305  uint16_t c_window;
306  uint16_t c_interval;
307
308  bta_pan_cb.p_cback = p_data->api_enable.p_cback;
309
310  reg_data.pan_conn_state_cb = bta_pan_conn_state_cback;
311  reg_data.pan_bridge_req_cb = NULL;
312  reg_data.pan_data_buf_ind_cb = bta_pan_data_buf_ind_cback;
313  reg_data.pan_data_ind_cb = NULL;
314  reg_data.pan_pfilt_ind_cb = bta_pan_pfilt_ind_cback;
315  reg_data.pan_mfilt_ind_cb = bta_pan_mfilt_ind_cback;
316  reg_data.pan_tx_data_flow_cb = bta_pan_data_flow_cb;
317
318  /* read connectability and discoverability settings.
319  Pan profile changes the settings. We have to change it back to
320  be consistent with other bta subsystems */
321  initial_connectability = BTM_ReadConnectability(&c_window, &c_interval);
322  initial_discoverability = BTM_ReadDiscoverability(&d_window, &d_interval);
323
324  PAN_Register(&reg_data);
325
326  /* set it back to original value */
327  BTM_SetDiscoverability(initial_discoverability, d_window, d_interval);
328  BTM_SetConnectability(initial_connectability, c_window, c_interval);
329
330  bta_pan_cb.flow_mask = bta_pan_co_init(&bta_pan_cb.q_level);
331  bta_pan_cb.p_cback(BTA_PAN_ENABLE_EVT, NULL);
332}
333
334/*******************************************************************************
335 *
336 * Function         bta_pan_set_role
337 *
338 * Description
339 *
340 * Returns          void
341 *
342 ******************************************************************************/
343void bta_pan_set_role(tBTA_PAN_DATA* p_data) {
344  tPAN_RESULT status;
345  tBTA_PAN bta_pan;
346  uint8_t sec[3];
347
348  bta_pan_cb.app_id[0] = p_data->api_set_role.user_app_id;
349  bta_pan_cb.app_id[1] = p_data->api_set_role.gn_app_id;
350  bta_pan_cb.app_id[2] = p_data->api_set_role.nap_app_id;
351
352  sec[0] = p_data->api_set_role.user_sec_mask;
353  sec[1] = p_data->api_set_role.gn_sec_mask;
354  sec[2] = p_data->api_set_role.nap_sec_mask;
355
356  /* set security correctly in api and here */
357  status = PAN_SetRole(
358      p_data->api_set_role.role, sec, p_data->api_set_role.user_name,
359      p_data->api_set_role.gn_name, p_data->api_set_role.nap_name);
360
361  bta_pan.set_role.role = p_data->api_set_role.role;
362  if (status == PAN_SUCCESS) {
363    if (p_data->api_set_role.role & PAN_ROLE_NAP_SERVER)
364      bta_sys_add_uuid(UUID_SERVCLASS_NAP);
365    else
366      bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
367
368    if (p_data->api_set_role.role & PAN_ROLE_GN_SERVER)
369      bta_sys_add_uuid(UUID_SERVCLASS_GN);
370    else
371      bta_sys_remove_uuid(UUID_SERVCLASS_GN);
372
373    if (p_data->api_set_role.role & PAN_ROLE_CLIENT)
374      bta_sys_add_uuid(UUID_SERVCLASS_PANU);
375    else
376      bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
377
378    bta_pan.set_role.status = BTA_PAN_SUCCESS;
379  }
380  /* if status is not success clear everything */
381  else {
382    PAN_SetRole(0, 0, NULL, NULL, NULL);
383    bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
384    bta_sys_remove_uuid(UUID_SERVCLASS_GN);
385    bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
386    bta_pan.set_role.status = BTA_PAN_FAIL;
387  }
388  bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, &bta_pan);
389}
390
391/*******************************************************************************
392 *
393 * Function         bta_pan_disable
394 *
395 * Description
396 *
397 *
398 *
399 * Returns          void
400 *
401 ******************************************************************************/
402void bta_pan_disable(void) {
403  BT_HDR* p_buf;
404  tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
405  uint8_t i;
406
407  /* close all connections */
408  PAN_SetRole(0, NULL, NULL, NULL, NULL);
409
410#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
411  bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
412  bta_sys_remove_uuid(UUID_SERVCLASS_GN);
413  bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
414#endif  // BTA_EIR_CANNED_UUID_LIST
415  /* free all queued up data buffers */
416  for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
417    if (p_scb->in_use) {
418      while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) !=
419             NULL)
420        osi_free(p_buf);
421
422      bta_pan_co_close(p_scb->handle, p_scb->app_id);
423    }
424  }
425
426  PAN_Deregister();
427}
428
429/*******************************************************************************
430 *
431 * Function         bta_pan_open
432 *
433 * Description
434 *
435 * Returns          void
436 *
437 ******************************************************************************/
438void bta_pan_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
439  tPAN_RESULT status;
440  tBTA_PAN bta_pan;
441
442  status = PAN_Connect(p_data->api_open.bd_addr, p_data->api_open.local_role,
443                       p_data->api_open.peer_role, &p_scb->handle);
444  APPL_TRACE_DEBUG("%s pan connect status: %d", __func__, status);
445
446  if (status == PAN_SUCCESS) {
447    bdcpy(p_scb->bd_addr, p_data->api_open.bd_addr);
448    p_scb->local_role = p_data->api_open.local_role;
449    p_scb->peer_role = p_data->api_open.peer_role;
450    bdcpy(bta_pan.opening.bd_addr, p_data->api_open.bd_addr);
451    bta_pan.opening.handle = p_scb->handle;
452    bta_pan_cb.p_cback(BTA_PAN_OPENING_EVT, &bta_pan);
453
454  } else {
455    bta_pan_scb_dealloc(p_scb);
456    bdcpy(bta_pan.open.bd_addr, p_data->api_open.bd_addr);
457    bta_pan.open.status = BTA_PAN_FAIL;
458    bta_pan.open.local_role = p_data->api_open.local_role;
459    bta_pan.open.peer_role = p_data->api_open.peer_role;
460    bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, &bta_pan);
461  }
462}
463
464/*******************************************************************************
465 *
466 * Function         bta_pan_close
467 *
468 * Description
469 *
470 *
471 *
472 * Returns          void
473 *
474 ******************************************************************************/
475void bta_pan_api_close(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
476  tBTA_PAN_CONN* p_buf = (tBTA_PAN_CONN*)osi_malloc(sizeof(tBTA_PAN_CONN));
477
478  PAN_Disconnect(p_scb->handle);
479
480  /*
481   * Send an event to BTA so that application will get the connection
482   * close event.
483   */
484  p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
485  p_buf->hdr.layer_specific = p_scb->handle;
486
487  bta_sys_sendmsg(p_buf);
488}
489
490/*******************************************************************************
491 *
492 * Function         bta_pan_conn_open
493 *
494 * Description      process connection open event
495 *
496 * Returns          void
497 *
498 ******************************************************************************/
499void bta_pan_conn_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
500  tBTA_PAN bta_pan;
501
502  APPL_TRACE_DEBUG("%s pan connection result: %d", __func__,
503                   p_data->conn.result);
504
505  bdcpy(bta_pan.open.bd_addr, p_scb->bd_addr);
506  bta_pan.open.handle = p_scb->handle;
507  bta_pan.open.local_role = p_scb->local_role;
508  bta_pan.open.peer_role = p_scb->peer_role;
509
510  if (p_data->conn.result == PAN_SUCCESS) {
511    bta_pan.open.status = BTA_PAN_SUCCESS;
512    p_scb->pan_flow_enable = true;
513    p_scb->app_flow_enable = true;
514    bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
515  } else {
516    bta_pan_scb_dealloc(p_scb);
517    bta_pan.open.status = BTA_PAN_FAIL;
518  }
519
520  p_scb->pan_flow_enable = true;
521  p_scb->app_flow_enable = true;
522
523  /* If app_id is NAP/GN, check whether there are multiple connections.
524     If there are, provide a special app_id to dm to enforce master role only.
525     */
526  if ((p_scb->app_id == bta_pan_cb.app_id[1] ||
527       p_scb->app_id == bta_pan_cb.app_id[2]) &&
528      bta_pan_has_multiple_connections(p_scb->app_id)) {
529    p_scb->app_id = BTA_APP_ID_PAN_MULTI;
530  }
531
532  bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
533  bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, &bta_pan);
534}
535
536/*******************************************************************************
537 *
538 * Function         bta_pan_conn_close
539 *
540 * Description      process connection close event
541 *
542 *
543 *
544 * Returns          void
545 *
546 ******************************************************************************/
547void bta_pan_conn_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
548  tBTA_PAN bta_pan;
549  BT_HDR* p_buf;
550
551  bta_pan.close.handle = p_data->hdr.layer_specific;
552
553  bta_sys_conn_close(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
554
555  /* free all queued up data buffers */
556  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) != NULL)
557    osi_free(p_buf);
558
559  bta_pan_scb_dealloc(p_scb);
560
561  bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, &bta_pan);
562}
563
564/*******************************************************************************
565 *
566 * Function         bta_pan_rx_path
567 *
568 * Description      Handle data on the RX path (data sent from the phone to
569 *                  BTA).
570 *
571 *
572 * Returns          void
573 *
574 ******************************************************************************/
575void bta_pan_rx_path(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
576  /* if data path configured for rx pull */
577  if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PULL) {
578    /* if we can accept data */
579    if (p_scb->pan_flow_enable == true) {
580      /* call application callout function for rx path */
581      bta_pan_co_rx_path(p_scb->handle, p_scb->app_id);
582    }
583  }
584  /* else data path configured for rx push */
585  else {
586  }
587}
588
589/*******************************************************************************
590 *
591 * Function         bta_pan_tx_path
592 *
593 * Description      Handle the TX data path (data sent from BTA to the phone).
594 *
595 *
596 * Returns          void
597 *
598 ******************************************************************************/
599void bta_pan_tx_path(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
600  /* if data path configured for tx pull */
601  if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PULL) {
602    bta_pan_pm_conn_busy(p_scb);
603    /* call application callout function for tx path */
604    bta_pan_co_tx_path(p_scb->handle, p_scb->app_id);
605
606    /* free data that exceeds queue level */
607    while (fixed_queue_length(p_scb->data_queue) > bta_pan_cb.q_level)
608      osi_free(fixed_queue_try_dequeue(p_scb->data_queue));
609    bta_pan_pm_conn_idle(p_scb);
610  }
611  /* if configured for zero copy push */
612  else if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PUSH_BUF) {
613    /* if app can accept data */
614    if (p_scb->app_flow_enable == true) {
615      BT_HDR* p_buf;
616
617      /* read data from the queue */
618      p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue);
619      if (p_buf != NULL) {
620        /* send data to application */
621        bta_pan_co_tx_writebuf(p_scb->handle, p_scb->app_id,
622                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->src,
623                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->dst,
624                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol, p_buf,
625                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext,
626                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->forward);
627      }
628      /* free data that exceeds queue level  */
629      while (fixed_queue_length(p_scb->data_queue) > bta_pan_cb.q_level)
630        osi_free(fixed_queue_try_dequeue(p_scb->data_queue));
631
632      /* if there is more data to be passed to
633      upper layer */
634      if (!fixed_queue_is_empty(p_scb->data_queue)) {
635        p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
636        p_buf->layer_specific = p_scb->handle;
637        p_buf->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
638        bta_sys_sendmsg(p_buf);
639      }
640    }
641  }
642}
643
644/*******************************************************************************
645 *
646 * Function         bta_pan_tx_flow
647 *
648 * Description      Set the application flow control state.
649 *
650 *
651 * Returns          void
652 *
653 ******************************************************************************/
654void bta_pan_tx_flow(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
655  p_scb->app_flow_enable = p_data->ci_tx_flow.enable;
656}
657
658/*******************************************************************************
659 *
660 * Function         bta_pan_write_buf
661 *
662 * Description      Handle a bta_pan_ci_rx_writebuf() and send data to PAN.
663 *
664 *
665 * Returns          void
666 *
667 ******************************************************************************/
668void bta_pan_write_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
669  if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PUSH_BUF) {
670    bta_pan_pm_conn_busy(p_scb);
671
672    PAN_WriteBuf(p_scb->handle, ((tBTA_PAN_DATA_PARAMS*)p_data)->dst,
673                 ((tBTA_PAN_DATA_PARAMS*)p_data)->src,
674                 ((tBTA_PAN_DATA_PARAMS*)p_data)->protocol, (BT_HDR*)p_data,
675                 ((tBTA_PAN_DATA_PARAMS*)p_data)->ext);
676    bta_pan_pm_conn_idle(p_scb);
677  }
678}
679
680/*******************************************************************************
681 *
682 * Function         bta_pan_free_buf
683 *
684 * Description      Frees the data buffer during closing state
685 *
686 *
687 * Returns          void
688 *
689 ******************************************************************************/
690void bta_pan_free_buf(UNUSED_ATTR tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
691  osi_free(p_data);
692}
693
694#endif /* PAN_INCLUDED */
695