l2c_fcr.cc revision 9ca07091a1f07ea201cee0504dab6a1d7073d429
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
26ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include <assert.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
315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "bt_types.h"
32258c2538e3b62a8cdb403f2730c45d721e5292b4Pavlin Radoslavov#include "bt_common.h"
335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "hcimsgs.h"
345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "l2c_api.h"
35ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include "l2c_int.h"
36ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include "l2cdefs.h"
375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "btm_api.h"
385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#include "btm_int.h"
39ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton#include "btu.h"
405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov
4278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovextern fixed_queue_t *btu_general_alarm_queue;
4378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov
449ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson/* Flag passed to retransmit_i_frames() when all packets should be retransmitted
459ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson */
465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#define L2C_FCR_RETX_ALL_PKTS   0xFF
475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
482e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov/* this is the minimal offset required by OBX to process incoming packets */
492e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavovstatic const uint16_t OBX_BUF_MIN_OFFSET = 4;
502e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov
51a1e7e5561026e32c5f4d51bf6102fd275061b80fMarie Janssenstatic const char *SAR_types[] = { "Unsegmented", "Start", "End", "Continuation" };
52a1e7e5561026e32c5f4d51bf6102fd275061b80fMarie Janssenstatic 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] = {
565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project};
895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
92ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *  Static local functions
935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project*/
94d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic bool    process_reqseq (tL2C_CCB *p_ccb, uint16_t ctrl_word);
95d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void    process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word);
96d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void    process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word, bool    delay_ack);
97d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic bool    retransmit_i_frames (tL2C_CCB *p_ccb, uint8_t tx_seq);
98d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void    prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, bool    is_retransmission);
995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectstatic void    process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf);
100d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic bool    do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word);
1015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
103d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, uint8_t num_bufs_acked);
1045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
1055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
107ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
108ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_updcrc
109ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
110ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function computes the CRC using the look-up table.
111ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
112ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          CRC
113ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
114ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
115ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Mantonstatic unsigned short l2c_fcr_updcrc(unsigned short icrc, unsigned char *icp, int icnt)
1165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
117b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov    unsigned short crc = icrc;
118b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov    unsigned char *cp = icp;
119b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov    int cnt = icnt;
1205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    while (cnt--)
1225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        crc = ((crc >> 8) & 0xff) ^ crctab[(crc & 0xff) ^ *cp++];
1245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return(crc);
1275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
131ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
132ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_tx_get_fcs
133ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
134ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function computes the CRC for a frame to be TXed.
135ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
136ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          CRC
137ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
138ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
139d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic uint16_t l2c_fcr_tx_get_fcs (BT_HDR *p_buf)
1405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
141d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t *p = ((uint8_t *) (p_buf + 1)) + p_buf->offset;
1425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len));
1445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
147ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
148ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_rx_get_fcs
149ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
150ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function computes the CRC for a received frame.
151ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
152ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          CRC
153ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
154ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
155d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic uint16_t l2c_fcr_rx_get_fcs (BT_HDR *p_buf)
1565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
157d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t *p = ((uint8_t *) (p_buf + 1)) + p_buf->offset;
1585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* offset points past the L2CAP header, but the CRC check includes it */
1605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p -= L2CAP_PKT_OVERHEAD;
1615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len + L2CAP_PKT_OVERHEAD));
1635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
166ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
167ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_start_timer
168ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
169ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function starts the (monitor or retransmission) timer.
170ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
171ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
172ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
173ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_start_timer (tL2C_CCB *p_ccb)
1755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
176ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
177d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint32_t tout;
1785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* The timers which are in milliseconds */
1805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->fcrb.wait_ack)
1815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
182d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        tout = (uint32_t)p_ccb->our_cfg.fcr.mon_tout;
1835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
1845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
1855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
186d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        tout = (uint32_t)p_ccb->our_cfg.fcr.rtrans_tout;
1875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
188ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
1895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Only start a timer that was not started */
19078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    if (!alarm_is_scheduled(p_ccb->fcrb.mon_retrans_timer)) {
19178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov        alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, tout,
19278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                           l2c_ccb_timer_timeout, p_ccb,
19378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                           btu_general_alarm_queue);
19478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    }
1955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
1965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
198ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
199ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_stop_timer
200ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
201ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function stops the (monitor or transmission) timer.
202ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
203ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
204ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
205ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_stop_timer (tL2C_CCB *p_ccb)
2075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
208ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
20978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    alarm_cancel(p_ccb->fcrb.mon_retrans_timer);
2105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
2115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
213ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
214ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_cleanup
215ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2169ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Description      This function cleans up the variable used for
2179ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  flow-control/retrans.
218ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
219ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
220ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
221ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_cleanup (tL2C_CCB *p_ccb)
2235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
224ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
2255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
2265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    alarm_free(p_fcrb->mon_retrans_timer);
22878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    p_fcrb->mon_retrans_timer = NULL;
22978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    alarm_free(p_fcrb->ack_timer);
23078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov    p_fcrb->ack_timer = NULL;
2315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
232cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov    osi_free_and_reset((void **)&p_fcrb->p_rx_sdu);
2335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
234072bd753e6ac2a011421cd7e4a2e622ee7d052fcAndre Eisenbach    fixed_queue_free(p_fcrb->waiting_for_ack_q, osi_free);
2351a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    p_fcrb->waiting_for_ack_q = NULL;
2365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
237072bd753e6ac2a011421cd7e4a2e622ee7d052fcAndre Eisenbach    fixed_queue_free(p_fcrb->srej_rcv_hold_q, osi_free);
2381a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    p_fcrb->srej_rcv_hold_q = NULL;
2395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
240072bd753e6ac2a011421cd7e4a2e622ee7d052fcAndre Eisenbach    fixed_queue_free(p_fcrb->retrans_q, osi_free);
2411a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    p_fcrb->retrans_q = NULL;
2425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
2445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID) && (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) )
2455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
246d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        uint32_t dur = time_get_os_boottime_ms() - p_ccb->fcrb.connect_tick_count;
24780d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV        size_t p_str_size = 120;
24880d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV        char    *p_str = (char *)osi_malloc(p_str_size);
249d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        uint16_t i;
250d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        uint32_t throughput_avg, ack_delay_avg, ack_q_count_avg;
2515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2520212487880be33e255d49f6e38dbb035d1f77750Sharvil Nanavati        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
2535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                   "---  L2CAP ERTM  Stats for CID: 0x%04x   Duration: %08ums", p_ccb->local_cid, dur);
2540212487880be33e255d49f6e38dbb035d1f77750Sharvil Nanavati        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
2555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                   "Retransmissions:%08u Times Flow Controlled:%08u Retrans Touts:%08u Ack Touts:%08u",
2565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_ccb->fcrb.pkts_retransmitted, p_ccb->fcrb.xmit_window_closed, p_ccb->fcrb.retrans_touts, p_ccb->fcrb.xmit_ack_touts);
2570212487880be33e255d49f6e38dbb035d1f77750Sharvil Nanavati        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
2585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                   "Times there is less than 2 packets in controller when flow controlled:%08u", p_ccb->fcrb.controller_idle);
2590212487880be33e255d49f6e38dbb035d1f77750Sharvil Nanavati        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
2605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                   "max_held_acks:%08u, in_cfg.fcr.tx_win_sz:%08u", p_ccb->fcrb.max_held_acks, p_ccb->peer_cfg.fcr.tx_win_sz );
261717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov
26280d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV        snprintf(p_str, p_str_size, "Sent Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u",
2635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.ertm_pkt_counts[0], p_ccb->fcrb.ertm_byte_counts[0],
2645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[0] * 100) / (dur / 10) : 0),
2655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.s_frames_sent[0], p_ccb->fcrb.s_frames_sent[1], p_ccb->fcrb.s_frames_sent[2], p_ccb->fcrb.s_frames_sent[3]);
2665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
267717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
2685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
26980d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV        snprintf(p_str, p_str_size, "Rcvd Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u",
2705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.ertm_pkt_counts[1], p_ccb->fcrb.ertm_byte_counts[1],
2715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[1] * 100) / (dur / 10) : 0),
2725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.s_frames_rcvd[0], p_ccb->fcrb.s_frames_rcvd[1], p_ccb->fcrb.s_frames_rcvd[2], p_ccb->fcrb.s_frames_rcvd[3]);
2735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
274717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
2755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
276717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        throughput_avg = 0;
277717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        ack_delay_avg = 0;
278717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        ack_q_count_avg = 0;
2795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
280717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        for (i = 0; i < L2CAP_ERTM_STATS_NUM_AVG; i++) {
281717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            if (i == p_ccb->fcrb.ack_delay_avg_index) {
282717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
283717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                         "[%02u] collecting data ...", i );
284717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                continue;
285717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            }
2865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
28780d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV            snprintf(p_str, p_str_size, "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u",
288717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                    i, p_ccb->fcrb.throughput[i],
289717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                    p_ccb->fcrb.ack_delay_avg[i], p_ccb->fcrb.ack_delay_min[i], p_ccb->fcrb.ack_delay_max[i],
290717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                    p_ccb->fcrb.ack_q_count_avg[i], p_ccb->fcrb.ack_q_count_min[i], p_ccb->fcrb.ack_q_count_max[i] );
2915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
292717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
2935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
294717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            throughput_avg  += p_ccb->fcrb.throughput[i];
295717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            ack_delay_avg   += p_ccb->fcrb.ack_delay_avg[i];
296717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            ack_q_count_avg += p_ccb->fcrb.ack_q_count_avg[i];
297717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        }
2985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
299717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        throughput_avg  /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
300717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        ack_delay_avg   /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
301717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        ack_q_count_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
3025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
303717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
304717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                 "throughput_avg: %8u (kbytes/sec), ack_delay_avg: %8u ms, ack_q_count_avg: %8u",
305717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                 throughput_avg, ack_delay_avg, ack_q_count_avg );
3065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
307717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        osi_free(p_str);
3085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3090212487880be33e255d49f6e38dbb035d1f77750Sharvil Nanavati        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
3105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                   "---");
3115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
3125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
3135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    memset (p_fcrb, 0, sizeof (tL2C_FCRB));
3155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
3165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
318ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
319ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_clone_buf
320ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
3219ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Description      This function allocates and copies requested part of a
3229ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  buffer at a new-offset.
323ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
324ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          pointer to new buffer
325ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
326ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
327d19e0785e662e640191a075eda07acce61c2aedaMarie JanssenBT_HDR *l2c_fcr_clone_buf(BT_HDR *p_buf, uint16_t new_offset, uint16_t no_of_bytes)
3285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
329ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
330871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov    /*
331871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov     * NOTE: We allocate extra L2CAP_FCS_LEN octets, in case we need to put
332871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov     * the FCS (Frame Check Sequence) at the end of the buffer.
333871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov     */
334871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov    uint16_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
335871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov#if (L2CAP_ERTM_STATS == TRUE)
336871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov    /*
337871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov     * NOTE: If L2CAP_ERTM_STATS is enabled, we need 4 extra octets at the
338871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov     * end for a timestamp at the end of an I-frame.
339871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov     */
340871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov    buf_size += sizeof(uint32_t);
341871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov#endif
342cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov    BT_HDR *p_buf2 = (BT_HDR *)osi_malloc(buf_size);
3435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
344717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    p_buf2->offset = new_offset;
345717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    p_buf2->len = no_of_bytes;
346d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    memcpy(((uint8_t *)(p_buf2 + 1)) + p_buf2->offset,
347d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen           ((uint8_t *)(p_buf + 1))  + p_buf->offset,
348717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov           no_of_bytes);
3495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (p_buf2);
3515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
3525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
354ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
355ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_is_flow_controlled
356ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
357ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function checks if the CCB is flow controlled by peer.
358ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
359ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          The control word
360ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
361ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
362d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenbool    l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb)
3635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
364ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
3655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
3665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
3675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Check if remote side flowed us off or the transmit window is full */
368d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        if ( (p_ccb->fcrb.remote_busy == true)
3691a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov         ||  (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >= p_ccb->peer_cfg.fcr.tx_win_sz) )
3705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
3715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
3721a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
3735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
3745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.xmit_window_closed++;
3755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if ((p_ccb->p_lcb->sent_not_acked < 2)&&(l2cb.controller_xmit_window > 0))
3775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_ccb->fcrb.controller_idle++;
3785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
3795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
380d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            return (true);
3815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
3825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
383d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    return (false);
3845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
3855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
3865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
387ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
388ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         prepare_I_frame
389ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
390ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function sets the FCR variables in an I-frame that is
391ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  about to be sent to HCI for transmission. This may be the
392ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  first time the I-frame is sent, or a retransmission
393ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
394ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
395ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
396ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
397d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, bool    is_retransmission)
3985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
399ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
400ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
4015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
402d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
403d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    fcs;
404d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    ctrl_word;
405d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        set_f_bit = p_fcrb->send_f_rsp;
4065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
407d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p_fcrb->send_f_rsp = false;
4085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (is_retransmission)
4105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
4115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Get the old control word and clear out the old req_seq and F bits */
412d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p = ((uint8_t *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
4135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        STREAM_TO_UINT16 (ctrl_word, p);
4155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ctrl_word  &= ~(L2CAP_FCR_REQ_SEQ_BITS + L2CAP_FCR_F_BIT);
4175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
4185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
4195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
4205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ctrl_word  = p_buf->layer_specific & L2CAP_FCR_SEG_BITS;                /* SAR bits */
4215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ctrl_word |= (p_fcrb->next_tx_seq << L2CAP_FCR_TX_SEQ_BITS_SHIFT);      /* Tx Seq */
4225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_fcrb->next_tx_seq = (p_fcrb->next_tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
4245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
4255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Set the F-bit and reqseq only if using re-transmission mode */
4275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
4285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
4295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (set_f_bit)
4305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            ctrl_word |= L2CAP_FCR_F_BIT;
4315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ctrl_word |= (p_fcrb->next_seq_expected) << L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
4335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_fcrb->last_ack_sent = p_ccb->fcrb.next_seq_expected;
4355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
43678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov        alarm_cancel(p_ccb->fcrb.ack_timer);
4375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
4385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Set the control word */
440d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = ((uint8_t *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
4415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    UINT16_TO_STREAM (p, ctrl_word);
4435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Compute the FCS and add to the end of the buffer if not bypassed */
4455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
4465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
4475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* length field in l2cap header has to include FCS length */
448d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p = ((uint8_t *) (p_buf+1)) + p_buf->offset;
4495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        UINT16_TO_STREAM (p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD);
4505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Calculate the FCS */
4525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        fcs = l2c_fcr_tx_get_fcs(p_buf);
4535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Point to the end of the buffer and put the FCS there */
455871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov        /*
456871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov         * NOTE: Here we assume the allocated buffer is large enough
457871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov         * to include extra L2CAP_FCS_LEN octets at the end.
458871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov         */
459d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p = ((uint8_t *) (p_buf+1)) + p_buf->offset + p_buf->len;
4605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        UINT16_TO_STREAM (p, fcs);
4625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_buf->len += L2CAP_FCS_LEN;
4645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
4655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (is_retransmission)
4675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
468a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_EVENT ("L2CAP eRTM ReTx I-frame  CID: 0x%04x  Len: %u  SAR: %s  TxSeq: %u  ReqSeq: %u  F: %u",
4695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->local_cid, p_buf->len,
4705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
4715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
4725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
4735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
4745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
4755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
4765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
477a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_EVENT ("L2CAP eRTM Tx I-frame CID: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  ReqSeq: %u  F: %u",
4785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->local_cid, p_buf->len,
4795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
4805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
4815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
4825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
4835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
4845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Start the retransmission timer if not already running */
4865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
4875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_start_timer (p_ccb);
4885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
4895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
4905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
491ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
492ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_send_S_frame
493ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
494ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function formats and sends an S-frame for transmission.
495ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
496ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
497ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
498ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
499d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenvoid l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, uint16_t function_code, uint16_t pf_bit)
5005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
501ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
502d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
503d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    ctrl_word;
504d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    fcs;
5055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN))
5075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
5085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
5105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project     p_ccb->fcrb.s_frames_sent[function_code]++;
5115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
5125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (pf_bit == L2CAP_FCR_P_BIT)
5145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
515d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_ccb->fcrb.wait_ack = true;
5165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_stop_timer (p_ccb);         /* Restart the monitor timer */
5185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_start_timer (p_ccb);
5195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
5205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Create the control word to use */
5225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    ctrl_word = (function_code << L2CAP_FCR_SUP_SHIFT) | L2CAP_FCR_S_FRAME_BIT;
5235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT);
5245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    ctrl_word |= pf_bit;
5255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
526717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    BT_HDR *p_buf = (BT_HDR *)osi_malloc(L2CAP_CMD_BUF_SIZE);
527717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    p_buf->offset = HCI_DATA_PREAMBLE_SIZE;
528717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    p_buf->len    = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
5295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
530717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    /* Set the pointer to the beginning of the data */
531d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
5325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
533717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    /* Put in the L2CAP header */
534717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN);
535717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    UINT16_TO_STREAM(p, p_ccb->remote_cid);
536717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    UINT16_TO_STREAM(p, ctrl_word);
5375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
538717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    /* Compute the FCS and add to the end of the buffer if not bypassed */
539717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
540717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        fcs = l2c_fcr_tx_get_fcs (p_buf);
5415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
542717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        UINT16_TO_STREAM (p, fcs);
543717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        p_buf->len += L2CAP_FCS_LEN;
544717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    } else {
545717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        /* rewrite the length without FCS length */
546717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        p -= 6;
547717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        UINT16_TO_STREAM (p, L2CAP_FCR_OVERHEAD);
548717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    }
5495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
550717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    /* Now, the HCI transport header */
551717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT;
552717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    l2cu_set_acl_hci_header (p_buf, p_ccb);
5535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
554717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1)
555717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) {
556717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        L2CAP_TRACE_WARNING("L2CAP eRTM Tx S-frame  CID: 0x%04x  ctrlword: 0x%04x  Type: %s  ReqSeq: %u  P: %u  F: %u",
5575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->local_cid, ctrl_word,
5585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
5595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
5605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
5615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
562717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        L2CAP_TRACE_WARNING ("                  Buf Len: %u", p_buf->len);
563717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    } else {
564717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        L2CAP_TRACE_EVENT("L2CAP eRTM Tx S-frame  CID: 0x%04x  ctrlword: 0x%04x  Type: %s  ReqSeq: %u  P: %u  F: %u",
565717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                          p_ccb->local_cid, ctrl_word,
566717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                          SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
567717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                          (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
568717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                          (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
569717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                          (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
570717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov        L2CAP_TRACE_EVENT("                  Buf Len: %u", p_buf->len);
571717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    }
5725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
573717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
5745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
575717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    p_ccb->fcrb.last_ack_sent = p_ccb->fcrb.next_seq_expected;
5765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
577717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov    alarm_cancel(p_ccb->fcrb.ack_timer);
5785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
5795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
5815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
582ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
583ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_proc_pdu
584ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
585ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function is the entry point for processing of a
5869ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  received PDU when in flow control and/or retransmission
5879ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  modes.
588ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
589ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
590ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
591ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
5925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf)
5935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
594ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
595ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
596d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
597d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    fcs;
598d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    min_pdu_len;
599d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    ctrl_word;
6005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Check the length */
6025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    min_pdu_len = (p_ccb->bypass_fcs == L2CAP_BYPASS_FCS) ?
603d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                  (uint16_t)L2CAP_FCR_OVERHEAD : (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD);
6045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_buf->len < min_pdu_len)
6065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
607a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  Len too short: %u", p_ccb->local_cid, p_buf->len);
608cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free(p_buf);
6095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
6105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
6115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_STREAM_MODE)
6135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
6145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        process_stream_frame (p_ccb, p_buf);
6155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
6165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
6175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Get the control word */
619d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = ((uint8_t *)(p_buf+1)) + p_buf->offset;
6205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    STREAM_TO_UINT16 (ctrl_word, p);
6215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
6235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
6245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1)
6255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project         || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3))
6265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
6275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* REJ or SREJ */
628a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("L2CAP eRTM Rx S-frame: cid: 0x%04x  Len: %u  Type: %s  ReqSeq: %u  P: %u  F: %u",
6295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->local_cid, p_buf->len,
6305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
6315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
6325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
6335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
6345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
6355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
6365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
637a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_EVENT ("L2CAP eRTM Rx S-frame: cid: 0x%04x  Len: %u  Type: %s  ReqSeq: %u  P: %u  F: %u",
6385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->local_cid, p_buf->len,
6395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
6405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
6415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
6425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
6435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
6445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
6455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
6465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
647a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_EVENT ("L2CAP eRTM Rx I-frame: cid: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  ReqSeq: %u  F: %u",
6485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->local_cid, p_buf->len,
6495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
6505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
6515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
6525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
6535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
6545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
655a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati    L2CAP_TRACE_EVENT ("      eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt %u, wt_q.cnt %u, tries %u",
6561a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack,
6571a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->fcrb.next_seq_expected,
6581a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->fcrb.last_ack_sent,
6591a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q),
6601a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->fcrb.num_tries);
6615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Verify FCS if using */
6635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
6645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
665d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p = ((uint8_t *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
6665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Extract and drop the FCS from the packet */
6685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        STREAM_TO_UINT16 (fcs, p);
6695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_buf->len -= L2CAP_FCS_LEN;
6705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (l2c_fcr_rx_get_fcs(p_buf) != fcs)
6725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
673a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  BAD FCS", p_ccb->local_cid);
674cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_buf);
6755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            return;
6765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
6775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
6785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Get the control word */
680d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = ((uint8_t *)(p_buf+1)) + p_buf->offset;
6815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    STREAM_TO_UINT16 (ctrl_word, p);
6835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_buf->len    -= L2CAP_FCR_OVERHEAD;
6855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_buf->offset += L2CAP_FCR_OVERHEAD;
6865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
6875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If we had a poll bit outstanding, check if we got a final response */
6885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->fcrb.wait_ack)
6895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
6905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If final bit not set, ignore the frame unless it is a polled S-frame */
6915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( !(ctrl_word & L2CAP_FCR_F_BIT) )
6925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
6935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if ( (ctrl_word & L2CAP_FCR_P_BIT) && (ctrl_word & L2CAP_FCR_S_FRAME_BIT) )
6945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
6955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if (p_ccb->fcrb.srej_sent)
6965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
6975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                else if (p_ccb->fcrb.local_busy)
6985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
6995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                else
7005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
7015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* Got a poll while in wait_ack state, so re-start our timer with 1-second */
7035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* This is a small optimization... the monitor timer is 12 secs, but we saw */
7045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* that if the other side sends us a poll when we are waiting for a final,  */
7055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* then it speeds up recovery significantly if we poll him back soon after his poll. */
70678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer,
70778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   BT_1SEC_TIMEOUT_MS,
70878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   l2c_ccb_timer_timeout, p_ccb,
70978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   btu_general_alarm_queue);
7105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
711cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_buf);
7125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            return;
7135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
7145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
715d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_ccb->fcrb.wait_ack  = false;
7165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* P and F are mutually exclusive */
7185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
7195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            ctrl_word &= ~L2CAP_FCR_P_BIT;
7205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7211a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        if (fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
7225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->fcrb.num_tries = 0;
7235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_stop_timer (p_ccb);
7255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
7265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
7275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
7285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Otherwise, ensure the final bit is ignored */
7295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ctrl_word &= ~L2CAP_FCR_F_BIT;
7305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
7315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Process receive sequence number */
7335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!process_reqseq (p_ccb, ctrl_word))
7345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
735cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free(p_buf);
7365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
7375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
7385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project     /* Process based on whether it is an S-frame or an I-frame */
7405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
7415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        process_s_frame (p_ccb, p_buf, ctrl_word);
7425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
743d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        process_i_frame (p_ccb, p_buf, ctrl_word, false);
7445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Return if the channel got disconnected by a bad packet or max retransmissions */
7465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN) )
7475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
7485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If we have some buffers held while doing SREJ, and SREJ has cleared, process them now */
7501a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) &&
7511a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov         (!fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q)))
7525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
7531a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        fixed_queue_t *temp_q = p_ccb->fcrb.srej_rcv_hold_q;
7541a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
7555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7561a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(temp_q)) != NULL)
7575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
7585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN))
7595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
7605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* Get the control word */
761d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p = ((uint8_t *)(p_buf+1)) + p_buf->offset - L2CAP_FCR_OVERHEAD;
7625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                STREAM_TO_UINT16 (ctrl_word, p);
7645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
765a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_DEBUG ("l2c_fcr_proc_pdu() CID: 0x%04x  Process Buffer from SREJ_Hold_Q   TxSeq: %u  Expected_Seq: %u",
7665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                    p_ccb->local_cid, (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
7675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                    p_ccb->fcrb.next_seq_expected);
7685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* Process the SREJ held I-frame, but do not send an RR for each individual frame */
770d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                process_i_frame (p_ccb, p_buf, ctrl_word, true);
7715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
7725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else
773cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov                osi_free(p_buf);
7745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* If more frames were lost during SREJ, send a REJ */
7765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_ccb->fcrb.rej_after_srej)
7775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
778d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p_ccb->fcrb.rej_after_srej = false;
779d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p_ccb->fcrb.rej_sent       = true;
7805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0);
7825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
7835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
7841a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        fixed_queue_free(temp_q, NULL);
7855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Now, if needed, send one RR for the whole held queue */
7875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.rej_sent) && (!p_ccb->fcrb.srej_sent)
7885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project         &&  (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent) )
7895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
7905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
7915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
792a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_DEBUG ("l2c_fcr_proc_pdu() not sending RR CID: 0x%04x  local_busy:%d rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u",
7935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                p_ccb->local_cid, p_ccb->fcrb.local_busy, p_ccb->fcrb.rej_sent, p_ccb->fcrb.srej_sent, p_ccb->fcrb.next_seq_expected,
7945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                p_ccb->fcrb.last_ack_sent);
7955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
7965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
7975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
7985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If a window has opened, check if we can send any more packets */
7991a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if ( (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q) ||
8001a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov          !fixed_queue_is_empty(p_ccb->xmit_hold_q))
801d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen      && (p_ccb->fcrb.wait_ack == false)
802d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen      && (l2c_fcr_is_flow_controlled (p_ccb) == false) )
8035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
8045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
8055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
8065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
8075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
8085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
809ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
810ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_lcc_proc_pdu
811ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
812ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function is the entry point for processing of a
813ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  received PDU when in LE Coc flow control modes.
814ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
815ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
816ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
817ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
8186721232129f137ab024d9b95fc1094a714bc4c01Navin Kocharvoid l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
8196721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar{
8206721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8216721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    assert(p_ccb != NULL);
8226721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    assert(p_buf != NULL);
823d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t *p = (uint8_t*)(p_buf + 1) + p_buf->offset;
824d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t sdu_length;
8256721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    BT_HDR *p_data = NULL;
8266721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8276721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    /* Buffer length should not exceed local mps */
8286721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    if (p_buf->len > p_ccb->local_conn_cfg.mps)
8296721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
8306721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        /* Discard the buffer */
8316721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        osi_free(p_buf);
8326721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        return;
8336721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
8346721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8356721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    if (p_ccb->is_first_seg)
8366721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
8376721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        STREAM_TO_UINT16(sdu_length, p);
8386721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        /* Check the SDU Length with local MTU size */
8396721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        if (sdu_length > p_ccb->local_conn_cfg.mtu)
8406721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        {
8416721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            /* Discard the buffer */
8426721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            osi_free(p_buf);
8436721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            return;
8446721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        }
8456721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8466721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
847f33b6f434f086b20fabe5913016bc423ac975057Marie Janssen        p_data = (BT_HDR *)osi_malloc(L2CAP_MAX_BUF_SIZE);
848f33b6f434f086b20fabe5913016bc423ac975057Marie Janssen        if (p_data == NULL)
8496721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        {
8506721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            osi_free(p_buf);
8516721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            return;
8526721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        }
8536721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8546721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_ccb->ble_sdu = p_data;
8556721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_data->len = 0;
8566721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_ccb->ble_sdu_length = sdu_length;
8576721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        L2CAP_TRACE_DEBUG ("%s SDU Length = %d",__func__,sdu_length);
8586721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_buf->len -= sizeof(sdu_length);
8596721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_buf->offset += sizeof(sdu_length);
8606721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_data->offset = 0;
8616721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8626721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
8636721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else
8646721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_data = p_ccb->ble_sdu;
8656721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
866d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    memcpy((uint8_t*)(p_data + 1) + p_data->offset + p_data->len, (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
8676721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    p_data->len += p_buf->len;
868d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = (uint8_t*)(p_data+1) + p_data->offset;
8696721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    if (p_data->len == p_ccb->ble_sdu_length)
8706721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
8716721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_data);
872d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_ccb->is_first_seg = true;
8736721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_ccb->ble_sdu = NULL;
8746721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_ccb->ble_sdu_length = 0;
8756721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
8766721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else if (p_data->len < p_ccb->ble_sdu_length)
8776721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
878d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_ccb->is_first_seg = false;
8796721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
8806721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else
8816721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
8826721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        L2CAP_TRACE_ERROR ("%s Length in the SDU messed up",__func__);
8836721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        // TODO: reset every thing may be???
8846721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
8856721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8866721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    osi_free(p_buf);
8876721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    return;
8886721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar}
8896721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
8906721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar/*******************************************************************************
891ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
892ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_proc_tout
893ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
894ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Handle a timeout. We should be in error recovery state.
895ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
896ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
897ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
898ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
8995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_proc_tout (tL2C_CCB *p_ccb)
9005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
901ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
902a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati    L2CAP_TRACE_DEBUG ("l2c_fcr_proc_tout:  CID: 0x%04x  num_tries: %u (max: %u)  wait_ack: %u  ack_q_count: %u",
9031a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->local_cid, p_ccb->fcrb.num_tries,
9041a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->peer_cfg.fcr.max_transmit,
9051a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       p_ccb->fcrb.wait_ack,
9061a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                       fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
9075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
9095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_ccb->fcrb.retrans_touts++;
9105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
9115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (p_ccb->peer_cfg.fcr.max_transmit != 0) && (++p_ccb->fcrb.num_tries > p_ccb->peer_cfg.fcr.max_transmit) )
9135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
9145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2cu_disconnect_chnl (p_ccb);
9155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
9165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
9175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
9185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (!p_ccb->fcrb.srej_sent && !p_ccb->fcrb.rej_sent)
9195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
9205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_ccb->fcrb.local_busy)
9215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_P_BIT);
9225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else
9235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
9245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
9255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
9265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
9275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
930ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
931ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_proc_ack_tout
932ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
933ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Send RR/RNR if we have not acked I frame
934ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
935ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
936ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
937ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
9385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb)
9395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
940ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
941a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati    L2CAP_TRACE_DEBUG ("l2c_fcr_proc_ack_tout:  CID: 0x%04x State: %u  Wack:%u  Rq:%d  Acked:%d", p_ccb->local_cid,
9425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_ccb->chnl_state, p_ccb->fcrb.wait_ack, p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent);
9435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack)
9455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project      && (p_ccb->fcrb.last_ack_sent != p_ccb->fcrb.next_seq_expected) )
9465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
9475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
9485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.xmit_ack_touts++;
9495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
9505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_ccb->fcrb.local_busy)
9515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
9525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
9535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
9545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
9555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
9565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
959ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
960ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_reqseq
961ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
962ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Handle receive sequence number
963ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
964ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
965ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
966ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
967d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic bool    process_reqseq (tL2C_CCB *p_ccb, uint16_t ctrl_word)
9685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
969ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
9705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
971d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     req_seq, num_bufs_acked, xx;
972d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    ls;
973d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    full_sdus_xmitted;
9745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Receive sequence number does not ack anything for SREJ with P-bit set to zero */
9765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
9775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project     &&  ((ctrl_word & L2CAP_FCR_SUP_BITS) == (L2CAP_FCR_SUP_SREJ << L2CAP_FCR_SUP_SHIFT))
9785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project     &&  ((ctrl_word & L2CAP_FCR_P_BIT) == 0) )
9795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
9805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If anything still waiting for ack, restart the timer if it was stopped */
9811a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
9821a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            l2c_fcr_start_timer(p_ccb);
9835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
984d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        return (true);
9855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
9865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Extract the receive sequence number from the control word */
9885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    req_seq = (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
9895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    num_bufs_acked = (req_seq - p_fcrb->last_rx_ack) & L2CAP_FCR_SEQ_MODULO;
9915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
9925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Verify the request sequence is in range before proceeding */
9931a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if (num_bufs_acked > fixed_queue_length(p_fcrb->waiting_for_ack_q))
9945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
9955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* The channel is closed if ReqSeq is not in range */
996a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x  req_seq 0x%02x  last_rx_ack: 0x%02x  QCount: %u",
9971a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                             ctrl_word, req_seq, p_fcrb->last_rx_ack,
9981a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                             fixed_queue_length(p_fcrb->waiting_for_ack_q));
9995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2cu_disconnect_chnl (p_ccb);
1001d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        return (false);
10025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
10035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_fcrb->last_rx_ack = req_seq;
10055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Now we can release all acknowledged frames, and restart the retransmission timer if needed */
10075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (num_bufs_acked != 0)
10085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
10095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_fcrb->num_tries = 0;
10105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        full_sdus_xmitted = 0;
10115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
10135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_collect_ack_delay (p_ccb, num_bufs_acked);
10145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
10155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        for (xx = 0; xx < num_bufs_acked; xx++)
10175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
10181a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            BT_HDR *p_tmp = (BT_HDR *)fixed_queue_try_dequeue(p_fcrb->waiting_for_ack_q);
10191a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            ls = p_tmp->layer_specific & L2CAP_FCR_SAR_BITS;
10205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if ( (ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU) )
10225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                full_sdus_xmitted++;
10235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1024cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_tmp);
10255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
10265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If we are still in a wait_ack state, do not mess with the timer */
10285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (!p_ccb->fcrb.wait_ack)
10295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            l2c_fcr_stop_timer (p_ccb);
10305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Check if we need to call the "packet_sent" callback */
10325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (full_sdus_xmitted) )
10335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
10345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Special case for eRTM, if all packets sent, send 0xFFFF */
10351a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            if (fixed_queue_is_empty(p_fcrb->waiting_for_ack_q) &&
10361a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
10375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                full_sdus_xmitted = 0xFFFF;
10381a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            }
10395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, full_sdus_xmitted);
10415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
10425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
10435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If anything still waiting for ack, restart the timer if it was stopped */
10451a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
10461a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        l2c_fcr_start_timer(p_ccb);
1047d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    return (true);
10485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
10495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1052ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1053ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_s_frame
1054ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1055ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Process an S frame
1056ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1057ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
1058ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1059ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1060d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word)
10615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1062ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1063ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
1064ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
10655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2C_FCRB   *p_fcrb      = &p_ccb->fcrb;
1066d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    s_frame_type = (ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT;
1067d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        remote_was_busy;
1068d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        all_ok = true;
10695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_buf->len != 0)
10715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1072a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("Incorrect S-frame Length (%d)", p_buf->len);
10735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
10745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1075a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati    L2CAP_TRACE_DEBUG ("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d", ctrl_word, p_fcrb->remote_busy);
10765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
10785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_ccb->fcrb.s_frames_rcvd[s_frame_type]++;
10795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
10805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (ctrl_word & L2CAP_FCR_P_BIT)
10825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1083d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_fcrb->rej_sent   = false;             /* After checkpoint, we can send anoher REJ */
1084d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_fcrb->send_f_rsp = true;              /* Set a flag in case an I-frame is pending */
10855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
10865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    switch (s_frame_type)
10885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
10895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_RR:
10905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        remote_was_busy     = p_fcrb->remote_busy;
1091d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_fcrb->remote_busy = false;
10925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( (ctrl_word & L2CAP_FCR_F_BIT) || (remote_was_busy) )
10945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS);
10955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        break;
10965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
10975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_REJ:
1098d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_fcrb->remote_busy = false;
10995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS);
11005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        break;
11015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_RNR:
1103d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_fcrb->remote_busy = true;
11045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_stop_timer (p_ccb);
11055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        break;
11065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    case L2CAP_FCR_SUP_SREJ:
1108d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_fcrb->remote_busy = false;
1109d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        all_ok = retransmit_i_frames (p_ccb, (uint8_t)((ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT));
11105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        break;
11115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
11125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (all_ok)
11145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
11155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If polled, we need to respond with F-bit. Note, we may have sent a I-frame with the F-bit */
11165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_fcrb->send_f_rsp)
11175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
11185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcrb->srej_sent)
11195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
11205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else if (p_fcrb->local_busy)
11215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
11225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else
11235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
11245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1125d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_fcrb->send_f_rsp = false;
11265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
11275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
11285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
11295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1130a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_DEBUG ("process_s_frame hit_max_retries");
11315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
11325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1133cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov    osi_free(p_buf);
11345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
11355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1138ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1139ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_i_frame
1140ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1141ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Process an I frame
1142ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1143ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
1144ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1145ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1146d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word, bool    delay_ack)
11475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1148ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1149ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
1150ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
11515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
1152d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     tx_seq, num_lost, num_to_ack, next_srej;
11535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If we were doing checkpoint recovery, first retransmit all unacked I-frames */
11555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (ctrl_word & L2CAP_FCR_F_BIT)
11565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
11575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (!retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS))
11585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1159cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_buf);
11605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            return;
11615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
11625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
11635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
11655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_ccb->fcrb.ertm_pkt_counts[1]++;
11665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_ccb->fcrb.ertm_byte_counts[1] += p_buf->len;
11675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
11685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Extract the sequence number */
11705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
11715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If we have flow controlled the peer, ignore any bad I-frames from him */
11735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (tx_seq != p_fcrb->next_seq_expected) && (p_fcrb->local_busy) )
11745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1175a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("Dropping bad I-Frame since we flowed off, tx_seq:%u", tx_seq);
11765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
1177cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free(p_buf);
11785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
11795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
11805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Check if tx-sequence is the expected one */
11825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (tx_seq != p_fcrb->next_seq_expected)
11835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
11845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        num_lost = (tx_seq - p_fcrb->next_seq_expected) & L2CAP_FCR_SEQ_MODULO;
11855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Is the frame a duplicate ? If so, just drop it */
11875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz)
11885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
11895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Duplicate - simply drop it */
1190a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("process_i_frame() Dropping Duplicate Frame tx_seq:%u  ExpectedTxSeq %u", tx_seq, p_fcrb->next_seq_expected);
1191cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_buf);
11925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
11935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
11945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1195a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: %u  SRej: %u",
11965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                 p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent, p_fcrb->srej_sent);
11975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
11985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcrb->srej_sent)
11995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
12005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* If SREJ sent, save the frame for later processing as long as it is in sequence */
12011a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                next_srej = (((BT_HDR *)fixed_queue_try_peek_last(p_fcrb->srej_rcv_hold_q))->layer_specific + 1) & L2CAP_FCR_SEQ_MODULO;
12025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12031a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                if ( (tx_seq == next_srej) && (fixed_queue_length(p_fcrb->srej_rcv_hold_q) < p_ccb->our_cfg.fcr.tx_win_sz) )
12045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
12055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    /* If user gave us a pool for held rx buffers, use that */
12061d5b85924df3a114efe6588e857d0de3eb47b1d2Pavlin Radoslavov                    /* TODO: Could that happen? Get rid of this code. */
12071d5b85924df3a114efe6588e857d0de3eb47b1d2Pavlin Radoslavov                    if (p_ccb->ertm_info.fcr_rx_buf_size != L2CAP_FCR_RX_BUF_SIZE)
12085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    {
12095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        BT_HDR *p_buf2;
12105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        /* Adjust offset and len so that control word is copied */
12125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_buf->offset -= L2CAP_FCR_OVERHEAD;
12135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_buf->len    += L2CAP_FCR_OVERHEAD;
12145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12152e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov                        p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
12165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        if (p_buf2)
12185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        {
1219cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov                            osi_free(p_buf);
12205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_buf = p_buf2;
12215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        }
12225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_buf->offset += L2CAP_FCR_OVERHEAD;
12235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_buf->len -= L2CAP_FCR_OVERHEAD;
12245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    }
1225a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                    L2CAP_TRACE_DEBUG ("process_i_frame() Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: %u  SRej1",
12265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                         num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
12275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_buf->layer_specific = tx_seq;
12291a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                    fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
12305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
12315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                else
12325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
1233a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                    L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  frame dropped in Srej Sent next_srej:%u  hold_q.count:%u  win_sz:%u",
12341a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                                         p_ccb->local_cid, next_srej, fixed_queue_length(p_fcrb->srej_rcv_hold_q), p_ccb->our_cfg.fcr.tx_win_sz);
12355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1236d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                    p_fcrb->rej_after_srej = true;
1237cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov                    osi_free(p_buf);
12385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
12395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
12405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else if (p_fcrb->rej_sent)
12415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
1242a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: 1  SRej: %u",
12435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                     p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->srej_sent);
12445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* If REJ sent, just drop the frame */
1246cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov                osi_free(p_buf);
12475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
12485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else
12495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
1250a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_DEBUG ("process_i_frame() CID: 0x%04x  tx_seq:%u  ExpTxSeq %u  Rej: %u",
12515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                     p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
12525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* If only one lost, we will send SREJ, otherwise we will send REJ */
12545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if (num_lost > 1)
12555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
1256cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov                    osi_free(p_buf);
1257d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                    p_fcrb->rej_sent = true;
12585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0);
12595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
12605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                else
12615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
12621a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                    if (!fixed_queue_is_empty(p_fcrb->srej_rcv_hold_q))
12635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    {
1264a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                        L2CAP_TRACE_ERROR ("process_i_frame() CID: 0x%04x  sending SREJ tx_seq:%d hold_q.count:%u",
12651a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                                             p_ccb->local_cid, tx_seq, fixed_queue_length(p_fcrb->srej_rcv_hold_q));
12665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    }
12675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_buf->layer_specific = tx_seq;
12681a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                    fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
1269d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                    p_fcrb->srej_sent = true;
12705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, 0);
12715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
127278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                alarm_cancel(p_ccb->fcrb.ack_timer);
12735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
12745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
12755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
12765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
12775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Seq number is the next expected. Clear possible reject exception in case it occured */
1279d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p_fcrb->rej_sent = p_fcrb->srej_sent = false;
12805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Adjust the next_seq, so that if the upper layer sends more data in the callback
12825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project       context, the received frame is acked by an I-frame. */
12835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_fcrb->next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
12845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If any SAR problem in eRTM mode, spec says disconnect. */
12865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word))
12875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1288a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  reassembly failed", p_ccb->local_cid);
12895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2cu_disconnect_chnl (p_ccb);
12905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
12915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
12925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* RR optimization - if peer can still send us more, then start an ACK timer */
12945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    num_to_ack = (p_fcrb->next_seq_expected - p_fcrb->last_ack_sent) & L2CAP_FCR_SEQ_MODULO;
12955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (num_to_ack < p_ccb->fcrb.max_held_acks) && (!p_fcrb->local_busy) )
1297d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        delay_ack = true;
12985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
12995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* We should neve never ack frame if we are not in OPEN state */
13005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ((num_to_ack != 0) && p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN))
13015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
13025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If no frames are awaiting transmission or are held, send an RR or RNR S-frame for ack */
13035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (delay_ack)
13045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
13055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* If it is the first I frame we did not ack, start ack timer */
130678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov            if (!alarm_is_scheduled(p_ccb->fcrb.ack_timer)) {
130778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                alarm_set_on_queue(p_ccb->fcrb.ack_timer,
130878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   L2CAP_FCR_ACK_TIMEOUT_MS,
130978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   l2c_fcrb_ack_timer_timeout, p_ccb,
131078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   btu_general_alarm_queue);
13115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
13125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
13131a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        else if ((fixed_queue_is_empty(p_ccb->xmit_hold_q) ||
13141a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                  l2c_fcr_is_flow_controlled(p_ccb))
13151a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                 && fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q))
13165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
13175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcrb->local_busy)
13185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
13195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else
13205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
13215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
13225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
13235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
13245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1327ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1328ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         process_stream_frame
1329ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1330ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function processes frames in streaming mode
1331ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1332ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          -
1333ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1334ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
13355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectstatic void process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf)
13365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1337ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1338ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
1339ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
1340d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    ctrl_word;
1341d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    fcs;
1342d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
1343d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     tx_seq;
13445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Verify FCS if using */
13465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
13475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1348d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p = ((uint8_t *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
13495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Extract and drop the FCS from the packet */
13515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        STREAM_TO_UINT16 (fcs, p);
13525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_buf->len -= L2CAP_FCS_LEN;
13535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (l2c_fcr_rx_get_fcs(p_buf) != fcs)
13555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1356a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  BAD FCS", p_ccb->local_cid);
1357cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_buf);
13585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            return;
13595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
13605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
13615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Get the control word */
1363d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = ((uint8_t *)(p_buf+1)) + p_buf->offset;
13645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    STREAM_TO_UINT16 (ctrl_word, p);
13665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_buf->len    -= L2CAP_FCR_OVERHEAD;
13685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_buf->offset += L2CAP_FCR_OVERHEAD;
13695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Make sure it is an I-frame */
13715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
13725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1373a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  BAD S-frame in streaming mode  ctrl_word: 0x%04x", p_ccb->local_cid, ctrl_word);
1374cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free(p_buf);
13755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return;
13765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
13775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1378a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati    L2CAP_TRACE_EVENT ("L2CAP eRTM Rx I-frame: cid: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  ReqSeq: %u  F: %u",
13795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_ccb->local_cid, p_buf->len,
13805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
13815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
13825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
13835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
13845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Extract the sequence number */
13865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
13875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Check if tx-sequence is the expected one */
13895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (tx_seq != p_ccb->fcrb.next_seq_expected)
13905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1391a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  Lost frames Exp: %u  Got: %u  p_rx_sdu: 0x%08x",
13925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                p_ccb->local_cid, p_ccb->fcrb.next_seq_expected, tx_seq, p_ccb->fcrb.p_rx_sdu);
13935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Lost one or more packets, so flush the SAR queue */
1395cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free_and_reset((void **)&p_ccb->fcrb.p_rx_sdu);
13965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
13975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
13985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_ccb->fcrb.next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
13995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word))
14015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
14025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Some sort of SAR error, so flush the SAR queue */
1403cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free_and_reset((void **)&p_ccb->fcrb.p_rx_sdu);
14045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
14055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
14065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1409ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1410ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         do_sar_reassembly
1411ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1412ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Process SAR bits and re-assemble frame
1413ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1414ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          true if all OK, else false
1415ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1416ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1417d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic bool    do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word)
14185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1419ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1420ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_buf != NULL);
1421ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
14225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
1423d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    sar_type = ctrl_word & L2CAP_FCR_SEG_BITS;
1424d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        packet_ok = true;
1425d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
14265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Check if the SAR state is correct */
14285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU))
14295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
14305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_fcrb->p_rx_sdu != NULL)
14315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1432a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("SAR - got unexpected unsegmented or start SDU  Expected len: %u  Got so far: %u",
14335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                  p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len);
14345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1435d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            packet_ok = false;
14365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
14375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Check the length of the packet */
14385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( (sar_type == L2CAP_FCR_START_SDU) && (p_buf->len < L2CAP_SDU_LEN_OVERHEAD) )
14395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1440a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("SAR start packet too short: %u", p_buf->len);
1441d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            packet_ok = false;
14425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
14435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
14445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
14455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
14465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_fcrb->p_rx_sdu == NULL)
14475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1448a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("SAR - got unexpected cont or end SDU");
1449d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            packet_ok = false;
14505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
14515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
14525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (packet_ok) && (sar_type != L2CAP_FCR_UNSEG_SDU) )
14545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1455d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p = ((uint8_t *)(p_buf + 1)) + p_buf->offset;
14565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* For start SDU packet, extract the SDU length */
14585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (sar_type == L2CAP_FCR_START_SDU)
14595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
14605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Get the SDU length */
14615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            STREAM_TO_UINT16 (p_fcrb->rx_sdu_len, p);
14625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_buf->offset += 2;
14635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_buf->len    -= 2;
14645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu)
14665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
1467a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_WARNING ("SAR - SDU len: %u  larger than MTU: %u", p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len);
1468d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                packet_ok = false;
1469717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov            } else {
1470717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                p_fcrb->p_rx_sdu = (BT_HDR *)osi_malloc(L2CAP_MAX_BUF_SIZE);
14712e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov                p_fcrb->p_rx_sdu->offset = OBX_BUF_MIN_OFFSET;
1472717a4a9f3a044f264ec2482c2d1806ec3093707aPavlin Radoslavov                p_fcrb->p_rx_sdu->len = 0;
14735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
14745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
14755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (packet_ok)
14775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
14785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len)
14795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
1480a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_ERROR ("SAR - SDU len exceeded  Type: %u   Lengths: %u %u %u",
14815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                    sar_type, p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
1482d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                packet_ok = false;
14835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
14845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else if ( (sar_type == L2CAP_FCR_END_SDU) && ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len) )
14855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
1486a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_WARNING ("SAR - SDU end rcvd but SDU incomplete: %u %u %u",
14875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                      p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
1488d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                packet_ok = false;
14895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
14905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else
14915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
1492d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                memcpy (((uint8_t *) (p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset + p_fcrb->p_rx_sdu->len, p, p_buf->len);
14935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_fcrb->p_rx_sdu->len += p_buf->len;
14955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1496cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov                osi_free(p_buf);
14975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_buf = NULL;
14985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
14995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if (sar_type == L2CAP_FCR_END_SDU)
15005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
15015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_buf            = p_fcrb->p_rx_sdu;
15025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_fcrb->p_rx_sdu = NULL;
15035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
15045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
15055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
15065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
15075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1508d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    if (packet_ok == false)
15095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1510cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov        osi_free(p_buf);
15115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
15125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else if (p_buf != NULL)
15135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
15145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_NUM_FIXED_CHNLS > 0)
1515ead3cde4bac0c3e32cd31f149093f004eef8ceebGanesh Ganapathi Batta        if (p_ccb->local_cid < L2CAP_BASE_APPL_CID &&
1516ead3cde4bac0c3e32cd31f149093f004eef8ceebGanesh Ganapathi Batta            (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL && p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL))
1517ead3cde4bac0c3e32cd31f149093f004eef8ceebGanesh Ganapathi Batta        {
1518ead3cde4bac0c3e32cd31f149093f004eef8ceebGanesh Ganapathi Batta            if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
15198372aa5fa535ee4f09c09981b6125b54ace31fe2Kim Schulz                (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
15208372aa5fa535ee4f09c09981b6125b54ace31fe2Kim Schulz                    (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr, p_buf);
1521ead3cde4bac0c3e32cd31f149093f004eef8ceebGanesh Ganapathi Batta        }
15225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
15235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
15245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_buf);
15255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
15265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (packet_ok);
15285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
15295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1532ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1533ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         retransmit_i_frames
1534ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1535ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function retransmits i-frames awaiting acks.
1536ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1537ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          bool    - true if retransmitted
1538ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1539ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1540d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic bool    retransmit_i_frames (tL2C_CCB *p_ccb, uint8_t tx_seq)
15415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1542ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1543ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
15441a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    BT_HDR      *p_buf = NULL;
1545d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
1546d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     buf_seq;
1547d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    ctrl_word;
15485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15491a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if ( (!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
15505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project     &&  (p_ccb->peer_cfg.fcr.max_transmit != 0)
15515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project     &&  (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit) )
15525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1553a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_EVENT ("Max Tries Exceeded:  (last_acq: %d  CID: 0x%04x  num_tries: %u (max: %u) ack_q_count: %u",
15545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit,
15551a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
15565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2cu_disconnect_chnl (p_ccb);
1558d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        return (false);
15595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
15605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* tx_seq indicates whether to retransmit a specific sequence or all (if == L2C_FCR_RETX_ALL_PKTS) */
1562577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    list_t *list_ack = NULL;
1563577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    const list_node_t *node_ack = NULL;
1564577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    if (! fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) {
1565577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        list_ack = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
1566577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        node_ack = list_begin(list_ack);
1567577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    }
15685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (tx_seq != L2C_FCR_RETX_ALL_PKTS)
15695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
15705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If sending only one, the sequence number tells us which one. Look for it.
15715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        */
1572577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        if (list_ack != NULL) {
1573577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            for ( ; node_ack != list_end(list_ack); node_ack = list_next(node_ack)) {
1574577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                p_buf = (BT_HDR *)list_node(node_ack);
1575577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                /* Get the old control word */
1576d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p = ((uint8_t *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
15775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1578577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                STREAM_TO_UINT16 (ctrl_word, p);
15795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1580577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                buf_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
15815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1582577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                L2CAP_TRACE_DEBUG ("retransmit_i_frames()   cur seq: %u  looking for: %u", buf_seq, tx_seq);
15835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1584577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                if (tx_seq == buf_seq)
1585577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                    break;
1586577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            }
15875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
15885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
15895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (!p_buf)
15905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
15911a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            L2CAP_TRACE_ERROR ("retransmit_i_frames() UNKNOWN seq: %u  q_count: %u",
15921a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                               tx_seq,
15931a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov                               fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
1594d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            return (true);
15955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
15965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
15975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
15985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
15996c303aeca25783453333172d0b29e5472f1b1c93Chris Manton        // Iterate though list and flush the amount requested from
16006c303aeca25783453333172d0b29e5472f1b1c93Chris Manton        // the transmit data queue that satisfy the layer and event conditions.
16011a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        for (list_node_t *node_tmp = list_begin(p_ccb->p_lcb->link_xmit_data_q);
16021a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            node_tmp != list_end(p_ccb->p_lcb->link_xmit_data_q);) {
16031a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov          BT_HDR *p_tmp = (BT_HDR *)list_node(node_tmp);
16041a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov          node_tmp = list_next(node_tmp);
16053805ab67b9c973b2afb7475e1a86e35bc18ffd1dChris Manton
16066c303aeca25783453333172d0b29e5472f1b1c93Chris Manton            /* Do not flush other CIDs or partial segments */
16071a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov          if ((p_tmp->layer_specific == 0) && (p_tmp->event == p_ccb->local_cid)) {
16081a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            list_remove(p_ccb->p_lcb->link_xmit_data_q, p_tmp);
1609cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(p_tmp);
16106c303aeca25783453333172d0b29e5472f1b1c93Chris Manton          }
16115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
16125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Also flush our retransmission queue */
16141a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        while (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
1615cceb430489a70add1b996d54289867c17f4ac0fdPavlin Radoslavov            osi_free(fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q));
16165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1617577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        if (list_ack != NULL)
1618577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            node_ack = list_begin(list_ack);
16195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
16205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1621577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    if (list_ack != NULL) {
1622577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        while (node_ack != list_end(list_ack))
16235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1624577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            p_buf = (BT_HDR *)list_node(node_ack);
1625577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            node_ack = list_next(node_ack);
16265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1627577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            BT_HDR *p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
1628577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            if (p_buf2)
1629577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            {
1630577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                p_buf2->layer_specific = p_buf->layer_specific;
1631577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov
1632577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                fixed_queue_enqueue(p_ccb->fcrb.retrans_q, p_buf2);
1633577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            }
16345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1635577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            if ( (tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL) )
1636577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                break;
1637577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        }
16385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
16395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
16415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16421a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q))
16435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
16445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.num_tries++;
16455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2c_fcr_start_timer (p_ccb);
16465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
16475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1648d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    return (true);
16495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
16505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1653ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1654ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_get_next_xmit_sdu_seg
1655ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1656ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Get the next SDU segment to transmit.
1657ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1658ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          pointer to buffer with segment or NULL
1659ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1660ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1661d19e0785e662e640191a075eda07acce61c2aedaMarie JanssenBT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, uint16_t max_packet_length)
16625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1663ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1664ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
1665d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        first_seg    = false,       /* The segment is the first part of data  */
1666d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                mid_seg      = false,       /* The segment is the middle part of data */
1667d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                last_seg     = false;       /* The segment is the last part of data   */
1668d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    sdu_len = 0;
16695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    BT_HDR      *p_buf, *p_xmit;
1670d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
1671d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/;
16725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If there is anything in the retransmit queue, that goes first
16745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    */
16751a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q);
16761a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if (p_buf != NULL)
16775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
16785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Update Rx Seq and FCS if we acked some packets while this one was queued */
1679d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        prepare_I_frame (p_ccb, p_buf, true);
16805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_buf->event = p_ccb->local_cid;
16825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
16845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.pkts_retransmitted++;
16855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ertm_pkt_counts[0]++;
16865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ertm_byte_counts[0] += (p_buf->len - 8);
16875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
16885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        return (p_buf);
16895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
16905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* For BD/EDR controller, max_packet_length is set to 0             */
16925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* For AMP controller, max_packet_length is set by available blocks */
16935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if ( (max_packet_length > L2CAP_MAX_HEADER_FCS)
16945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project      && (max_pdu + L2CAP_MAX_HEADER_FCS > max_packet_length) )
16955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
16965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        max_pdu = max_packet_length - L2CAP_MAX_HEADER_FCS;
16975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
16985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
16991a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
17005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If there is more data than the MPS, it requires segmentation */
17025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_buf->len > max_pdu)
17035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
17045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* We are using the "event" field to tell is if we already started segmentation */
17055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_buf->event == 0)
17065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
1707d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            first_seg = true;
17085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            sdu_len   = p_buf->len;
17095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
17105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
1711d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            mid_seg = true;
17125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Get a new buffer and copy the data that can be sent in a PDU */
17142e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov        p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET,
17152e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov                                   max_pdu);
17165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_xmit != NULL)
17185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
17195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_buf->event  = p_ccb->local_cid;
17205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_xmit->event = p_ccb->local_cid;
17215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_buf->len    -= max_pdu;
17235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_buf->offset += max_pdu;
17245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* copy PBF setting */
17265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_xmit->layer_specific = p_buf->layer_specific;
17275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
17285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else /* Should never happen if the application has configured buffers correctly */
17295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
17302e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov            L2CAP_TRACE_ERROR ("L2CAP - cannot get buffer for segmentation, max_pdu: %u", max_pdu);
17315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            return (NULL);
17325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
17335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
17345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else    /* Use the original buffer if no segmentation, or the last segment */
17355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
17361a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        p_xmit = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
17375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_xmit->event != 0)
1739d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            last_seg = true;
17405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->event = p_ccb->local_cid;
17425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
17435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Step back to add the L2CAP headers */
17455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_xmit->offset -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD);
17465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_xmit->len    += L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
17475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (first_seg)
17495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
17505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->offset -= L2CAP_SDU_LEN_OVERHEAD;
17515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->len    += L2CAP_SDU_LEN_OVERHEAD;
17525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
17535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Set the pointer to the beginning of the data */
1755d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = (uint8_t *)(p_xmit + 1) + p_xmit->offset;
17565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Now the L2CAP header */
17585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Note: if FCS has to be included then the length is recalculated later */
17605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    UINT16_TO_STREAM (p, p_xmit->len - L2CAP_PKT_OVERHEAD);
17615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    UINT16_TO_STREAM (p, p_ccb->remote_cid);
17635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (first_seg)
17655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
17665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Skip control word and add SDU length */
17675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p += 2;
17685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        UINT16_TO_STREAM (p, sdu_len);
17695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* We will store the SAR type in layer-specific */
17715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* layer_specific is shared with flushable flag(bits 0-1), don't clear it */
17725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->layer_specific |= L2CAP_FCR_START_SDU;
17735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1774d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        first_seg = false;
17755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
17765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else if (mid_seg)
17775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->layer_specific |= L2CAP_FCR_CONT_SDU;
17785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else if (last_seg)
17795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->layer_specific |= L2CAP_FCR_END_SDU;
17805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else
17815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_xmit->layer_specific |= L2CAP_FCR_UNSEG_SDU;
17825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1783d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    prepare_I_frame (p_ccb, p_xmit, false);
17845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
17865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
17872e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov        BT_HDR *p_wack = l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len);
17885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (!p_wack)
17905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
17912e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov            L2CAP_TRACE_ERROR("L2CAP - no buffer for xmit cloning, CID: 0x%04x  Length: %u",
17922e3d006b96eafb0651fe7f78d28250faf89405dePavlin Radoslavov                              p_ccb->local_cid, p_xmit->len);
17935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* We will not save the FCS in case we reconfigure and change options */
17955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
17965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_xmit->len -= L2CAP_FCS_LEN;
17975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
17985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Pretend we sent it and it got lost */
17991a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit);
18005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            return (NULL);
18015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
18025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
18035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
18045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
18055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* set timestamp at the end of tx I-frame to get acking delay */
1806871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov            /*
1807871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov             * NOTE: Here we assume the allocate buffer is large enough
1808871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov             * to include extra 4 octets at the end.
1809871e9ba3063530a81ca7ff03e8433c25e1e8c096Pavlin Radoslavov             */
1810d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p = ((uint8_t *) (p_wack+1)) + p_wack->offset + p_wack->len;
1811c196f214c5ae349ec2022f8d3cbaf56910b3b9f8Pavlin Radoslavov            UINT32_TO_STREAM (p, time_get_os_boottime_ms());
18125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
18135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* We will not save the FCS in case we reconfigure and change options */
18145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
18155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_wack->len -= L2CAP_FCS_LEN;
18165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_wack->layer_specific = p_xmit->layer_specific;
18181a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov            fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack);
18195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
18205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
18225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ertm_pkt_counts[0]++;
18235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ertm_byte_counts[0] += (p_xmit->len - 8);
18245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
18255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
18275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (p_xmit);
18295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
18305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
18316721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar/*******************************************************************************
1832ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1833ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_lcc_get_next_xmit_sdu_seg
1834ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
18359ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Description      Get the next SDU segment to transmit for LE connection
18369ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                  oriented channel
1837ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1838ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          pointer to buffer with segment or NULL
1839ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1840ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1841d19e0785e662e640191a075eda07acce61c2aedaMarie JanssenBT_HDR *l2c_lcc_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, uint16_t max_packet_length)
18426721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar{
1843d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        first_seg    = false;       /* The segment is the first part of data  */
1844d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool        last_seg     = false;       /* The segment is the last part of data  */
1845d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    no_of_bytes_to_send = 0;
1846d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    sdu_len = 0;
18476721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    BT_HDR      *p_buf, *p_xmit;
1848d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t     *p;
1849d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t    max_pdu = p_ccb->peer_conn_cfg.mps;
18506721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
18516721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
18526721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
18536721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    /* We are using the "event" field to tell is if we already started segmentation */
18546721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    if (p_buf->event == 0)
18556721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
1856d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        first_seg = true;
18576721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        sdu_len   = p_buf->len;
18586721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        if (p_buf->len <= (max_pdu - L2CAP_LCC_SDU_LENGTH))
18596721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        {
1860d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            last_seg = true;
18616721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            no_of_bytes_to_send = p_buf->len;
18626721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        }
18636721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        else
18646721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            no_of_bytes_to_send = max_pdu - L2CAP_LCC_SDU_LENGTH;
18656721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
18666721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else if (p_buf->len <= max_pdu)
18676721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
1868d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        last_seg = true;
18696721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        no_of_bytes_to_send = p_buf->len;
18706721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
18716721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else
18726721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
18736721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        /* Middle Packet */
18746721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        no_of_bytes_to_send = max_pdu;
18756721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
18766721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
18776721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    /* Get a new buffer and copy the data that can be sent in a PDU */
1878d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    if (first_seg == true)
18796721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_xmit = l2c_fcr_clone_buf (p_buf, L2CAP_LCC_OFFSET,
18806721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar                    no_of_bytes_to_send);
18816721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else
18826721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_xmit = l2c_fcr_clone_buf (p_buf, L2CAP_MIN_OFFSET,
18836721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar                   no_of_bytes_to_send);
18846721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
18856721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    if (p_xmit != NULL)
18866721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
18876721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_buf->event  = p_ccb->local_cid;
18886721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_xmit->event = p_ccb->local_cid;
18896721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
1890d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        if (first_seg == true)
18916721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        {
18926721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            p_xmit->offset -= L2CAP_LCC_SDU_LENGTH;  /* for writing the SDU length. */
1893d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p = (uint8_t *)(p_xmit + 1) + p_xmit->offset;
18946721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            UINT16_TO_STREAM(p, sdu_len);
18956721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar            p_xmit->len += L2CAP_LCC_SDU_LENGTH;
18966721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        }
18976721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
18986721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_buf->len    -= no_of_bytes_to_send;
18996721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_buf->offset += no_of_bytes_to_send;
19006721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
19016721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        /* copy PBF setting */
19026721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_xmit->layer_specific = p_buf->layer_specific;
19036721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
19046721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
19056721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    else /* Should never happen if the application has configured buffers correctly */
19066721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
19076721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        L2CAP_TRACE_ERROR ("L2CAP - cannot get buffer, for segmentation");
19086721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        return (NULL);
19096721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
19106721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
1911d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    if (last_seg == true)
19126721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    {
19136721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
19146721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar        osi_free(p_buf);
19156721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    }
19166721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
19176721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    /* Step back to add the L2CAP headers */
19186721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    p_xmit->offset -= L2CAP_PKT_OVERHEAD;
19196721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    p_xmit->len    += L2CAP_PKT_OVERHEAD ;
19206721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
19216721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    /* Set the pointer to the beginning of the data */
1922d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p = (uint8_t *)(p_xmit + 1) + p_xmit->offset;
19236721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
19246721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    /* Note: if FCS has to be included then the length is recalculated later */
19256721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    UINT16_TO_STREAM (p, p_xmit->len - L2CAP_PKT_OVERHEAD);
19266721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    UINT16_TO_STREAM (p, p_ccb->remote_cid);
19276721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar    return (p_xmit);
19286721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar
19296721232129f137ab024d9b95fc1094a714bc4c01Navin Kochar}
19305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1932ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Configuration negotiation functions
1933ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1934ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * The following functions are used in negotiating channel modes during
1935ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * configuration
1936ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
19375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1939ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1940ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_chk_chan_modes
1941ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1942ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Validates and adjusts if necessary, the FCR options
1943ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  based on remote EXT features.
1944ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1945ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  Note: This assumes peer EXT Features have been received.
1946ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                      Basic mode is used if FCR Options have not been received
1947ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
19489ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson * Returns          uint8_t - nonzero if can continue, '0' if no compatible
19499ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson *                            channels
1950ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1951ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1952d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenuint8_t l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb)
19535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1954ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1955ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
19565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Remove nonbasic options that the peer does not support */
19575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS))
19585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_ERTM;
19595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_STREAM_MODE))
19615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_STREAM;
19625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* At least one type needs to be set (Basic, ERTM, STM) to continue */
19645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!p_ccb->ertm_info.allowed_modes)
19655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1966a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("L2CAP - Peer does not support our desired channel types");
19675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
19685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (p_ccb->ertm_info.allowed_modes);
19705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
19715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
1973ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1974ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_adj_our_req_options
1975ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1976ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Validates and sets up the FCR options passed in from
1977ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  L2CA_ConfigReq based on remote device's features.
1978ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1979ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          true if no errors, Otherwise false
1980ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
1981ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
1982d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenbool    l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
19835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
1984ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
1985ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_cfg != NULL);
1986ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
19875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    tL2CAP_FCR_OPTS *p_fcr = &p_cfg->fcr;
19885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_fcr->mode != p_ccb->ertm_info.preferred_mode)
19905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
1991a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("l2c_fcr_adj_our_req_options - preferred_mode (%d), does not match mode (%d)",
19925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                            p_ccb->ertm_info.preferred_mode, p_fcr->mode);
19935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* The preferred mode is passed in through tL2CAP_ERTM_INFO, so override this one */
19955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_fcr->mode = p_ccb->ertm_info.preferred_mode;
19965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
19975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
19985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If upper layer did not request eRTM mode, BASIC must be used */
19995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC)
20005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
20015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_cfg->fcr_present && p_fcr->mode != L2CAP_FCR_BASIC_MODE)
20025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
2003a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati            L2CAP_TRACE_WARNING ("l2c_fcr_adj_our_req_options (mode %d): ERROR: No FCR options set using BASIC mode", p_fcr->mode);
20045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
20055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_fcr->mode = L2CAP_FCR_BASIC_MODE;
20065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
20075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Process the FCR options if initial channel bring-up (not a reconfig request)
20095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    ** Determine initial channel mode to try based on our options and remote's features
20105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    */
20115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_cfg->fcr_present && !(p_ccb->config_done & RECONFIG_FLAG))
20125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
20135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* We need to have at least one mode type common with the peer */
20145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (!l2c_fcr_chk_chan_modes(p_ccb))
20155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
20165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Two channels have incompatible supported types */
20175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            l2cu_disconnect_chnl (p_ccb);
2018d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            return (false);
20195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
20205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Basic is the only common channel mode between the two devices */
20225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC)
20235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
20245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* We only want to try Basic, so bypass sending the FCR options entirely */
2025d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_cfg->fcr_present = false;
2026d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_cfg->fcs_present = false;             /* Illegal to use FCS option in basic mode */
2027d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_cfg->ext_flow_spec_present = false;   /* Illegal to use extended flow spec in basic mode */
20285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
20295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* We have at least one non-basic mode available
20315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project         * Override mode from available mode options based on preference, if needed
20325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project         */
20335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
20345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
20355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* If peer does not support STREAMING, try ERTM */
20365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcr->mode == L2CAP_FCR_STREAM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_STREAM))
20375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2038a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_DEBUG ("L2C CFG: mode is STREAM, but peer does not support; Try ERTM");
20395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_fcr->mode = L2CAP_FCR_ERTM_MODE;
20405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
20415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* If peer does not support ERTM, try BASIC (will support this if made it here in the code) */
20435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcr->mode == L2CAP_FCR_ERTM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM))
20445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2045a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_DEBUG ("L2C CFG: mode is ERTM, but peer does not support; Try BASIC");
20465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_fcr->mode = L2CAP_FCR_BASIC_MODE;
20475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
20485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
20495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_fcr->mode != L2CAP_FCR_BASIC_MODE)
20515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
20525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* MTU must be smaller than buffer size */
20535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if ( (p_cfg->mtu_present) && (p_cfg->mtu > p_ccb->max_rx_mtu) )
20545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2055a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_WARNING ("L2CAP - MTU: %u  larger than buf size: %u", p_cfg->mtu, p_ccb->max_rx_mtu);
2056d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                return (false);
20575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
20585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* application want to use the default MPS */
20605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcr->mps == L2CAP_DEFAULT_ERM_MPS)
20615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
20625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_fcr->mps = L2CAP_MPS_OVER_BR_EDR;
20635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
20645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* MPS must be less than MTU */
20655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            else if (p_fcr->mps > p_ccb->max_rx_mtu)
20665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2067a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_WARNING ("L2CAP - MPS  %u  invalid  MTU: %u", p_fcr->mps, p_ccb->max_rx_mtu);
2068d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                return (false);
20695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
20705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* We always initially read into the HCI buffer pool, so make sure it fits */
20725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_fcr->mps > (L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS))
20735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_fcr->mps = L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS;
20745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
20755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
20765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
2077d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_cfg->fcs_present = false;             /* Illegal to use FCS option in basic mode */
2078d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_cfg->ext_flow_spec_present = false;   /* Illegal to use extended flow spec in basic mode */
20795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
20805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->our_cfg.fcr = *p_fcr;
20825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
20835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else    /* Not sure how to send a reconfiguration(??) should fcr be included? */
20845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
2085d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_ccb->our_cfg.fcr_present = false;
20865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
20875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2088d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    return (true);
20895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
20905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
20925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2093ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2094ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_adj_monitor_retran_timeout
2095ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2096ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Overrides monitor/retrans timer value based on controller
2097ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2098ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          None
2099ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2100ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
21015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb)
21025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
2103ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
2104ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
21055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* adjust our monitor/retran timeout */
21065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->out_cfg_fcr_present)
21075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
21085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /*
21095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ** if we requestd ERTM or accepted ERTM
21105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ** We may accept ERTM even if we didn't request ERTM, in case of requesting STREAM
21115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        */
21125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
21135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project          ||(p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE))
21145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
21155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* upper layer setting is ignored */
21165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->our_cfg.fcr.mon_tout    = L2CAP_MIN_MONITOR_TOUT;
21175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->our_cfg.fcr.rtrans_tout = L2CAP_MIN_RETRANS_TOUT;
21185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
21195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
21205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
21215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->our_cfg.fcr.mon_tout    = 0;
21225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->our_cfg.fcr.rtrans_tout = 0;
21235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
21245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2125a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_DEBUG ("l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d",
21265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                             p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout);
21275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
21285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
21295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2130ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2131ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_adj_our_rsp_options
2132ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2133ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Overrides any neccesary FCR options passed in from
2134ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  L2CA_ConfigRsp based on our FCR options.
2135ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  Only makes adjustments if channel is in ERTM mode.
2136ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2137ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          None
2138ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2139ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
21405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectvoid l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
21415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
2142ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
2143ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_cfg != NULL);
2144ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
21455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* adjust our monitor/retran timeout */
21465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    l2c_fcr_adj_monitor_retran_timeout(p_ccb);
21475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_cfg->fcr_present = p_ccb->out_cfg_fcr_present;
21495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_cfg->fcr_present)
21515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
21525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Temporary - until a better algorithm is implemented */
21535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If peer's tx_wnd_sz requires too many buffers for us to support, then adjust it. For now, respond with our own tx_wnd_sz. */
21545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Note: peer is not guaranteed to obey our adjustment */
21555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz)
21565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
2157d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            L2CAP_TRACE_DEBUG ("%s: adjusting requested tx_win_sz from %i to %i", __func__, p_ccb->peer_cfg.fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz);
21585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
21595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
21605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_cfg->fcr.mode         = p_ccb->peer_cfg.fcr.mode;
21625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_cfg->fcr.tx_win_sz    = p_ccb->peer_cfg.fcr.tx_win_sz;
21635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_cfg->fcr.max_transmit = p_ccb->peer_cfg.fcr.max_transmit;
21645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_cfg->fcr.mps          = p_ccb->peer_cfg.fcr.mps;
21655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_cfg->fcr.rtrans_tout  = p_ccb->our_cfg.fcr.rtrans_tout;
21665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_cfg->fcr.mon_tout     = p_ccb->our_cfg.fcr.mon_tout;
21675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
21685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
21695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2171ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2172ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_renegotiate_chan
2173ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2174ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      Called upon unsuccessful peer response to config request.
2175ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  If the error is because of the channel mode, it will try
2176ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  to resend using another supported optional channel.
2177ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2178ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          true if resent configuration, False if channel matches or
2179ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  cannot match.
2180ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2181ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2182d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenbool    l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
21835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
2184ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
2185ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_cfg != NULL);
2186ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
2187d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t peer_mode = p_ccb->our_cfg.fcr.mode;
2188d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    bool    can_renegotiate;
21895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21905738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Skip if this is a reconfiguration from OPEN STATE or if FCR is not returned */
21915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (!p_cfg->fcr_present || (p_ccb->config_done & RECONFIG_FLAG))
2192d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        return (false);
21935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Only retry if there are more channel options to try */
21955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS)
21965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
21975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        peer_mode = (p_cfg->fcr_present) ? p_cfg->fcr.mode : L2CAP_FCR_BASIC_MODE;
21985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
21995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_ccb->our_cfg.fcr.mode != peer_mode)
22005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
22015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if ((--p_ccb->fcr_cfg_tries) == 0)
22035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
22045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
2205a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_WARNING ("l2c_fcr_renegotiate_chan (Max retries exceeded)");
22065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
22075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2208d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            can_renegotiate = false;
22095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Try another supported mode if available based on our last attempted channel */
22115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            switch (p_ccb->our_cfg.fcr.mode)
22125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
22135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* Our Streaming mode request was unnacceptable; try ERTM or Basic */
22145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            case L2CAP_FCR_STREAM_MODE:
22155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* Peer wants ERTM and we support it */
22165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if ( (peer_mode == L2CAP_FCR_ERTM_MODE) && (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) )
22175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
2218a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                    L2CAP_TRACE_DEBUG ("l2c_fcr_renegotiate_chan(Trying ERTM)");
22195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
2220d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                    can_renegotiate = true;
22215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
22225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                else    /* Falls through */
22235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            case L2CAP_FCR_ERTM_MODE:
22255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
22265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    /* We can try basic for any other peer mode if we support it */
22275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC)
22285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    {
2229a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                        L2CAP_TRACE_DEBUG ("l2c_fcr_renegotiate_chan(Trying Basic)");
2230d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                        can_renegotiate = true;
22315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
22325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    }
22335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
22345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                break;
22355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            default:
22375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* All other scenarios cannot be renegotiated */
22385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                break;
22395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
22405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (can_renegotiate)
22425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2243d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p_ccb->our_cfg.fcr_present = true;
22445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if (p_ccb->our_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
22465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                {
2247d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                    p_ccb->our_cfg.fcs_present = false;
2248d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                    p_ccb->our_cfg.ext_flow_spec_present = false;
22495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    /* Basic Mode uses ACL Data Pool, make sure the MTU fits */
22515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
22525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    {
2253a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                        L2CAP_TRACE_WARNING ("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
22545738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_cfg->mtu = L2CAP_MTU_SIZE;
22555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    }
22565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                }
22575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2cu_process_our_cfg_req (p_ccb, &p_ccb->our_cfg);
22595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                l2cu_send_peer_config_req (p_ccb, &p_ccb->our_cfg);
226078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                alarm_set_on_queue(p_ccb->l2c_ccb_timer,
226178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   L2CAP_CHNL_CFG_TIMEOUT_MS,
226278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   l2c_ccb_timer_timeout, p_ccb,
226378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov                                   btu_general_alarm_queue);
2264d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                return (true);
22655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
22665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
22675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
22685738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Disconnect if the channels do not match */
22705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->our_cfg.fcr.mode != peer_mode)
22715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
2272a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati        L2CAP_TRACE_WARNING ("L2C CFG:  Channels incompatible (local %d, peer %d)",
22735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                              p_ccb->our_cfg.fcr.mode, peer_mode);
22745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        l2cu_disconnect_chnl (p_ccb);
22755738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
22765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2277d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    return (false);
22785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
22795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
22815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2282ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2283ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_process_peer_cfg_req
2284ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2285ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      This function is called to process the FCR options passed
2286ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  in the peer's configuration request.
2287ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2288ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          uint8_t - L2CAP_PEER_CFG_OK, L2CAP_PEER_CFG_UNACCEPTABLE,
2289ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                          or L2CAP_PEER_CFG_DISCONNECT.
2290ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2291ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2292d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenuint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
22935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
2294ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_ccb != NULL);
2295ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton    assert(p_cfg != NULL);
2296ca9ec85560ac0b43f2c65f08a7374a14b510e08eChris Manton
2297d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint16_t max_retrans_size;
2298d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t fcr_ok = L2CAP_PEER_CFG_OK;
22995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2300d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    p_ccb->p_lcb->w4_info_rsp = false;      /* Handles T61x SonyEricsson Bug in Info Request */
23015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2302a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati    L2CAP_TRACE_EVENT ("l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR mode:%d preferred: %u allowed:%u",
23035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode, p_ccb->ertm_info.preferred_mode,
23045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                        p_ccb->ertm_info.allowed_modes);
23055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* If Peer wants basic, we are done (accept it or disconnect) */
23075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)
23085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
23095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If we do not allow basic, disconnect */
23105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) )
23115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
23125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
23135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Need to negotiate if our modes are not the same */
23155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else if (p_cfg->fcr.mode != p_ccb->ertm_info.preferred_mode)
23165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
23175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If peer wants a mode that we don't support then retry our mode (ex. rtx/flc), OR
23185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ** If we want ERTM and they wanted streaming retry our mode.
23195738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        ** Note: If we have already determined they support our mode previously
23205738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        **       from their EXF mask.
23215738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        */
23225738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if ( (((1 << p_cfg->fcr.mode) & L2CAP_FCR_CHAN_OPT_ALL_MASK) == 0)
23235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            || (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE) )
23245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
23255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_cfg->fcr.mode = p_ccb->our_cfg.fcr.mode;
23265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_cfg->fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
23275738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_cfg->fcr.max_transmit = p_ccb->our_cfg.fcr.max_transmit;
23285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
23295738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
23305738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23315738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* If we wanted basic, then try to renegotiate it */
23325738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else if (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_BASIC_MODE)
23335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
23345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
23355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
23365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_cfg->fcr.rtrans_tout = p_cfg->fcr.mon_tout = p_cfg->fcr.mps = 0;
23375738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->our_cfg.fcr.rtrans_tout = p_ccb->our_cfg.fcr.mon_tout = p_ccb->our_cfg.fcr.mps = 0;
23385738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
23395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
23405738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23415738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Only other valid case is if they want ERTM and we wanted STM which should be
23425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project           accepted if we support it; otherwise the channel should be disconnected */
23435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else if ( (p_cfg->fcr.mode != L2CAP_FCR_ERTM_MODE)
23445738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project              || !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) )
23455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
23465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
23475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
23485738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
23495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* Configuration for FCR channels so make any adjustments and fwd to upper layer */
23515738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (fcr_ok == L2CAP_PEER_CFG_OK)
23525738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
23535738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* by default don't need to send params in the response */
2354d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        p_ccb->out_cfg_fcr_present = false;
23555738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23565738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Make any needed adjustments for the response to the peer */
23575738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_cfg->fcr_present && p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
23585738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        {
23595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Peer desires to bypass FCS check, and streaming or ERTM mode */
23605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_cfg->fcs_present)
23615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
23625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->peer_cfg.fcs = p_cfg->fcs;
23635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
23645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                if( p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
23655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                    p_ccb->bypass_fcs |= L2CAP_CFG_FCS_PEER;
23665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
23675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23681d5b85924df3a114efe6588e857d0de3eb47b1d2Pavlin Radoslavov            max_retrans_size = p_ccb->ertm_info.fcr_tx_buf_size - sizeof(BT_HDR)
23695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                                            - L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET - L2CAP_FCS_LEN;
23705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Ensure the MPS is not bigger than the MTU */
23725738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if ( (p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu) )
23735738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
23745738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_cfg->fcr.mps = p_ccb->peer_cfg.mtu;
2375d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p_ccb->out_cfg_fcr_present = true;
23765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
23775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            /* Ensure the MPS is not bigger than our retransmission buffer */
23795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            if (p_cfg->fcr.mps > max_retrans_size)
23805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2381a51c9d9d225e41fe36a0133f1c17fd981ea59c1dSharvil Nanavati                L2CAP_TRACE_DEBUG("CFG: Overriding MPS to %d (orig %d)", max_retrans_size, p_cfg->fcr.mps);
23825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_cfg->fcr.mps = max_retrans_size;
2384d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p_ccb->out_cfg_fcr_present = true;
23855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
23865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23878fe58875ce67c6e1099e7ba2339dcd2b979491b0Ganesh Ganapathi Batta            if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE || p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE)
23885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
23895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                /* Always respond with FCR ERTM parameters */
2390d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p_ccb->out_cfg_fcr_present = true;
23915738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            }
23925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
23935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Everything ok, so save the peer's adjusted fcr options */
23955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->peer_cfg.fcr = p_cfg->fcr;
23965738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
23975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_cfg->fcr_present)
23985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
23995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
24005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    else if (fcr_ok == L2CAP_PEER_CFG_UNACCEPTABLE)
24015738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
24025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* Allow peer only one retry for mode */
24035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        if (p_ccb->peer_cfg_already_rejected)
24045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
24055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        else
2406d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen            p_ccb->peer_cfg_already_rejected = true;
24075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
24085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    return (fcr_ok);
24105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
24115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#if (L2CAP_ERTM_STATS == TRUE)
24135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*******************************************************************************
2414ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2415ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Function         l2c_fcr_collect_ack_delay
2416ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2417ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Description      collect throughput, delay, queue size of waiting ack
2418ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2419ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Parameters
2420ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *                  tL2C_CCB
2421ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2422ee96a3c60fca590d38025925c072d264e06493c4Myles Watson * Returns          void
2423ee96a3c60fca590d38025925c072d264e06493c4Myles Watson *
2424ee96a3c60fca590d38025925c072d264e06493c4Myles Watson ******************************************************************************/
2425d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenstatic void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, uint8_t num_bufs_acked)
24265738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project{
2427d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint32_t index;
24285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    BT_HDR *p_buf;
2429d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t *p;
2430d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint32_t timestamp, delay;
2431d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t xx;
2432d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    uint8_t str[120];
24335738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    index = p_ccb->fcrb.ack_delay_avg_index;
24355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24365738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* update sum, max and min of waiting for ack queue size */
24371a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    p_ccb->fcrb.ack_q_count_avg[index] +=
24381a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
24395738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24401a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) > p_ccb->fcrb.ack_q_count_max[index])
24411a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        p_ccb->fcrb.ack_q_count_max[index] = fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
24425738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24431a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov    if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) < p_ccb->fcrb.ack_q_count_min[index])
24441a3844f933bd63c8a381371dabfb35c6a0249e3ePavlin Radoslavov        p_ccb->fcrb.ack_q_count_min[index] = fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
24455738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* update sum, max and min of round trip delay of acking */
2447577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    list_t *list = NULL;
2448577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    if (! fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
2449577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        list = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
2450577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov    if (list != NULL) {
2451577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov        for (const list_node_t *node = list_begin(list), xx = 0;
2452577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov             (node != list_end(list)) && (xx < num_bufs_acked);
2453577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov             node = list_next(node), xx++) {
2454577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            p_buf = list_node(node);
2455577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            /* adding up length of acked I-frames to get throughput */
2456577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            p_ccb->fcrb.throughput[index] += p_buf->len - 8;
2457577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov
2458577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            if ( xx == num_bufs_acked - 1 )
24595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            {
2460577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                /* get timestamp from tx I-frame that receiver is acking */
2461d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen                p = ((uint8_t *) (p_buf+1)) + p_buf->offset + p_buf->len;
2462577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
2463577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                {
2464577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                    p += L2CAP_FCS_LEN;
2465577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                }
24665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2467577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                STREAM_TO_UINT32(timestamp, p);
2468577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                delay = time_get_os_boottime_ms() - timestamp;
24695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
2470577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                p_ccb->fcrb.ack_delay_avg[index] += delay;
2471577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                if ( delay > p_ccb->fcrb.ack_delay_max[index] )
2472577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                    p_ccb->fcrb.ack_delay_max[index] = delay;
2473577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                if ( delay < p_ccb->fcrb.ack_delay_min[index] )
2474577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov                    p_ccb->fcrb.ack_delay_min[index] = delay;
2475577862e0d87891164a469afcecd1135bf04d1f6ePavlin Radoslavov            }
24765738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        }
24775738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
24785738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24795738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    p_ccb->fcrb.ack_delay_avg_count++;
24805738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24815738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    /* calculate average and initialize next avg, min and max */
24825738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    if (p_ccb->fcrb.ack_delay_avg_count > L2CAP_ERTM_STATS_AVG_NUM_SAMPLES)
24835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    {
24845738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_delay_avg_count = 0;
24855738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24865738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_q_count_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
24875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
24885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24895738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        /* calculate throughput */
2490c196f214c5ae349ec2022f8d3cbaf56910b3b9f8Pavlin Radoslavov        timestamp = time_get_os_boottime_ms();
2491c196f214c5ae349ec2022f8d3cbaf56910b3b9f8Pavlin Radoslavov        if (timestamp - p_ccb->fcrb.throughput_start > 0)
24925738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            p_ccb->fcrb.throughput[index] /= (timestamp - p_ccb->fcrb.throughput_start);
24935738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
24945738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.throughput_start = timestamp;
24955738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
249680d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV        snprintf(str, sizeof(str), "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u",
24975738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                index, p_ccb->fcrb.throughput[index],
24985738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.ack_delay_avg[index], p_ccb->fcrb.ack_delay_min[index], p_ccb->fcrb.ack_delay_max[index],
24995738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project                p_ccb->fcrb.ack_q_count_avg[index], p_ccb->fcrb.ack_q_count_min[index], p_ccb->fcrb.ack_q_count_max[index] );
25005738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
25010212487880be33e255d49f6e38dbb035d1f77750Sharvil Nanavati        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", str);
25025738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
25035738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        index = (index + 1) % L2CAP_ERTM_STATS_NUM_AVG;
25045738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_delay_avg_index = index;
25055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
25065738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_q_count_max[index] = 0;
25075738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_q_count_min[index] = 0xFFFFFFFF;
25085738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_q_count_avg[index] = 0;
25095738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
25105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
25115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_delay_max[index] = 0;
25125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_delay_min[index] = 0xFFFFFFFF;
25135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.ack_delay_avg[index] = 0;
25145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
25155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        p_ccb->fcrb.throughput[index] = 0;
25165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    }
25175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project}
25185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project#endif
2519