15738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/******************************************************************************
25738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
35738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  Copyright (C) 2004-2012 Broadcom Corporation
45738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
55738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  Licensed under the Apache License, Version 2.0 (the "License");
65738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  you may not use this file except in compliance with the License.
75738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  You may obtain a copy of the License at:
85738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
95738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  http://www.apache.org/licenses/LICENSE-2.0
105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  See the License for the specific language governing permissions and
155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  limitations under the License.
165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project ******************************************************************************/
185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/******************************************************************************
205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  This file contains the L2CAP 1.2 Flow Control and retransmissions
225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *  functions
235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project ******************************************************************************/
255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
26f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h>
27ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include <stdio.h>
285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <stdlib.h>
295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include <string.h>
305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
31258c2538e3b62a8cdb403f2730c45d721e5292b4Pavlin Radoslavov#include "bt_common.h"
32911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson#include "bt_types.h"
33911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson#include "btm_api.h"
34911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson#include "btm_int.h"
35911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson#include "btu.h"
365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "hcimsgs.h"
375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "l2c_api.h"
38ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include "l2c_int.h"
39ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include "l2cdefs.h"
405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
41911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonextern fixed_queue_t* btu_general_alarm_queue;
4278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov
439ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson/* Flag passed to retransmit_i_frames() when all packets should be retransmitted
449ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson */
45911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson#define L2C_FCR_RETX_ALL_PKTS 0xFF
465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
472e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov/* this is the minimal offset required by OBX to process incoming packets */
482e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavovstatic const uint16_t OBX_BUF_MIN_OFFSET = 4;
492e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov
50911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic const char* SAR_types[] = {"Unsegmented", "Start", "End",
51911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                  "Continuation"};
52911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic const char* SUP_types[] = {"RR", "REJ", "RNR", "SREJ"};
535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/* Look-up table for the CRC calculation */
555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectstatic const unsigned short crctab[256] = {
56911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601,
57911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0,
58911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81,
59911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941,
60911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01,
61911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0,
62911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081,
63911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
64911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00,
65911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0,
66911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981,
67911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41,
68911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700,
69911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
70911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281,
71911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
72911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01,
73911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1,
74911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80,
75911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541,
76911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101,
77911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0,
78911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481,
79911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
80911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801,
81911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1,
82911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581,
83911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
84911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    0x4100, 0x81c1, 0x8081, 0x4040,
855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project};
865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
88ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *  Static local functions
895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project*/
90911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic bool process_reqseq(tL2C_CCB* p_ccb, uint16_t ctrl_word);
91911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void process_s_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word);
92911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word,
93911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            bool delay_ack);
94911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic bool retransmit_i_frames(tL2C_CCB* p_ccb, uint8_t tx_seq);
95911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf,
96911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            bool is_retransmission);
97911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void process_stream_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf);
98911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf,
99911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                              uint16_t ctrl_word);
1005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
102911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void l2c_fcr_collect_ack_delay(tL2C_CCB* p_ccb, uint8_t num_bufs_acked);
1035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
1045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
106ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
107ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_updcrc
108ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
109ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function computes the CRC using the look-up table.
110ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
111ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          CRC
112ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
113ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
114911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic unsigned short l2c_fcr_updcrc(unsigned short icrc, unsigned char* icp,
115911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                     int icnt) {
116911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  unsigned short crc = icrc;
117911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  unsigned char* cp = icp;
118911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  int cnt = icnt;
1195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
120911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  while (cnt--) {
121911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    crc = ((crc >> 8) & 0xff) ^ crctab[(crc & 0xff) ^ *cp++];
122911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
124911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (crc);
1255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
128ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
129ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_tx_get_fcs
130ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
131ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function computes the CRC for a frame to be TXed.
132ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
133ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          CRC
134ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
135ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
136911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic uint16_t l2c_fcr_tx_get_fcs(BT_HDR* p_buf) {
137911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
1385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
139911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (l2c_fcr_updcrc(L2CAP_FCR_INIT_CRC, p, p_buf->len));
1405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
143ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
144ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_rx_get_fcs
145ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
146ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function computes the CRC for a received frame.
147ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
148ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          CRC
149ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
150ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
151911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic uint16_t l2c_fcr_rx_get_fcs(BT_HDR* p_buf) {
152911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
1535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
154911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* offset points past the L2CAP header, but the CRC check includes it */
155911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p -= L2CAP_PKT_OVERHEAD;
1565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
157911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (
158911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_fcr_updcrc(L2CAP_FCR_INIT_CRC, p, p_buf->len + L2CAP_PKT_OVERHEAD));
1595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
162ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
163ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_start_timer
164ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
165ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function starts the (monitor or retransmission) timer.
166ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
167ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
168ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
169ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
170911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_start_timer(tL2C_CCB* p_ccb) {
171f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
172911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint32_t tout;
173911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
174911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* The timers which are in milliseconds */
175911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->fcrb.wait_ack) {
176911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    tout = (uint32_t)p_ccb->our_cfg.fcr.mon_tout;
177911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
178911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    tout = (uint32_t)p_ccb->our_cfg.fcr.rtrans_tout;
179911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
180911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
181911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Only start a timer that was not started */
182911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!alarm_is_scheduled(p_ccb->fcrb.mon_retrans_timer)) {
183911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, tout,
184911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                       l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
185911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
189ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
190ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_stop_timer
191ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
192ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function stops the (monitor or transmission) timer.
193ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
194ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
195ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
196ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
197911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_stop_timer(tL2C_CCB* p_ccb) {
198f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
199911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  alarm_cancel(p_ccb->fcrb.mon_retrans_timer);
2005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
2015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
203ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
204ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_cleanup
205ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2069ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Description      This function cleans up the variable used for
2079ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  flow-control/retrans.
208ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
209ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
210ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
211ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
212911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_cleanup(tL2C_CCB* p_ccb) {
213f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
214911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
2155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
216911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  alarm_free(p_fcrb->mon_retrans_timer);
217911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->mon_retrans_timer = NULL;
218911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  alarm_free(p_fcrb->ack_timer);
219911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->ack_timer = NULL;
2205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
221911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  osi_free_and_reset((void**)&p_fcrb->p_rx_sdu);
2225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
223911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  fixed_queue_free(p_fcrb->waiting_for_ack_q, osi_free);
224911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->waiting_for_ack_q = NULL;
2255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
226911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  fixed_queue_free(p_fcrb->srej_rcv_hold_q, osi_free);
227911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->srej_rcv_hold_q = NULL;
2285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
229911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  fixed_queue_free(p_fcrb->retrans_q, osi_free);
230911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->retrans_q = NULL;
2315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
233911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((p_ccb->local_cid >= L2CAP_BASE_APPL_CID) &&
234911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)) {
235911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    uint32_t dur = time_get_os_boottime_ms() - p_ccb->fcrb.connect_tick_count;
236911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    size_t p_str_size = 120;
237911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    char* p_str = (char*)osi_malloc(p_str_size);
238911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    uint16_t i;
239911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    uint32_t throughput_avg, ack_delay_avg, ack_q_count_avg;
240911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
241911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
242911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC,
243911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "---  L2CAP ERTM  Stats for CID: 0x%04x   Duration: %08ums",
244911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             p_ccb->local_cid, dur);
245911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
246911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC,
247911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "Retransmissions:%08u Times Flow Controlled:%08u Retrans "
248911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "Touts:%08u Ack Touts:%08u",
249911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             p_ccb->fcrb.pkts_retransmitted, p_ccb->fcrb.xmit_window_closed,
250911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             p_ccb->fcrb.retrans_touts, p_ccb->fcrb.xmit_ack_touts);
251911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
252911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC,
253911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "Times there is less than 2 packets in controller when flow "
254911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "controlled:%08u",
255911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             p_ccb->fcrb.controller_idle);
256911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
257911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC,
258911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "max_held_acks:%08u, in_cfg.fcr.tx_win_sz:%08u",
259911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             p_ccb->fcrb.max_held_acks, p_ccb->peer_cfg.fcr.tx_win_sz);
260911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
261911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    snprintf(
262911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_str, p_str_size,
263911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "Sent Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u "
264911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "SREJ:%08u",
265911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.ertm_pkt_counts[0], p_ccb->fcrb.ertm_byte_counts[0],
266911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[0] * 100) / (dur / 10) : 0),
267911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.s_frames_sent[0], p_ccb->fcrb.s_frames_sent[1],
268911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.s_frames_sent[2], p_ccb->fcrb.s_frames_sent[3]);
269911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
270911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
271911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC, "%s", p_str);
272911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
273911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    snprintf(
274911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_str, p_str_size,
275911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "Rcvd Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u "
276911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "SREJ:%08u",
277911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.ertm_pkt_counts[1], p_ccb->fcrb.ertm_byte_counts[1],
278911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[1] * 100) / (dur / 10) : 0),
279911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.s_frames_rcvd[0], p_ccb->fcrb.s_frames_rcvd[1],
280911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.s_frames_rcvd[2], p_ccb->fcrb.s_frames_rcvd[3]);
281911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
282911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
283911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC, "%s", p_str);
284911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
285911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    throughput_avg = 0;
286911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ack_delay_avg = 0;
287911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ack_q_count_avg = 0;
288911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
289911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    for (i = 0; i < L2CAP_ERTM_STATS_NUM_AVG; i++) {
290911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (i == p_ccb->fcrb.ack_delay_avg_index) {
291911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
292911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                 TRACE_TYPE_GENERIC, "[%02u] collecting data ...", i);
293911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        continue;
294911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
295911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
296911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      snprintf(p_str, p_str_size,
297911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, "
298911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               "ack_q_count avg:%3u, min:%3u, max:%3u",
299911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               i, p_ccb->fcrb.throughput[i], p_ccb->fcrb.ack_delay_avg[i],
300911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               p_ccb->fcrb.ack_delay_min[i], p_ccb->fcrb.ack_delay_max[i],
301911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               p_ccb->fcrb.ack_q_count_avg[i], p_ccb->fcrb.ack_q_count_min[i],
302911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               p_ccb->fcrb.ack_q_count_max[i]);
303911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
304911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
305911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               TRACE_TYPE_GENERIC, "%s", p_str);
306911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
307911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      throughput_avg += p_ccb->fcrb.throughput[i];
308911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      ack_delay_avg += p_ccb->fcrb.ack_delay_avg[i];
309911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      ack_q_count_avg += p_ccb->fcrb.ack_q_count_avg[i];
310911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
311911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
312911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    throughput_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
313911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ack_delay_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
314911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ack_q_count_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
315911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
316911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
317911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC,
318911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "throughput_avg: %8u (kbytes/sec), ack_delay_avg: %8u ms, "
319911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             "ack_q_count_avg: %8u",
320911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             throughput_avg, ack_delay_avg, ack_q_count_avg);
321911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
322911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_str);
323911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
324911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
325911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC, "---");
326911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
3275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
3285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
329911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  memset(p_fcrb, 0, sizeof(tL2C_FCRB));
3305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
3315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
333ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
334ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_clone_buf
335ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
3369ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Description      This function allocates and copies requested part of a
3379ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  buffer at a new-offset.
338ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
339ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          pointer to new buffer
340ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
341ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
342911d1ae03efec2d54c3b1b605589d790d1745488Myles WatsonBT_HDR* l2c_fcr_clone_buf(BT_HDR* p_buf, uint16_t new_offset,
343911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                          uint16_t no_of_bytes) {
344f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
345911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /*
346911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * NOTE: We allocate extra L2CAP_FCS_LEN octets, in case we need to put
347911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * the FCS (Frame Check Sequence) at the end of the buffer.
348911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   */
349911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
350871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov#if (L2CAP_ERTM_STATS == TRUE)
351911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /*
352911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * NOTE: If L2CAP_ERTM_STATS is enabled, we need 4 extra octets at the
353911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * end for a timestamp at the end of an I-frame.
354911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   */
355911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  buf_size += sizeof(uint32_t);
356871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov#endif
357911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR* p_buf2 = (BT_HDR*)osi_malloc(buf_size);
3585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
359911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf2->offset = new_offset;
360911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf2->len = no_of_bytes;
361911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  memcpy(((uint8_t*)(p_buf2 + 1)) + p_buf2->offset,
362911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         ((uint8_t*)(p_buf + 1)) + p_buf->offset, no_of_bytes);
3635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
364911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (p_buf2);
3655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
3665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
368ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
369ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_is_flow_controlled
370ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
371ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function checks if the CCB is flow controlled by peer.
372ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
373ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          The control word
374ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
375ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
376911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonbool l2c_fcr_is_flow_controlled(tL2C_CCB* p_ccb) {
377f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
378911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
379911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Check if remote side flowed us off or the transmit window is full */
380911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((p_ccb->fcrb.remote_busy == true) ||
381911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >=
382911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         p_ccb->peer_cfg.fcr.tx_win_sz)) {
3835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
384911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
385911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.xmit_window_closed++;
3865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
387911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if ((p_ccb->p_lcb->sent_not_acked < 2) &&
388911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            (l2cb.controller_xmit_window > 0))
389911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->fcrb.controller_idle++;
390911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
3915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
392911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return (true);
3935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
394911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
395911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (false);
3965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
3975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
399ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
400ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         prepare_I_frame
401ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
402ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function sets the FCR variables in an I-frame that is
403ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  about to be sent to HCI for transmission. This may be the
404ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  first time the I-frame is sent, or a retransmission
405ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
406ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
407ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
408ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
409911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf,
410911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            bool is_retransmission) {
411f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
412f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
413911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
414911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
415911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t fcs;
416911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t ctrl_word;
417911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool set_f_bit = p_fcrb->send_f_rsp;
4185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
419911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->send_f_rsp = false;
4205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
421911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (is_retransmission) {
422911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Get the old control word and clear out the old req_seq and F bits */
423911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
4245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
425911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    STREAM_TO_UINT16(ctrl_word, p);
4265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
427911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ctrl_word &= ~(L2CAP_FCR_REQ_SEQ_BITS + L2CAP_FCR_F_BIT);
428911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
429911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ctrl_word = p_buf->layer_specific & L2CAP_FCR_SEG_BITS; /* SAR bits */
430911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ctrl_word |=
431911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (p_fcrb->next_tx_seq << L2CAP_FCR_TX_SEQ_BITS_SHIFT); /* Tx Seq */
4325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
433911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcrb->next_tx_seq = (p_fcrb->next_tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
434911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
4355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
436911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Set the F-bit and reqseq only if using re-transmission mode */
437911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
438911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (set_f_bit) ctrl_word |= L2CAP_FCR_F_BIT;
4395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
440911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ctrl_word |= (p_fcrb->next_seq_expected) << L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
4415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
442911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcrb->last_ack_sent = p_ccb->fcrb.next_seq_expected;
4435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
444911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    alarm_cancel(p_ccb->fcrb.ack_timer);
445911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
4465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
447911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Set the control word */
448911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
4495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
450911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, ctrl_word);
4515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
452911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Compute the FCS and add to the end of the buffer if not bypassed */
453911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
454911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* length field in l2cap header has to include FCS length */
455911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
456911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    UINT16_TO_STREAM(p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD);
4575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
458911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Calculate the FCS */
459911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    fcs = l2c_fcr_tx_get_fcs(p_buf);
4605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
461911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Point to the end of the buffer and put the FCS there */
462911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /*
463911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * NOTE: Here we assume the allocated buffer is large enough
464911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * to include extra L2CAP_FCS_LEN octets at the end.
465911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     */
466911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len;
467911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
468911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    UINT16_TO_STREAM(p, fcs);
469911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
470911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->len += L2CAP_FCS_LEN;
471911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
472911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
473911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (is_retransmission) {
474911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_EVENT(
475911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP eRTM ReTx I-frame  CID: 0x%04x  Len: %u  SAR: %s  TxSeq: %u  "
476911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "ReqSeq: %u  F: %u",
477911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, p_buf->len,
478911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
479911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
480911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
481911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
482911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
483911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_EVENT(
484911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP eRTM Tx I-frame CID: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  "
485911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "ReqSeq: %u  F: %u",
486911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, p_buf->len,
487911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
488911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
489911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
490911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
491911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
492911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
493911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Start the retransmission timer if not already running */
494911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
495911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_start_timer(p_ccb);
4965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
4975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
499ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
500ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_send_S_frame
501ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
502ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function formats and sends an S-frame for transmission.
503ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
504ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
505ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
506ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
507911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code,
508911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                          uint16_t pf_bit) {
509f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
510911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
511911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t ctrl_word;
512911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t fcs;
5135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
514911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN)) return;
5155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
517911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.s_frames_sent[function_code]++;
5185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
5195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
520911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (pf_bit == L2CAP_FCR_P_BIT) {
521911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.wait_ack = true;
522911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
523911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_stop_timer(p_ccb); /* Restart the monitor timer */
524911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_start_timer(p_ccb);
525911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
526911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
527911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Create the control word to use */
528911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  ctrl_word = (function_code << L2CAP_FCR_SUP_SHIFT) | L2CAP_FCR_S_FRAME_BIT;
529911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT);
530911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  ctrl_word |= pf_bit;
531911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
532911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR* p_buf = (BT_HDR*)osi_malloc(L2CAP_CMD_BUF_SIZE);
533911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->offset = HCI_DATA_PREAMBLE_SIZE;
534911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->len = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
535911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
536911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Set the pointer to the beginning of the data */
537911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = (uint8_t*)(p_buf + 1) + p_buf->offset;
538911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
539911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Put in the L2CAP header */
540911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN);
541911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, p_ccb->remote_cid);
542911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, ctrl_word);
543911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
544911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Compute the FCS and add to the end of the buffer if not bypassed */
545911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
546911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    fcs = l2c_fcr_tx_get_fcs(p_buf);
547911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
548911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    UINT16_TO_STREAM(p, fcs);
549911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->len += L2CAP_FCS_LEN;
550911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
551911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* rewrite the length without FCS length */
552911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p -= 6;
553911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD);
554911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
555911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
556911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Now, the HCI transport header */
557911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT;
558911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  l2cu_set_acl_hci_header(p_buf, p_ccb);
559911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
560911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) ||
561911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) {
562911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING(
563911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP eRTM Tx S-frame  CID: 0x%04x  ctrlword: 0x%04x  Type: %s  "
564911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "ReqSeq: %u  P: %u  F: %u",
565911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, ctrl_word,
566911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
567911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
568911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
569911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
570911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING("                  Buf Len: %u", p_buf->len);
571911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
572911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_EVENT(
573911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP eRTM Tx S-frame  CID: 0x%04x  ctrlword: 0x%04x  Type: %s  "
574911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "ReqSeq: %u  P: %u  F: %u",
575911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, ctrl_word,
576911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
577911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
578911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
579911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
580911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_EVENT("                  Buf Len: %u", p_buf->len);
581911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
582911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
583911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
584911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
585911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.last_ack_sent = p_ccb->fcrb.next_seq_expected;
586911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
587911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  alarm_cancel(p_ccb->fcrb.ack_timer);
5885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
5895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
591ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
592ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_proc_pdu
593ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
594ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function is the entry point for processing of a
5959ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  received PDU when in flow control and/or retransmission
5969ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  modes.
597ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
598ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
599ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
600ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
601911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
602f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
603f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
604911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
605911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t fcs;
606911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t min_pdu_len;
607911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t ctrl_word;
608911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
609911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Check the length */
610911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  min_pdu_len = (p_ccb->bypass_fcs == L2CAP_BYPASS_FCS)
611911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                    ? (uint16_t)L2CAP_FCR_OVERHEAD
612911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                    : (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD);
613911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
614911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_buf->len < min_pdu_len) {
615911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x  Len too short: %u",
616911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        p_ccb->local_cid, p_buf->len);
617911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_buf);
618911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
619911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
6205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
621911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_STREAM_MODE) {
622911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    process_stream_frame(p_ccb, p_buf);
623911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
624911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
625911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
626911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Get the control word */
627911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
628911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  STREAM_TO_UINT16(ctrl_word, p);
629911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
630911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) {
631911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) ||
632911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) {
633911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* REJ or SREJ */
634911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING(
635911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "L2CAP eRTM Rx S-frame: cid: 0x%04x  Len: %u  Type: %s  ReqSeq: %u  "
636911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "P: %u  F: %u",
637911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->local_cid, p_buf->len,
638911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
639911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
640911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
641911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
642911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else {
643911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_EVENT(
644911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "L2CAP eRTM Rx S-frame: cid: 0x%04x  Len: %u  Type: %s  ReqSeq: %u  "
645911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "P: %u  F: %u",
646911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->local_cid, p_buf->len,
647911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
648911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
649911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
650911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
651911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
652911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
653911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_EVENT(
654911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP eRTM Rx I-frame: cid: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  "
655911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "ReqSeq: %u  F: %u",
656911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, p_buf->len,
657911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
658911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
659911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
660911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
661911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
662911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
663911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  L2CAP_TRACE_EVENT(
664911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "      eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt "
665911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "%u, wt_q.cnt %u, tries %u",
666911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack,
667911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent,
668911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q), p_ccb->fcrb.num_tries);
669911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
670911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Verify FCS if using */
671911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
672911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
673911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
674911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Extract and drop the FCS from the packet */
675911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    STREAM_TO_UINT16(fcs, p);
676911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->len -= L2CAP_FCS_LEN;
677911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
678911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (l2c_fcr_rx_get_fcs(p_buf) != fcs) {
679911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x  BAD FCS",
680911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                          p_ccb->local_cid);
681911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
682911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return;
683911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
684911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
685911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
686911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Get the control word */
687911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
688911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
689911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  STREAM_TO_UINT16(ctrl_word, p);
690911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
691911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->len -= L2CAP_FCR_OVERHEAD;
692911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->offset += L2CAP_FCR_OVERHEAD;
693911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
694911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If we had a poll bit outstanding, check if we got a final response */
695911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->fcrb.wait_ack) {
696911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If final bit not set, ignore the frame unless it is a polled S-frame */
697911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!(ctrl_word & L2CAP_FCR_F_BIT)) {
698911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((ctrl_word & L2CAP_FCR_P_BIT) &&
699911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (ctrl_word & L2CAP_FCR_S_FRAME_BIT)) {
700911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (p_ccb->fcrb.srej_sent)
701911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
702911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        else if (p_ccb->fcrb.local_busy)
703911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
7045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
705911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
706911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
707911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* Got a poll while in wait_ack state, so re-start our timer with
708911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         * 1-second */
709911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* This is a small optimization... the monitor timer is 12 secs, but we
710911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         * saw */
711911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* that if the other side sends us a poll when we are waiting for a
712911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         * final,  */
713911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* then it speeds up recovery significantly if we poll him back soon
714911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         * after his poll. */
715911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, BT_1SEC_TIMEOUT_MS,
716911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           l2c_ccb_timer_timeout, p_ccb,
717911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           btu_general_alarm_queue);
718911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
719911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
720911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return;
7215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
7225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
723911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.wait_ack = false;
7245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
725911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* P and F are mutually exclusive */
726911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) ctrl_word &= ~L2CAP_FCR_P_BIT;
7275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
728911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
729911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.num_tries = 0;
7305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
731911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_stop_timer(p_ccb);
732911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
733911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Otherwise, ensure the final bit is ignored */
734911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ctrl_word &= ~L2CAP_FCR_F_BIT;
735911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
7365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
737911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Process receive sequence number */
738911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!process_reqseq(p_ccb, ctrl_word)) {
739911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_buf);
740911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
741911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
742911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
743911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Process based on whether it is an S-frame or an I-frame */
744911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
745911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    process_s_frame(p_ccb, p_buf, ctrl_word);
746911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  else
747911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    process_i_frame(p_ccb, p_buf, ctrl_word, false);
748911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
749911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Return if the channel got disconnected by a bad packet or max
750911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * retransmissions */
751911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN)) return;
752911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
753911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If we have some buffers held while doing SREJ, and SREJ has cleared,
754911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * process them now */
755911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) &&
756911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (!fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q))) {
757911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    fixed_queue_t* temp_q = p_ccb->fcrb.srej_rcv_hold_q;
758911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
759911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
760911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(temp_q)) != NULL) {
761911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) {
762911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* Get the control word */
763911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p = ((uint8_t*)(p_buf + 1)) + p_buf->offset - L2CAP_FCR_OVERHEAD;
764911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
765911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        STREAM_TO_UINT16(ctrl_word, p);
766911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
767911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_DEBUG(
768911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "l2c_fcr_proc_pdu() CID: 0x%04x  Process Buffer from SREJ_Hold_Q   "
769911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "TxSeq: %u  Expected_Seq: %u",
770911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_ccb->local_cid,
771911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
772911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_ccb->fcrb.next_seq_expected);
773911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
774911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* Process the SREJ held I-frame, but do not send an RR for each
775911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         * individual frame */
776911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        process_i_frame(p_ccb, p_buf, ctrl_word, true);
777911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      } else
778cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free(p_buf);
7795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
780911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* If more frames were lost during SREJ, send a REJ */
781911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_ccb->fcrb.rej_after_srej) {
782911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.rej_after_srej = false;
783911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.rej_sent = true;
784911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
785911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_REJ, 0);
786911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
787911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
788911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    fixed_queue_free(temp_q, NULL);
789911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
790911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Now, if needed, send one RR for the whole held queue */
791911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.rej_sent) &&
792911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (!p_ccb->fcrb.srej_sent) &&
793911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent))
794911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0);
795911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else {
796911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_DEBUG(
797911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "l2c_fcr_proc_pdu() not sending RR CID: 0x%04x  local_busy:%d "
798911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u",
799911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->local_cid, p_ccb->fcrb.local_busy, p_ccb->fcrb.rej_sent,
800911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->fcrb.srej_sent, p_ccb->fcrb.next_seq_expected,
801911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->fcrb.last_ack_sent);
802911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
803911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
804911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
805911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If a window has opened, check if we can send any more packets */
806911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((!fixed_queue_is_empty(p_ccb->fcrb.retrans_q) ||
807911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       !fixed_queue_is_empty(p_ccb->xmit_hold_q)) &&
808911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (p_ccb->fcrb.wait_ack == false) &&
809911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (l2c_fcr_is_flow_controlled(p_ccb) == false)) {
810911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
811911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
8125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
8135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
8145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
815ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
816ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_lcc_proc_pdu
817ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
818ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function is the entry point for processing of a
819ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  received PDU when in LE Coc flow control modes.
820ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
821ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
822ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
823ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
824911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
825f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
826f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
827911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
828911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t sdu_length;
829911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR* p_data = NULL;
830911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
831911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Buffer length should not exceed local mps */
832911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_buf->len > p_ccb->local_conn_cfg.mps) {
833911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Discard the buffer */
8346721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    osi_free(p_buf);
8356721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    return;
836911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
837911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
838911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->is_first_seg) {
839911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    STREAM_TO_UINT16(sdu_length, p);
840911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Check the SDU Length with local MTU size */
841911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (sdu_length > p_ccb->local_conn_cfg.mtu) {
842911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Discard the buffer */
843911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
844911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return;
845911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
846911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
847911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_data = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
848911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_data == NULL) {
849911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
850911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return;
851911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
852911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
853911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->ble_sdu = p_data;
854911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_data->len = 0;
855911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->ble_sdu_length = sdu_length;
856911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_DEBUG("%s SDU Length = %d", __func__, sdu_length);
857911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->len -= sizeof(sdu_length);
858911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->offset += sizeof(sdu_length);
859911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_data->offset = 0;
860911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
861911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else
862911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_data = p_ccb->ble_sdu;
863911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
864911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  memcpy((uint8_t*)(p_data + 1) + p_data->offset + p_data->len,
865911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
866911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_data->len += p_buf->len;
867911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = (uint8_t*)(p_data + 1) + p_data->offset;
868911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_data->len == p_ccb->ble_sdu_length) {
869911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_data);
870911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->is_first_seg = true;
871911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->ble_sdu = NULL;
872911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->ble_sdu_length = 0;
873911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else if (p_data->len < p_ccb->ble_sdu_length) {
874911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->is_first_seg = false;
875911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
876911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_ERROR("%s Length in the SDU messed up", __func__);
877911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    // TODO: reset every thing may be???
878911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
879911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
880911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  osi_free(p_buf);
881911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return;
8826721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar}
8836721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8846721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar/*******************************************************************************
885ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
886ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_proc_tout
887ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
888ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Handle a timeout. We should be in error recovery state.
889ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
890ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
891ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
892ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
893911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_proc_tout(tL2C_CCB* p_ccb) {
894f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
895911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  L2CAP_TRACE_DEBUG(
896911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "l2c_fcr_proc_tout:  CID: 0x%04x  num_tries: %u (max: %u)  wait_ack: %u  "
897911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "ack_q_count: %u",
898911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit,
899911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.wait_ack, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
9005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
902911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.retrans_touts++;
9035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
9045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
905911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((p_ccb->peer_cfg.fcr.max_transmit != 0) &&
906911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (++p_ccb->fcrb.num_tries > p_ccb->peer_cfg.fcr.max_transmit)) {
907911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2cu_disconnect_chnl(p_ccb);
908911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
909911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!p_ccb->fcrb.srej_sent && !p_ccb->fcrb.rej_sent) {
910911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_ccb->fcrb.local_busy)
911911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_P_BIT);
912911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      else
913911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
914911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
915911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
9165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
9175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
919ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
920ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_proc_ack_tout
921ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
922ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Send RR/RNR if we have not acked I frame
923ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
924ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
925ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
926ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
927911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_proc_ack_tout(tL2C_CCB* p_ccb) {
928f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
929911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  L2CAP_TRACE_DEBUG(
930911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "l2c_fcr_proc_ack_tout:  CID: 0x%04x State: %u  Wack:%u  Rq:%d  Acked:%d",
931911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->local_cid, p_ccb->chnl_state, p_ccb->fcrb.wait_ack,
932911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent);
933911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
934911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack) &&
935911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (p_ccb->fcrb.last_ack_sent != p_ccb->fcrb.next_seq_expected)) {
9365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
937911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.xmit_ack_touts++;
9385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
939911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_ccb->fcrb.local_busy)
940911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
941911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else
942911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0);
943911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
9445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
9455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
947ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
948ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_reqseq
949ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
950ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Handle receive sequence number
951ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
952ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
953ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
954ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
955911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic bool process_reqseq(tL2C_CCB* p_ccb, uint16_t ctrl_word) {
956f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
957911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
958911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t req_seq, num_bufs_acked, xx;
959911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t ls;
960911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t full_sdus_xmitted;
961911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
962911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Receive sequence number does not ack anything for SREJ with P-bit set to
963911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * zero */
964911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((ctrl_word & L2CAP_FCR_S_FRAME_BIT) &&
965911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      ((ctrl_word & L2CAP_FCR_SUP_BITS) ==
966911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       (L2CAP_FCR_SUP_SREJ << L2CAP_FCR_SUP_SHIFT)) &&
967911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      ((ctrl_word & L2CAP_FCR_P_BIT) == 0)) {
968911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If anything still waiting for ack, restart the timer if it was stopped */
969911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
970911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_fcr_start_timer(p_ccb);
9715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
972911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return (true);
973911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
9745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
975911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Extract the receive sequence number from the control word */
976911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  req_seq =
977911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
9785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
979911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  num_bufs_acked = (req_seq - p_fcrb->last_rx_ack) & L2CAP_FCR_SEQ_MODULO;
9805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
981911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Verify the request sequence is in range before proceeding */
982911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (num_bufs_acked > fixed_queue_length(p_fcrb->waiting_for_ack_q)) {
983911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* The channel is closed if ReqSeq is not in range */
984911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING(
985911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x  req_seq 0x%02x  "
986911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "last_rx_ack: 0x%02x  QCount: %u",
987911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        ctrl_word, req_seq, p_fcrb->last_rx_ack,
988911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        fixed_queue_length(p_fcrb->waiting_for_ack_q));
9895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
990911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2cu_disconnect_chnl(p_ccb);
991911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return (false);
992911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
9935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
994911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->last_rx_ack = req_seq;
9955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
996911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Now we can release all acknowledged frames, and restart the retransmission
997911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * timer if needed */
998911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (num_bufs_acked != 0) {
999911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcrb->num_tries = 0;
1000911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    full_sdus_xmitted = 0;
10015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
1003911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_collect_ack_delay(p_ccb, num_bufs_acked);
10045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
10055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1006911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    for (xx = 0; xx < num_bufs_acked; xx++) {
1007911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      BT_HDR* p_tmp =
1008911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (BT_HDR*)fixed_queue_try_dequeue(p_fcrb->waiting_for_ack_q);
1009911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      ls = p_tmp->layer_specific & L2CAP_FCR_SAR_BITS;
10105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1011911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU))
1012911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        full_sdus_xmitted++;
10135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1014911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_tmp);
1015911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
10165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1017911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If we are still in a wait_ack state, do not mess with the timer */
1018911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!p_ccb->fcrb.wait_ack) l2c_fcr_stop_timer(p_ccb);
10195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1020911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Check if we need to call the "packet_sent" callback */
1021911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) &&
1022911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (full_sdus_xmitted)) {
1023911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Special case for eRTM, if all packets sent, send 0xFFFF */
1024911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (fixed_queue_is_empty(p_fcrb->waiting_for_ack_q) &&
1025911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
1026911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        full_sdus_xmitted = 0xFFFF;
1027911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
1028911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1029911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid,
1030911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                               full_sdus_xmitted);
10315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1032911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
10335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1034911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If anything still waiting for ack, restart the timer if it was stopped */
1035911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
1036911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_start_timer(p_ccb);
1037911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (true);
10385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
10395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1041ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1042ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_s_frame
1043ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1044ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Process an S frame
1045ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1046ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
1047ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1048ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1049911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void process_s_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf,
1050911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            uint16_t ctrl_word) {
1051f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1052f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
1053ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
1054911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
1055911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t s_frame_type =
1056911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT;
1057911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool remote_was_busy;
1058911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool all_ok = true;
10595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1060911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_buf->len != 0) {
1061911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING("Incorrect S-frame Length (%d)", p_buf->len);
1062911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
10635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1064911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  L2CAP_TRACE_DEBUG("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d",
1065911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                    ctrl_word, p_fcrb->remote_busy);
10665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
1068911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.s_frames_rcvd[s_frame_type]++;
10695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
10705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1071911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (ctrl_word & L2CAP_FCR_P_BIT) {
1072911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcrb->rej_sent = false;  /* After checkpoint, we can send anoher REJ */
1073911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcrb->send_f_rsp = true; /* Set a flag in case an I-frame is pending */
1074911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
10755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1076911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  switch (s_frame_type) {
10775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_RR:
1078911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      remote_was_busy = p_fcrb->remote_busy;
1079911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_fcrb->remote_busy = false;
10805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1081911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((ctrl_word & L2CAP_FCR_F_BIT) || (remote_was_busy))
1082911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        all_ok = retransmit_i_frames(p_ccb, L2C_FCR_RETX_ALL_PKTS);
1083911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      break;
10845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_REJ:
1086911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_fcrb->remote_busy = false;
1087911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      all_ok = retransmit_i_frames(p_ccb, L2C_FCR_RETX_ALL_PKTS);
1088911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      break;
10895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_RNR:
1091911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_fcrb->remote_busy = true;
1092911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_fcr_stop_timer(p_ccb);
1093911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      break;
10945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_SREJ:
1096911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_fcrb->remote_busy = false;
1097911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      all_ok = retransmit_i_frames(
1098911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb, (uint8_t)((ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >>
1099911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           L2CAP_FCR_REQ_SEQ_BITS_SHIFT));
1100911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      break;
1101911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1102911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1103911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (all_ok) {
1104911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If polled, we need to respond with F-bit. Note, we may have sent a
1105911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * I-frame with the F-bit */
1106911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_fcrb->send_f_rsp) {
1107911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcrb->srej_sent)
1108911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
1109911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      else if (p_fcrb->local_busy)
1110911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
1111911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      else
1112911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
1113911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1114911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_fcrb->send_f_rsp = false;
1115911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1116911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
1117911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_DEBUG("process_s_frame hit_max_retries");
1118911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1119911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1120911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  osi_free(p_buf);
11215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
11225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1124ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1125ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_i_frame
1126ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1127ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Process an I frame
1128ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1129ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
1130ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1131ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1132911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word,
1133911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            bool delay_ack) {
1134f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1135f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
1136ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
1137911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
1138911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t tx_seq, num_lost, num_to_ack, next_srej;
11395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1140911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If we were doing checkpoint recovery, first retransmit all unacked I-frames
1141911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   */
1142911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (ctrl_word & L2CAP_FCR_F_BIT) {
1143911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!retransmit_i_frames(p_ccb, L2C_FCR_RETX_ALL_PKTS)) {
1144911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
1145911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return;
11465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1147911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
11485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
1150911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.ertm_pkt_counts[1]++;
1151911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.ertm_byte_counts[1] += p_buf->len;
11525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
11535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1154911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Extract the sequence number */
1155911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
11565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1157911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If we have flow controlled the peer, ignore any bad I-frames from him */
1158911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((tx_seq != p_fcrb->next_seq_expected) && (p_fcrb->local_busy)) {
1159911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING("Dropping bad I-Frame since we flowed off, tx_seq:%u",
1160911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        tx_seq);
1161911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
1162911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_buf);
1163911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
1164911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1165911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1166911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Check if tx-sequence is the expected one */
1167911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (tx_seq != p_fcrb->next_seq_expected) {
1168911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    num_lost = (tx_seq - p_fcrb->next_seq_expected) & L2CAP_FCR_SEQ_MODULO;
1169911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1170911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Is the frame a duplicate ? If so, just drop it */
1171911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz) {
1172911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Duplicate - simply drop it */
1173911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING(
1174911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "process_i_frame() Dropping Duplicate Frame tx_seq:%u  ExpectedTxSeq "
1175911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "%u",
1176911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          tx_seq, p_fcrb->next_seq_expected);
1177911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
1178911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else {
1179911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING(
1180911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "process_i_frame() CID: 0x%04x  Lost: %u  tx_seq:%u  ExpTxSeq %u  "
1181911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "Rej: %u  SRej: %u",
1182911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected,
1183911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcrb->rej_sent, p_fcrb->srej_sent);
1184911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1185911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcrb->srej_sent) {
1186911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* If SREJ sent, save the frame for later processing as long as it is in
1187911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         * sequence */
1188911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        next_srej =
1189911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            (((BT_HDR*)fixed_queue_try_peek_last(p_fcrb->srej_rcv_hold_q))
1190911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                 ->layer_specific +
1191911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             1) &
1192911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            L2CAP_FCR_SEQ_MODULO;
1193911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1194911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if ((tx_seq == next_srej) &&
1195911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            (fixed_queue_length(p_fcrb->srej_rcv_hold_q) <
1196911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             p_ccb->our_cfg.fcr.tx_win_sz)) {
1197911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          /* If user gave us a pool for held rx buffers, use that */
1198911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          /* TODO: Could that happen? Get rid of this code. */
1199911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          if (p_ccb->ertm_info.fcr_rx_buf_size != L2CAP_FCR_RX_BUF_SIZE) {
1200911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            BT_HDR* p_buf2;
1201911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1202911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            /* Adjust offset and len so that control word is copied */
1203911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_buf->offset -= L2CAP_FCR_OVERHEAD;
1204911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_buf->len += L2CAP_FCR_OVERHEAD;
1205911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1206911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
1207911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1208911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            if (p_buf2) {
1209911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              osi_free(p_buf);
1210911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              p_buf = p_buf2;
12115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
1212911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_buf->offset += L2CAP_FCR_OVERHEAD;
1213911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_buf->len -= L2CAP_FCR_OVERHEAD;
1214911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          }
1215911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          L2CAP_TRACE_DEBUG(
1216911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              "process_i_frame() Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: %u  "
1217911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              "SRej1",
1218911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
1219911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1220911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_buf->layer_specific = tx_seq;
1221911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
1222911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        } else {
1223911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          L2CAP_TRACE_WARNING(
1224911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              "process_i_frame() CID: 0x%04x  frame dropped in Srej Sent "
1225911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              "next_srej:%u  hold_q.count:%u  win_sz:%u",
1226911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              p_ccb->local_cid, next_srej,
1227911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              fixed_queue_length(p_fcrb->srej_rcv_hold_q),
1228911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              p_ccb->our_cfg.fcr.tx_win_sz);
1229911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1230911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcrb->rej_after_srej = true;
1231911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          osi_free(p_buf);
12325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
1233911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      } else if (p_fcrb->rej_sent) {
1234911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_WARNING(
1235911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "process_i_frame() CID: 0x%04x  Lost: %u  tx_seq:%u  ExpTxSeq %u  "
1236911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "Rej: 1  SRej: %u",
1237911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected,
1238911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_fcrb->srej_sent);
1239911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1240911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* If REJ sent, just drop the frame */
1241911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        osi_free(p_buf);
1242911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      } else {
1243911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_DEBUG(
1244911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "process_i_frame() CID: 0x%04x  tx_seq:%u  ExpTxSeq %u  Rej: %u",
1245911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected,
1246911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_fcrb->rej_sent);
1247911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1248911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* If only one lost, we will send SREJ, otherwise we will send REJ */
1249911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (num_lost > 1) {
1250911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          osi_free(p_buf);
1251911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcrb->rej_sent = true;
1252911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_REJ, 0);
1253911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        } else {
1254911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          if (!fixed_queue_is_empty(p_fcrb->srej_rcv_hold_q)) {
1255911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            L2CAP_TRACE_ERROR(
1256911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                "process_i_frame() CID: 0x%04x  sending SREJ tx_seq:%d "
1257911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                "hold_q.count:%u",
1258911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                p_ccb->local_cid, tx_seq,
1259911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                fixed_queue_length(p_fcrb->srej_rcv_hold_q));
1260911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          }
1261911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_buf->layer_specific = tx_seq;
1262911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
1263911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcrb->srej_sent = true;
1264911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_SREJ, 0);
12655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
1266911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        alarm_cancel(p_ccb->fcrb.ack_timer);
1267911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
12685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1269911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
1270911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1271911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1272911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Seq number is the next expected. Clear possible reject exception in case it
1273911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * occured */
1274911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->rej_sent = p_fcrb->srej_sent = false;
1275911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1276911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Adjust the next_seq, so that if the upper layer sends more data in the
1277911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     callback
1278911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     context, the received frame is acked by an I-frame. */
1279911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_fcrb->next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
1280911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1281911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If any SAR problem in eRTM mode, spec says disconnect. */
1282911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!do_sar_reassembly(p_ccb, p_buf, ctrl_word)) {
1283911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING("process_i_frame() CID: 0x%04x  reassembly failed",
1284911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        p_ccb->local_cid);
1285911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2cu_disconnect_chnl(p_ccb);
1286911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
1287911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1288911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1289911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* RR optimization - if peer can still send us more, then start an ACK timer
1290911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   */
1291911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  num_to_ack = (p_fcrb->next_seq_expected - p_fcrb->last_ack_sent) &
1292911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               L2CAP_FCR_SEQ_MODULO;
1293911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1294911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((num_to_ack < p_ccb->fcrb.max_held_acks) && (!p_fcrb->local_busy))
1295911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    delay_ack = true;
1296911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1297911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* We should neve never ack frame if we are not in OPEN state */
1298911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((num_to_ack != 0) && p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) {
1299911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If no frames are awaiting transmission or are held, send an RR or RNR
1300911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * S-frame for ack */
1301911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (delay_ack) {
1302911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* If it is the first I frame we did not ack, start ack timer */
1303911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (!alarm_is_scheduled(p_ccb->fcrb.ack_timer)) {
1304911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        alarm_set_on_queue(p_ccb->fcrb.ack_timer, L2CAP_FCR_ACK_TIMEOUT_MS,
1305911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           l2c_fcrb_ack_timer_timeout, p_ccb,
1306911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           btu_general_alarm_queue);
1307911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
1308911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else if ((fixed_queue_is_empty(p_ccb->xmit_hold_q) ||
1309911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                l2c_fcr_is_flow_controlled(p_ccb)) &&
1310911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q)) {
1311911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcrb->local_busy)
1312911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
1313911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      else
1314911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0);
1315911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1316911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
13175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
13185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1320ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1321ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_stream_frame
1322ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1323ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function processes frames in streaming mode
1324ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1325ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
1326ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1327ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1328911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void process_stream_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
1329f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1330f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
13315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1332911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t ctrl_word;
1333911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t fcs;
1334911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
1335911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t tx_seq;
13365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1337911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Verify FCS if using */
1338911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
1339911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
13405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1341911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Extract and drop the FCS from the packet */
1342911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    STREAM_TO_UINT16(fcs, p);
1343911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->len -= L2CAP_FCS_LEN;
13445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1345911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (l2c_fcr_rx_get_fcs(p_buf) != fcs) {
1346911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x  BAD FCS",
1347911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                          p_ccb->local_cid);
1348911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(p_buf);
1349911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return;
13505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1351911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
13525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1353911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Get the control word */
1354911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
13555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1356911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  STREAM_TO_UINT16(ctrl_word, p);
13575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1358911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->len -= L2CAP_FCR_OVERHEAD;
1359911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf->offset += L2CAP_FCR_OVERHEAD;
13605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1361911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Make sure it is an I-frame */
1362911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) {
1363911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING(
1364911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "Rx L2CAP PDU: CID: 0x%04x  BAD S-frame in streaming mode  ctrl_word: "
1365911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "0x%04x",
1366911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, ctrl_word);
1367911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_buf);
1368911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return;
1369911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1370911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1371911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  L2CAP_TRACE_EVENT(
1372911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "L2CAP eRTM Rx I-frame: cid: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  "
1373911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "ReqSeq: %u  F: %u",
1374911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->local_cid, p_buf->len,
1375911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
1376911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
1377911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
1378911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
1379911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1380911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Extract the sequence number */
1381911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
1382911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1383911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Check if tx-sequence is the expected one */
1384911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (tx_seq != p_ccb->fcrb.next_seq_expected) {
1385911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING(
1386911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "Rx L2CAP PDU: CID: 0x%04x  Lost frames Exp: %u  Got: %u  p_rx_sdu: "
1387911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "0x%08x",
1388911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->local_cid, p_ccb->fcrb.next_seq_expected, tx_seq,
1389911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.p_rx_sdu);
1390911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1391911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Lost one or more packets, so flush the SAR queue */
1392911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free_and_reset((void**)&p_ccb->fcrb.p_rx_sdu);
1393911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1394911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1395911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
1396911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1397911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!do_sar_reassembly(p_ccb, p_buf, ctrl_word)) {
1398911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Some sort of SAR error, so flush the SAR queue */
1399911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free_and_reset((void**)&p_ccb->fcrb.p_rx_sdu);
1400911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
14015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
14025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1404ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1405ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         do_sar_reassembly
1406ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1407ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Process SAR bits and re-assemble frame
1408ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1409ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          true if all OK, else false
1410ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1411ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1412911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf,
1413911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                              uint16_t ctrl_word) {
1414f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1415f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_buf != NULL);
1416911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1417911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
1418911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t sar_type = ctrl_word & L2CAP_FCR_SEG_BITS;
1419911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool packet_ok = true;
1420911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
1421911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1422911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Check if the SAR state is correct */
1423911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU)) {
1424911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_fcrb->p_rx_sdu != NULL) {
1425911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING(
1426911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "SAR - got unexpected unsegmented or start SDU  Expected len: %u  "
1427911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "Got so far: %u",
1428911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len);
1429911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1430911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      packet_ok = false;
1431911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1432911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Check the length of the packet */
1433911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((sar_type == L2CAP_FCR_START_SDU) &&
1434911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (p_buf->len < L2CAP_SDU_LEN_OVERHEAD)) {
1435911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING("SAR start packet too short: %u", p_buf->len);
1436911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      packet_ok = false;
1437911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1438911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
1439911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_fcrb->p_rx_sdu == NULL) {
1440911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING("SAR - got unexpected cont or end SDU");
1441911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      packet_ok = false;
1442911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1443911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1444911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1445911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((packet_ok) && (sar_type != L2CAP_FCR_UNSEG_SDU)) {
1446911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
1447911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1448911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* For start SDU packet, extract the SDU length */
1449911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (sar_type == L2CAP_FCR_START_SDU) {
1450911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Get the SDU length */
1451911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      STREAM_TO_UINT16(p_fcrb->rx_sdu_len, p);
1452911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf->offset += 2;
1453911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf->len -= 2;
1454911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1455911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu) {
1456911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_WARNING("SAR - SDU len: %u  larger than MTU: %u",
1457911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len);
1458911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        packet_ok = false;
1459911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      } else {
1460911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcrb->p_rx_sdu = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
1461911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcrb->p_rx_sdu->offset = OBX_BUF_MIN_OFFSET;
1462911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcrb->p_rx_sdu->len = 0;
1463911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
1464911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1465911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1466911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (packet_ok) {
1467911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len) {
1468911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_ERROR(
1469911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "SAR - SDU len exceeded  Type: %u   Lengths: %u %u %u", sar_type,
1470911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
1471911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        packet_ok = false;
1472911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      } else if ((sar_type == L2CAP_FCR_END_SDU) &&
1473911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                 ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len)) {
1474911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_WARNING("SAR - SDU end rcvd but SDU incomplete: %u %u %u",
1475911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            p_fcrb->p_rx_sdu->len, p_buf->len,
1476911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            p_fcrb->rx_sdu_len);
1477911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        packet_ok = false;
1478911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      } else {
1479911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        memcpy(((uint8_t*)(p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset +
1480911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                   p_fcrb->p_rx_sdu->len,
1481911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson               p, p_buf->len);
1482911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1483911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcrb->p_rx_sdu->len += p_buf->len;
14845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1485911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        osi_free(p_buf);
1486911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_buf = NULL;
14875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1488911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (sar_type == L2CAP_FCR_END_SDU) {
1489911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_buf = p_fcrb->p_rx_sdu;
1490911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcrb->p_rx_sdu = NULL;
14915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
1492911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
14935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1494911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
14955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1496911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (packet_ok == false) {
1497911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_buf);
1498911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else if (p_buf != NULL) {
14995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_NUM_FIXED_CHNLS > 0)
1500911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_ccb->local_cid < L2CAP_BASE_APPL_CID &&
1501911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
1502911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL)) {
1503911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
1504911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              .pL2CA_FixedData_Cb)
1505911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
1506911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              .pL2CA_FixedData_Cb)(p_ccb->local_cid,
1507911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                   p_ccb->p_lcb->remote_bd_addr, p_buf);
1508911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else
15095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
1510911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_buf);
1511911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
15125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1513911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (packet_ok);
15145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
15155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1517ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1518ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         retransmit_i_frames
1519ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1520ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function retransmits i-frames awaiting acks.
1521ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1522ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          bool    - true if retransmitted
1523ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1524ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1525911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic bool retransmit_i_frames(tL2C_CCB* p_ccb, uint8_t tx_seq) {
1526f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1527911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1528911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR* p_buf = NULL;
1529911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
1530911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t buf_seq;
1531911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t ctrl_word;
1532911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1533911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) &&
1534911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (p_ccb->peer_cfg.fcr.max_transmit != 0) &&
1535911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit)) {
1536911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_EVENT(
1537911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "Max Tries Exceeded:  (last_acq: %d  CID: 0x%04x  num_tries: %u (max: "
1538911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "%u) ack_q_count: %u",
1539911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries,
1540911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->peer_cfg.fcr.max_transmit,
1541911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
1542911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1543911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2cu_disconnect_chnl(p_ccb);
1544911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return (false);
1545911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1546911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1547911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* tx_seq indicates whether to retransmit a specific sequence or all (if ==
1548911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * L2C_FCR_RETX_ALL_PKTS) */
1549911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  list_t* list_ack = NULL;
1550911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  const list_node_t* node_ack = NULL;
1551911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) {
1552911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    list_ack = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
1553911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    node_ack = list_begin(list_ack);
1554911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1555911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (tx_seq != L2C_FCR_RETX_ALL_PKTS) {
1556911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If sending only one, the sequence number tells us which one. Look for it.
1557911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    */
1558911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (list_ack != NULL) {
1559911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      for (; node_ack != list_end(list_ack); node_ack = list_next(node_ack)) {
1560911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_buf = (BT_HDR*)list_node(node_ack);
1561911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* Get the old control word */
1562911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
15635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1564911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        STREAM_TO_UINT16(ctrl_word, p);
15655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1566911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        buf_seq =
1567911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
15685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1569911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_DEBUG(
1570911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "retransmit_i_frames()   cur seq: %u  looking for: %u", buf_seq,
1571911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            tx_seq);
15725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1573911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (tx_seq == buf_seq) break;
1574911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
1575911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
15765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1577911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!p_buf) {
1578911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_ERROR("retransmit_i_frames() UNKNOWN seq: %u  q_count: %u",
1579911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        tx_seq,
1580911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
1581911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return (true);
1582911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1583911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
1584911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    // Iterate though list and flush the amount requested from
1585911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    // the transmit data queue that satisfy the layer and event conditions.
1586911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    for (list_node_t* node_tmp = list_begin(p_ccb->p_lcb->link_xmit_data_q);
1587911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         node_tmp != list_end(p_ccb->p_lcb->link_xmit_data_q);) {
1588911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      BT_HDR* p_tmp = (BT_HDR*)list_node(node_tmp);
1589911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      node_tmp = list_next(node_tmp);
15905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1591911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Do not flush other CIDs or partial segments */
1592911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((p_tmp->layer_specific == 0) && (p_tmp->event == p_ccb->local_cid)) {
1593911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        list_remove(p_ccb->p_lcb->link_xmit_data_q, p_tmp);
1594911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        osi_free(p_tmp);
1595911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
15965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
15975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1598911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Also flush our retransmission queue */
1599911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    while (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
1600911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      osi_free(fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q));
16015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1602911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (list_ack != NULL) node_ack = list_begin(list_ack);
1603911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
16045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1605911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (list_ack != NULL) {
1606911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    while (node_ack != list_end(list_ack)) {
1607911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf = (BT_HDR*)list_node(node_ack);
1608911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      node_ack = list_next(node_ack);
16095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1610911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      BT_HDR* p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
1611911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_buf2) {
1612911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_buf2->layer_specific = p_buf->layer_specific;
1613577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov
1614911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        fixed_queue_enqueue(p_ccb->fcrb.retrans_q, p_buf2);
1615911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
16165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1617911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL)) break;
16185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1619911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
16205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1621911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
16225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1623911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q)) {
1624911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.num_tries++;
1625911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2c_fcr_start_timer(p_ccb);
1626911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
16275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1628911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (true);
16295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
16305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1632ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1633ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_get_next_xmit_sdu_seg
1634ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1635ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Get the next SDU segment to transmit.
1636ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1637ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          pointer to buffer with segment or NULL
1638ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1639ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1640911d1ae03efec2d54c3b1b605589d790d1745488Myles WatsonBT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
1641911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                      uint16_t max_packet_length) {
1642f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1643911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1644911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool first_seg = false, /* The segment is the first part of data  */
1645911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      mid_seg = false,    /* The segment is the middle part of data */
1646911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      last_seg = false;   /* The segment is the last part of data   */
1647911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t sdu_len = 0;
1648911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR *p_buf, *p_xmit;
1649911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
1650911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/;
1651911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1652911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If there is anything in the retransmit queue, that goes first
1653911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  */
1654911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q);
1655911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_buf != NULL) {
1656911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Update Rx Seq and FCS if we acked some packets while this one was queued
1657911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     */
1658911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    prepare_I_frame(p_ccb, p_buf, true);
16595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1660911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->event = p_ccb->local_cid;
16615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
1663911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.pkts_retransmitted++;
1664911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ertm_pkt_counts[0]++;
1665911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ertm_byte_counts[0] += (p_buf->len - 8);
16665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
1667911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return (p_buf);
1668911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1669911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1670911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* For BD/EDR controller, max_packet_length is set to 0             */
1671911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* For AMP controller, max_packet_length is set by available blocks */
1672911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if ((max_packet_length > L2CAP_MAX_HEADER_FCS) &&
1673911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      (max_pdu + L2CAP_MAX_HEADER_FCS > max_packet_length)) {
1674911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    max_pdu = max_packet_length - L2CAP_MAX_HEADER_FCS;
1675911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1676911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1677911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
1678911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1679911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If there is more data than the MPS, it requires segmentation */
1680911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_buf->len > max_pdu) {
1681911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* We are using the "event" field to tell is if we already started
1682911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * segmentation */
1683911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_buf->event == 0) {
1684911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      first_seg = true;
1685911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      sdu_len = p_buf->len;
1686911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else
1687911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      mid_seg = true;
16885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1689911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Get a new buffer and copy the data that can be sent in a PDU */
1690911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET,
1691911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                               max_pdu);
16925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1693911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_xmit != NULL) {
1694911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf->event = p_ccb->local_cid;
1695911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_xmit->event = p_ccb->local_cid;
16965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1697911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf->len -= max_pdu;
1698911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf->offset += max_pdu;
16995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1700911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* copy PBF setting */
1701911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_xmit->layer_specific = p_buf->layer_specific;
1702911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else /* Should never happen if the application has configured buffers
1703911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              correctly */
17045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1705911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_ERROR(
1706911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "L2CAP - cannot get buffer for segmentation, max_pdu: %u", max_pdu);
1707911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return (NULL);
1708911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1709911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else /* Use the original buffer if no segmentation, or the last segment */
1710911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  {
1711911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
17125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1713911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_xmit->event != 0) last_seg = true;
17145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1715911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->event = p_ccb->local_cid;
1716911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
17175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1718911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Step back to add the L2CAP headers */
1719911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_xmit->offset -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD);
1720911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_xmit->len += L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
17215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1722911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (first_seg) {
1723911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->offset -= L2CAP_SDU_LEN_OVERHEAD;
1724911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->len += L2CAP_SDU_LEN_OVERHEAD;
1725911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
17265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1727911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Set the pointer to the beginning of the data */
1728911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
17295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1730911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Now the L2CAP header */
17315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1732911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Note: if FCS has to be included then the length is recalculated later */
1733911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, p_xmit->len - L2CAP_PKT_OVERHEAD);
17345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1735911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, p_ccb->remote_cid);
17365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1737911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (first_seg) {
1738911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Skip control word and add SDU length */
1739911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p += 2;
1740911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    UINT16_TO_STREAM(p, sdu_len);
17415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1742911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* We will store the SAR type in layer-specific */
1743911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* layer_specific is shared with flushable flag(bits 0-1), don't clear it */
1744911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->layer_specific |= L2CAP_FCR_START_SDU;
17455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1746911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    first_seg = false;
1747911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else if (mid_seg)
1748911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->layer_specific |= L2CAP_FCR_CONT_SDU;
1749911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  else if (last_seg)
1750911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->layer_specific |= L2CAP_FCR_END_SDU;
1751911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  else
1752911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->layer_specific |= L2CAP_FCR_UNSEG_SDU;
17535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1754911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  prepare_I_frame(p_ccb, p_xmit, false);
17555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1756911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
1757911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_HDR* p_wack =
1758911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len);
17595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1760911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!p_wack) {
1761911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_ERROR(
1762911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "L2CAP - no buffer for xmit cloning, CID: 0x%04x  Length: %u",
1763911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->local_cid, p_xmit->len);
17645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1765911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* We will not save the FCS in case we reconfigure and change options */
1766911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) p_xmit->len -= L2CAP_FCS_LEN;
17675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1768911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Pretend we sent it and it got lost */
1769911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit);
1770911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return (NULL);
1771911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else {
17725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
1773911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* set timestamp at the end of tx I-frame to get acking delay */
1774911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /*
1775911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       * NOTE: Here we assume the allocate buffer is large enough
1776911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       * to include extra 4 octets at the end.
1777911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       */
1778911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p = ((uint8_t*)(p_wack + 1)) + p_wack->offset + p_wack->len;
1779911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      UINT32_TO_STREAM(p, time_get_os_boottime_ms());
17805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
1781911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* We will not save the FCS in case we reconfigure and change options */
1782911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) p_wack->len -= L2CAP_FCS_LEN;
17835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1784911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_wack->layer_specific = p_xmit->layer_specific;
1785911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack);
1786911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
17875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
1789911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ertm_pkt_counts[0]++;
1790911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ertm_byte_counts[0] += (p_xmit->len - 8);
17915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
1792911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
17935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1794911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (p_xmit);
17955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
17965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17976721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar/*******************************************************************************
1798ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1799ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_lcc_get_next_xmit_sdu_seg
1800ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
18019ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Description      Get the next SDU segment to transmit for LE connection
18029ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  oriented channel
1803ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1804ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          pointer to buffer with segment or NULL
1805ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1806ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1807911d1ae03efec2d54c3b1b605589d790d1745488Myles WatsonBT_HDR* l2c_lcc_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
1808911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                      uint16_t max_packet_length) {
1809911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool first_seg = false; /* The segment is the first part of data  */
1810911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool last_seg = false;  /* The segment is the last part of data  */
1811911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t no_of_bytes_to_send = 0;
1812911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t sdu_len = 0;
1813911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR *p_buf, *p_xmit;
1814911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
1815911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t max_pdu = p_ccb->peer_conn_cfg.mps;
1816911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1817911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
1818911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1819911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* We are using the "event" field to tell is if we already started
1820911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * segmentation */
1821911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_buf->event == 0) {
1822911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    first_seg = true;
1823911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    sdu_len = p_buf->len;
1824911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_buf->len <= (max_pdu - L2CAP_LCC_SDU_LENGTH)) {
1825911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      last_seg = true;
1826911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      no_of_bytes_to_send = p_buf->len;
1827911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else
1828911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      no_of_bytes_to_send = max_pdu - L2CAP_LCC_SDU_LENGTH;
1829911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else if (p_buf->len <= max_pdu) {
1830911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    last_seg = true;
1831911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    no_of_bytes_to_send = p_buf->len;
1832911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else {
1833911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Middle Packet */
1834911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    no_of_bytes_to_send = max_pdu;
1835911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1836911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1837911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Get a new buffer and copy the data that can be sent in a PDU */
1838911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (first_seg == true)
1839911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_LCC_OFFSET, no_of_bytes_to_send);
1840911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  else
1841911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET, no_of_bytes_to_send);
1842911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1843911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_xmit != NULL) {
1844911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->event = p_ccb->local_cid;
1845911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->event = p_ccb->local_cid;
1846911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1847911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (first_seg == true) {
1848911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_xmit->offset -= L2CAP_LCC_SDU_LENGTH; /* for writing the SDU length. */
1849911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
1850911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      UINT16_TO_STREAM(p, sdu_len);
1851911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_xmit->len += L2CAP_LCC_SDU_LENGTH;
1852911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1853911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1854911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->len -= no_of_bytes_to_send;
1855911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf->offset += no_of_bytes_to_send;
1856911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1857911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* copy PBF setting */
1858911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_xmit->layer_specific = p_buf->layer_specific;
1859911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1860911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else /* Should never happen if the application has configured buffers
1861911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            correctly */
1862911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  {
1863911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_ERROR("L2CAP - cannot get buffer, for segmentation");
1864911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return (NULL);
1865911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1866911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1867911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (last_seg == true) {
1868911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
1869911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    osi_free(p_buf);
1870911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
18716721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
1872911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Step back to add the L2CAP headers */
1873911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_xmit->offset -= L2CAP_PKT_OVERHEAD;
1874911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_xmit->len += L2CAP_PKT_OVERHEAD;
18756721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
1876911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Set the pointer to the beginning of the data */
1877911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
18786721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
1879911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Note: if FCS has to be included then the length is recalculated later */
1880911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, p_xmit->len - L2CAP_PKT_OVERHEAD);
1881911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  UINT16_TO_STREAM(p, p_ccb->remote_cid);
1882911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (p_xmit);
18836721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar}
18845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1886ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Configuration negotiation functions
1887ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1888ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * The following functions are used in negotiating channel modes during
1889ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * configuration
1890ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
18915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1893ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1894ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_chk_chan_modes
1895ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1896ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Validates and adjusts if necessary, the FCR options
1897ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  based on remote EXT features.
1898ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1899ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  Note: This assumes peer EXT Features have been received.
1900ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                      Basic mode is used if FCR Options have not been received
1901ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
19029ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Returns          uint8_t - nonzero if can continue, '0' if no compatible
19039ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                            channels
1904ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1905ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1906911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonuint8_t l2c_fcr_chk_chan_modes(tL2C_CCB* p_ccb) {
1907f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1908ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
1909911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Remove nonbasic options that the peer does not support */
1910911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS))
1911911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_ERTM;
19125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1913911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_STREAM_MODE))
1914911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_STREAM;
19155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1916911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* At least one type needs to be set (Basic, ERTM, STM) to continue */
1917911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!p_ccb->ertm_info.allowed_modes) {
1918911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING(
1919911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "L2CAP - Peer does not support our desired channel types");
1920911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
19215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1922911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (p_ccb->ertm_info.allowed_modes);
19235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
19245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1926ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1927ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_adj_our_req_options
1928ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1929ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Validates and sets up the FCR options passed in from
1930ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  L2CA_ConfigReq based on remote device's features.
1931ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1932ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          true if no errors, Otherwise false
1933ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1934ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1935911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonbool l2c_fcr_adj_our_req_options(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
1936f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
1937f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_cfg != NULL);
1938911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1939911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  tL2CAP_FCR_OPTS* p_fcr = &p_cfg->fcr;
1940911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1941911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_fcr->mode != p_ccb->ertm_info.preferred_mode) {
1942911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING(
1943911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "l2c_fcr_adj_our_req_options - preferred_mode (%d), does not match "
1944911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "mode (%d)",
1945911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->ertm_info.preferred_mode, p_fcr->mode);
1946911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1947911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* The preferred mode is passed in through tL2CAP_ERTM_INFO, so override
1948911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * this one */
1949911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcr->mode = p_ccb->ertm_info.preferred_mode;
1950911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1951911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1952911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If upper layer did not request eRTM mode, BASIC must be used */
1953911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC) {
1954911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_cfg->fcr_present && p_fcr->mode != L2CAP_FCR_BASIC_MODE) {
1955911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_WARNING(
1956911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "l2c_fcr_adj_our_req_options (mode %d): ERROR: No FCR options set "
1957911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          "using BASIC mode",
1958911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_fcr->mode);
1959911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1960911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_fcr->mode = L2CAP_FCR_BASIC_MODE;
1961911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
1962911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1963911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Process the FCR options if initial channel bring-up (not a reconfig
1964911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  *request)
1965911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  ** Determine initial channel mode to try based on our options and remote's
1966911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  *features
1967911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  */
1968911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_cfg->fcr_present && !(p_ccb->config_done & RECONFIG_FLAG)) {
1969911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* We need to have at least one mode type common with the peer */
1970911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!l2c_fcr_chk_chan_modes(p_ccb)) {
1971911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Two channels have incompatible supported types */
1972911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      l2cu_disconnect_chnl(p_ccb);
1973911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      return (false);
1974911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1975911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1976911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Basic is the only common channel mode between the two devices */
1977911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC) {
1978911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* We only want to try Basic, so bypass sending the FCR options entirely
1979911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       */
1980911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr_present = false;
1981911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcs_present = false; /* Illegal to use FCS option in basic mode */
1982911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->ext_flow_spec_present =
1983911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          false; /* Illegal to use extended flow spec in basic mode */
1984911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
1985911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1986911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* We have at least one non-basic mode available
1987911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * Override mode from available mode options based on preference, if needed
1988911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     */
1989911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else {
1990911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* If peer does not support STREAMING, try ERTM */
1991911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcr->mode == L2CAP_FCR_STREAM_MODE &&
1992911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_STREAM)) {
1993911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_DEBUG(
1994911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "L2C CFG: mode is STREAM, but peer does not support; Try ERTM");
1995911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcr->mode = L2CAP_FCR_ERTM_MODE;
1996911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
1997911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1998911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* If peer does not support ERTM, try BASIC (will support this if made it
1999911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       * here in the code) */
2000911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcr->mode == L2CAP_FCR_ERTM_MODE &&
2001911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
2002911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_DEBUG(
2003911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            "L2C CFG: mode is ERTM, but peer does not support; Try BASIC");
20045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_fcr->mode = L2CAP_FCR_BASIC_MODE;
2005911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
20065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
20075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2008911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_fcr->mode != L2CAP_FCR_BASIC_MODE) {
2009911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* MTU must be smaller than buffer size */
2010911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((p_cfg->mtu_present) && (p_cfg->mtu > p_ccb->max_rx_mtu)) {
2011911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_WARNING("L2CAP - MTU: %u  larger than buf size: %u",
2012911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            p_cfg->mtu, p_ccb->max_rx_mtu);
2013911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        return (false);
2014911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2015911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2016911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* application want to use the default MPS */
2017911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcr->mps == L2CAP_DEFAULT_ERM_MPS) {
2018911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcr->mps = L2CAP_MPS_OVER_BR_EDR;
2019911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2020911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* MPS must be less than MTU */
2021911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      else if (p_fcr->mps > p_ccb->max_rx_mtu) {
2022911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_WARNING("L2CAP - MPS  %u  invalid  MTU: %u", p_fcr->mps,
2023911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            p_ccb->max_rx_mtu);
2024911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        return (false);
2025911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
20265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2027911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* We always initially read into the HCI buffer pool, so make sure it fits
2028911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       */
2029911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_fcr->mps > (L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS))
2030911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_fcr->mps = L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS;
2031911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else {
2032911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcs_present = false; /* Illegal to use FCS option in basic mode */
2033911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->ext_flow_spec_present =
2034911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          false; /* Illegal to use extended flow spec in basic mode */
20355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
20365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2037911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->our_cfg.fcr = *p_fcr;
2038911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else /* Not sure how to send a reconfiguration(??) should fcr be included?
2039911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            */
2040911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  {
2041911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->our_cfg.fcr_present = false;
2042911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
20435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2044911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (true);
2045911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson}
20465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2048ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2049ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_adj_monitor_retran_timeout
2050ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2051ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Overrides monitor/retrans timer value based on controller
2052ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2053ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          None
2054ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2055ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2056911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_adj_monitor_retran_timeout(tL2C_CCB* p_ccb) {
2057f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
20585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2059911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* adjust our monitor/retran timeout */
2060911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->out_cfg_fcr_present) {
2061911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /*
2062911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ** if we requestd ERTM or accepted ERTM
2063911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ** We may accept ERTM even if we didn't request ERTM, in case of requesting
2064911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    *STREAM
2065911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    */
2066911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) ||
2067911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)) {
2068911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* upper layer setting is ignored */
2069911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->our_cfg.fcr.mon_tout = L2CAP_MIN_MONITOR_TOUT;
2070911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->our_cfg.fcr.rtrans_tout = L2CAP_MIN_RETRANS_TOUT;
2071911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    } else {
2072911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->our_cfg.fcr.mon_tout = 0;
2073911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->our_cfg.fcr.rtrans_tout = 0;
20745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
2075911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2076911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_DEBUG(
2077911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d",
2078911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout);
2079911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
20805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
20815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2082ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2083ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_adj_our_rsp_options
2084ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2085ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Overrides any neccesary FCR options passed in from
2086ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  L2CA_ConfigRsp based on our FCR options.
2087ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  Only makes adjustments if channel is in ERTM mode.
2088ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2089ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          None
2090ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2091ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2092911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonvoid l2c_fcr_adj_our_rsp_options(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
2093f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
2094f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_cfg != NULL);
2095911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2096911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* adjust our monitor/retran timeout */
2097911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  l2c_fcr_adj_monitor_retran_timeout(p_ccb);
2098911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2099911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_cfg->fcr_present = p_ccb->out_cfg_fcr_present;
2100911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2101911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_cfg->fcr_present) {
2102911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Temporary - until a better algorithm is implemented */
2103911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If peer's tx_wnd_sz requires too many buffers for us to support, then
2104911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * adjust it. For now, respond with our own tx_wnd_sz. */
2105911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Note: peer is not guaranteed to obey our adjustment */
2106911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz) {
2107911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      L2CAP_TRACE_DEBUG("%s: adjusting requested tx_win_sz from %i to %i",
2108911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        __func__, p_ccb->peer_cfg.fcr.tx_win_sz,
2109911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        p_ccb->our_cfg.fcr.tx_win_sz);
2110911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
2111911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
2112911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2113911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_cfg->fcr.mode = p_ccb->peer_cfg.fcr.mode;
2114911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_cfg->fcr.tx_win_sz = p_ccb->peer_cfg.fcr.tx_win_sz;
2115911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_cfg->fcr.max_transmit = p_ccb->peer_cfg.fcr.max_transmit;
2116911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_cfg->fcr.mps = p_ccb->peer_cfg.fcr.mps;
2117911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_cfg->fcr.rtrans_tout = p_ccb->our_cfg.fcr.rtrans_tout;
2118911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_cfg->fcr.mon_tout = p_ccb->our_cfg.fcr.mon_tout;
2119911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
21205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
21215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2123ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2124ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_renegotiate_chan
2125ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2126ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Called upon unsuccessful peer response to config request.
2127ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  If the error is because of the channel mode, it will try
2128ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  to resend using another supported optional channel.
2129ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2130ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          true if resent configuration, False if channel matches or
2131ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  cannot match.
2132ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2133ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2134911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonbool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
2135f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
2136f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_cfg != NULL);
2137ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
2138911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t peer_mode = p_ccb->our_cfg.fcr.mode;
2139911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bool can_renegotiate;
21405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2141911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Skip if this is a reconfiguration from OPEN STATE or if FCR is not returned
2142911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   */
2143911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!p_cfg->fcr_present || (p_ccb->config_done & RECONFIG_FLAG))
2144911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    return (false);
21455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2146911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Only retry if there are more channel options to try */
2147911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS) {
2148911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    peer_mode = (p_cfg->fcr_present) ? p_cfg->fcr.mode : L2CAP_FCR_BASIC_MODE;
2149911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2150911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_ccb->our_cfg.fcr.mode != peer_mode) {
2151911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((--p_ccb->fcr_cfg_tries) == 0) {
2152911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
2153911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_WARNING("l2c_fcr_renegotiate_chan (Max retries exceeded)");
2154911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2155911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2156911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      can_renegotiate = false;
2157911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2158911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Try another supported mode if available based on our last attempted
2159911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       * channel */
2160911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      switch (p_ccb->our_cfg.fcr.mode) {
2161911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* Our Streaming mode request was unnacceptable; try ERTM or Basic */
2162911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        case L2CAP_FCR_STREAM_MODE:
2163911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          /* Peer wants ERTM and we support it */
2164911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          if ((peer_mode == L2CAP_FCR_ERTM_MODE) &&
2165911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
2166911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying ERTM)");
2167911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
2168911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            can_renegotiate = true;
2169911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          } else /* Falls through */
2170911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2171911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          case L2CAP_FCR_ERTM_MODE: {
2172911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            /* We can try basic for any other peer mode if we support it */
2173911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) {
2174911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying Basic)");
2175911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              can_renegotiate = true;
2176911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson              p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
2177911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            }
2178911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          } break;
21795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2180911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          default:
2181911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            /* All other scenarios cannot be renegotiated */
2182911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            break;
2183911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
21845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2185911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (can_renegotiate) {
2186911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->our_cfg.fcr_present = true;
21875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2188911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (p_ccb->our_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) {
2189911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->our_cfg.fcs_present = false;
2190911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->our_cfg.ext_flow_spec_present = false;
21915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2192911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          /* Basic Mode uses ACL Data Pool, make sure the MTU fits */
2193911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          if ((p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE)) {
2194911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            L2CAP_TRACE_WARNING("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
2195911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            p_cfg->mtu = L2CAP_MTU_SIZE;
2196911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          }
21975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
21985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2199911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2cu_process_our_cfg_req(p_ccb, &p_ccb->our_cfg);
2200911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        l2cu_send_peer_config_req(p_ccb, &p_ccb->our_cfg);
2201911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
2202911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           l2c_ccb_timer_timeout, p_ccb,
2203911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                           btu_general_alarm_queue);
2204911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        return (true);
2205911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
22065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
2207911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
22085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2209911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Disconnect if the channels do not match */
2210911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->our_cfg.fcr.mode != peer_mode) {
2211911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    L2CAP_TRACE_WARNING("L2C CFG:  Channels incompatible (local %d, peer %d)",
2212911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                        p_ccb->our_cfg.fcr.mode, peer_mode);
2213911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    l2cu_disconnect_chnl(p_ccb);
2214911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
22155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2216911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (false);
2217911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson}
22185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2220ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2221ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_process_peer_cfg_req
2222ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2223ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function is called to process the FCR options passed
2224ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  in the peer's configuration request.
2225ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2226ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          uint8_t - L2CAP_PEER_CFG_OK, L2CAP_PEER_CFG_UNACCEPTABLE,
2227ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                          or L2CAP_PEER_CFG_DISCONNECT.
2228ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2229ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2230911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonuint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
2231f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_ccb != NULL);
2232f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p_cfg != NULL);
2233911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2234911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint16_t max_retrans_size;
2235911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t fcr_ok = L2CAP_PEER_CFG_OK;
2236911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2237911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->p_lcb->w4_info_rsp =
2238911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      false; /* Handles T61x SonyEricsson Bug in Info Request */
2239911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2240911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  L2CAP_TRACE_EVENT(
2241911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR "
2242911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      "mode:%d preferred: %u allowed:%u",
2243911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode,
2244911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->ertm_info.preferred_mode, p_ccb->ertm_info.allowed_modes);
2245911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2246911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* If Peer wants basic, we are done (accept it or disconnect) */
2247911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE) {
2248911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If we do not allow basic, disconnect */
2249911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (!(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC))
2250911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
2251911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
2252911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2253911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Need to negotiate if our modes are not the same */
2254911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  else if (p_cfg->fcr.mode != p_ccb->ertm_info.preferred_mode) {
2255911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If peer wants a mode that we don't support then retry our mode (ex.
2256911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    *rtx/flc), OR
2257911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ** If we want ERTM and they wanted streaming retry our mode.
2258911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ** Note: If we have already determined they support our mode previously
2259911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    **       from their EXF mask.
2260911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    */
2261911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if ((((1 << p_cfg->fcr.mode) & L2CAP_FCR_CHAN_OPT_ALL_MASK) == 0) ||
2262911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE)) {
2263911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr.mode = p_ccb->our_cfg.fcr.mode;
2264911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
2265911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr.max_transmit = p_ccb->our_cfg.fcr.max_transmit;
2266911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
2267911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
2268911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2269911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* If we wanted basic, then try to renegotiate it */
2270911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else if (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_BASIC_MODE) {
2271911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
2272911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
2273911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_cfg->fcr.rtrans_tout = p_cfg->fcr.mon_tout = p_cfg->fcr.mps = 0;
2274911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->our_cfg.fcr.rtrans_tout = p_ccb->our_cfg.fcr.mon_tout =
2275911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->our_cfg.fcr.mps = 0;
2276911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
2277911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
2278911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2279911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Only other valid case is if they want ERTM and we wanted STM which should
2280911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       be
2281911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       accepted if we support it; otherwise the channel should be disconnected
2282911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       */
2283911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else if ((p_cfg->fcr.mode != L2CAP_FCR_ERTM_MODE) ||
2284911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
2285911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
2286911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
2287911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
2288911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2289911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* Configuration for FCR channels so make any adjustments and fwd to upper
2290911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson   * layer */
2291911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (fcr_ok == L2CAP_PEER_CFG_OK) {
2292911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* by default don't need to send params in the response */
2293911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->out_cfg_fcr_present = false;
2294911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2295911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Make any needed adjustments for the response to the peer */
2296911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_cfg->fcr_present && p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) {
2297911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Peer desires to bypass FCS check, and streaming or ERTM mode */
2298911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_cfg->fcs_present) {
2299911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->peer_cfg.fcs = p_cfg->fcs;
2300911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
2301911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
2302911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->bypass_fcs |= L2CAP_CFG_FCS_PEER;
2303911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2304911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2305911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      max_retrans_size = p_ccb->ertm_info.fcr_tx_buf_size - sizeof(BT_HDR) -
2306911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                         L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET -
2307911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                         L2CAP_FCS_LEN;
2308911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2309911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Ensure the MPS is not bigger than the MTU */
2310911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if ((p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu)) {
2311911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_cfg->fcr.mps = p_ccb->peer_cfg.mtu;
2312911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->out_cfg_fcr_present = true;
2313911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2314911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2315911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* Ensure the MPS is not bigger than our retransmission buffer */
2316911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_cfg->fcr.mps > max_retrans_size) {
2317911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        L2CAP_TRACE_DEBUG("CFG: Overriding MPS to %d (orig %d)",
2318911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                          max_retrans_size, p_cfg->fcr.mps);
2319911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2320911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_cfg->fcr.mps = max_retrans_size;
2321911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->out_cfg_fcr_present = true;
2322911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2323911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2324911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE ||
2325911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE) {
2326911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* Always respond with FCR ERTM parameters */
2327911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->out_cfg_fcr_present = true;
2328911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2329911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
2330911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2331911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Everything ok, so save the peer's adjusted fcr options */
2332911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->peer_cfg.fcr = p_cfg->fcr;
2333911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2334911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_cfg->fcr_present) p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
2335911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  } else if (fcr_ok == L2CAP_PEER_CFG_UNACCEPTABLE) {
2336911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* Allow peer only one retry for mode */
2337911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (p_ccb->peer_cfg_already_rejected)
2338911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
2339911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    else
2340911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->peer_cfg_already_rejected = true;
2341911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
23425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2343911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  return (fcr_ok);
23445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
23455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
23475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2348ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2349ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_collect_ack_delay
2350ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2351ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      collect throughput, delay, queue size of waiting ack
2352ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2353ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Parameters
2354ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  tL2C_CCB
2355ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2356ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          void
2357ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2358ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2359911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonstatic void l2c_fcr_collect_ack_delay(tL2C_CCB* p_ccb, uint8_t num_bufs_acked) {
2360911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint32_t index;
2361911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  BT_HDR* p_buf;
2362911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t* p;
2363911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint32_t timestamp, delay;
2364911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t xx;
2365911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  uint8_t str[120];
2366911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2367911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  index = p_ccb->fcrb.ack_delay_avg_index;
2368911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2369911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* update sum, max and min of waiting for ack queue size */
2370911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.ack_q_count_avg[index] +=
2371911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
2372911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2373911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >
2374911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.ack_q_count_max[index])
2375911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_q_count_max[index] =
23761a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
23775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2378911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) <
2379911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.ack_q_count_min[index])
2380911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_q_count_min[index] =
2381911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
2382911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2383911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* update sum, max and min of round trip delay of acking */
2384911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  list_t* list = NULL;
2385911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
2386911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    list = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
2387911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (list != NULL) {
2388911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    for (const list_node_t *node = list_begin(list), xx = 0;
2389911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         (node != list_end(list)) && (xx < num_bufs_acked);
2390911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson         node = list_next(node), xx++) {
2391911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_buf = list_node(node);
2392911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      /* adding up length of acked I-frames to get throughput */
2393911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.throughput[index] += p_buf->len - 8;
2394911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2395911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      if (xx == num_bufs_acked - 1) {
2396911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        /* get timestamp from tx I-frame that receiver is acking */
2397911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len;
2398911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
2399911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p += L2CAP_FCS_LEN;
24005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
24015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2402911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        STREAM_TO_UINT32(timestamp, p);
2403911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        delay = time_get_os_boottime_ms() - timestamp;
24045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2405911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.ack_delay_avg[index] += delay;
2406911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (delay > p_ccb->fcrb.ack_delay_max[index])
2407911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->fcrb.ack_delay_max[index] = delay;
2408911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (delay < p_ccb->fcrb.ack_delay_min[index])
2409911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          p_ccb->fcrb.ack_delay_min[index] = delay;
2410911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      }
2411911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
2412911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
24135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2414911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  p_ccb->fcrb.ack_delay_avg_count++;
24155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2416911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  /* calculate average and initialize next avg, min and max */
2417911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (p_ccb->fcrb.ack_delay_avg_count > L2CAP_ERTM_STATS_AVG_NUM_SAMPLES) {
2418911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_delay_avg_count = 0;
24195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2420911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_q_count_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
2421911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
24225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2423911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /* calculate throughput */
2424911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    timestamp = time_get_os_boottime_ms();
2425911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    if (timestamp - p_ccb->fcrb.throughput_start > 0)
2426911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      p_ccb->fcrb.throughput[index] /=
2427911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          (timestamp - p_ccb->fcrb.throughput_start);
24285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2429911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.throughput_start = timestamp;
24305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2431911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    snprintf(
2432911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        str, sizeof(str),
2433911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, "
2434911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        "ack_q_count avg:%3u, min:%3u, max:%3u",
2435911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        index, p_ccb->fcrb.throughput[index], p_ccb->fcrb.ack_delay_avg[index],
2436911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.ack_delay_min[index], p_ccb->fcrb.ack_delay_max[index],
2437911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.ack_q_count_avg[index], p_ccb->fcrb.ack_q_count_min[index],
2438911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        p_ccb->fcrb.ack_q_count_max[index]);
24395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2440911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
2441911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson             TRACE_TYPE_GENERIC, "%s", str);
24425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2443911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    index = (index + 1) % L2CAP_ERTM_STATS_NUM_AVG;
2444911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_delay_avg_index = index;
24455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2446911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_q_count_max[index] = 0;
2447911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_q_count_min[index] = 0xFFFFFFFF;
2448911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_q_count_avg[index] = 0;
24495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2450911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_delay_max[index] = 0;
2451911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_delay_min[index] = 0xFFFFFFFF;
2452911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.ack_delay_avg[index] = 0;
2453911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
2454911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    p_ccb->fcrb.throughput[index] = 0;
2455911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  }
24565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
24575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
2458