OSDN Git Service

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