#ifndef _L2CAP_H__
#define _L2CAP_H__

#include "base\bt_common.h"

#include "utils\simple_buf.h"
#include "utils\slist.h"

#include "common\addr.h"
#include "common\bt_buf.h"

#include "conn.h"



/** L2CAP PDU header size, used for buffer size calculations */
#define BT_L2CAP_HDR_SIZE 4

/** Maximum Transmission Unit (MTU) for an outgoing L2CAP PDU. */
// #define BT_L2CAP_TX_MTU (CONFIG_BT_BUF_ACL_TX_SIZE - BT_L2CAP_HDR_SIZE)

/** Maximum Transmission Unit (MTU) for an incoming L2CAP PDU. */
// #define BT_L2CAP_RX_MTU (CONFIG_BT_BUF_ACL_RX_SIZE - BT_L2CAP_HDR_SIZE)

/** @brief Helper to calculate needed buffer size for L2CAP PDUs.
 *         Useful for creating buffer pools.
 *
 *  @param mtu Needed L2CAP PDU MTU.
 *
 *  @return Needed buffer size to match the requested L2CAP PDU MTU.
 */
#define BT_L2CAP_BUF_SIZE(mtu) BT_BUF_ACL_SIZE(BT_L2CAP_HDR_SIZE + (mtu))

/** L2CAP SDU header size, used for buffer size calculations */
#define BT_L2CAP_SDU_HDR_SIZE 2

/** @brief Maximum Transmission Unit for an unsegmented outgoing L2CAP SDU.
 *
 *  The Maximum Transmission Unit for an outgoing L2CAP SDU when sent without
 *  segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU.
 *
 *  The MTU for outgoing L2CAP SDUs with segmentation is defined by the
 *  size of the application buffer pool.
 */
// #define BT_L2CAP_SDU_TX_MTU (BT_L2CAP_TX_MTU - BT_L2CAP_SDU_HDR_SIZE)

/** @brief Maximum Transmission Unit for an unsegmented incoming L2CAP SDU.
 *
 *  The Maximum Transmission Unit for an incoming L2CAP SDU when sent without
 *  segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU.
 *
 *  The MTU for incoming L2CAP SDUs with segmentation is defined by the
 *  size of the application buffer pool. The application will have to define
 *  an alloc_buf callback for the channel in order to support receiving
 *  segmented L2CAP SDUs.
 */
// #define BT_L2CAP_SDU_RX_MTU (BT_L2CAP_RX_MTU - BT_L2CAP_SDU_HDR_SIZE)

/**
 *
 *  @brief Helper to calculate needed buffer size for L2CAP SDUs.
 *         Useful for creating buffer pools.
 *
 *  @param mtu Required BT_L2CAP_*_SDU.
 *
 *  @return Needed buffer size to match the requested L2CAP SDU MTU.
 */
#define BT_L2CAP_SDU_BUF_SIZE(mtu) BT_L2CAP_BUF_SIZE(BT_L2CAP_SDU_HDR_SIZE + (mtu))























enum l2cap_conn_list_action
{
    BT_L2CAP_CHAN_LOOKUP,
    BT_L2CAP_CHAN_DETACH,
};

#define BT_L2CAP_CID_BR_SIG 0x0001
#define BT_L2CAP_CID_ATT    0x0004
#define BT_L2CAP_CID_LE_SIG 0x0005
#define BT_L2CAP_CID_SMP    0x0006
#define BT_L2CAP_CID_BR_SMP 0x0007

#define BT_L2CAP_PSM_RFCOMM 0x0003

struct bt_l2cap_hdr
{
    uint16_t len;
    uint16_t cid;
} __packed;

struct bt_l2cap_sig_hdr
{
    uint8_t code;
    uint8_t ident;
    uint16_t len;
} __packed;

#define BT_L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define BT_L2CAP_REJ_MTU_EXCEEDED   0x0001
#define BT_L2CAP_REJ_INVALID_CID    0x0002

#define BT_L2CAP_CMD_REJECT 0x01
struct bt_l2cap_cmd_reject
{
    uint16_t reason;
    uint8_t data[0];
} __packed;

struct bt_l2cap_cmd_reject_cid_data
{
    uint16_t scid;
    uint16_t dcid;
} __packed;

#define BT_L2CAP_CONN_REQ 0x02
struct bt_l2cap_conn_req
{
    uint16_t psm;
    uint16_t scid;
} __packed;

/* command statuses in response */
#define BT_L2CAP_CS_NO_INFO     0x0000
#define BT_L2CAP_CS_AUTHEN_PEND 0x0001

/* valid results in conn response on BR/EDR */
#define BT_L2CAP_BR_SUCCESS          0x0000
#define BT_L2CAP_BR_PENDING          0x0001
#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002
#define BT_L2CAP_BR_ERR_SEC_BLOCK    0x0003
#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004
#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006
#define BT_L2CAP_BR_ERR_SCID_IN_USE  0x0007

#define BT_L2CAP_CONN_RSP 0x03
struct bt_l2cap_conn_rsp
{
    uint16_t dcid;
    uint16_t scid;
    uint16_t result;
    uint16_t status;
} __packed;

#define BT_L2CAP_CONF_SUCCESS  0x0000
#define BT_L2CAP_CONF_UNACCEPT 0x0001
#define BT_L2CAP_CONF_REJECT   0x0002

#define BT_L2CAP_CONF_REQ 0x04
struct bt_l2cap_conf_req
{
    uint16_t dcid;
    uint16_t flags;
    uint8_t data[0];
} __packed;

#define BT_L2CAP_CONF_RSP 0x05
struct bt_l2cap_conf_rsp
{
    uint16_t scid;
    uint16_t flags;
    uint16_t result;
    uint8_t data[0];
} __packed;

/* Option type used by MTU config request data */
#define BT_L2CAP_CONF_OPT_MTU 0x01
/* Options bits selecting most significant bit (hint) in type field */
#define BT_L2CAP_CONF_HINT    0x80
#define BT_L2CAP_CONF_MASK    0x7f

struct bt_l2cap_conf_opt
{
    uint8_t type;
    uint8_t len;
    uint8_t data[0];
} __packed;

#define BT_L2CAP_DISCONN_REQ 0x06
struct bt_l2cap_disconn_req
{
    uint16_t dcid;
    uint16_t scid;
} __packed;

#define BT_L2CAP_DISCONN_RSP 0x07
struct bt_l2cap_disconn_rsp
{
    uint16_t dcid;
    uint16_t scid;
} __packed;

#define BT_L2CAP_INFO_FEAT_MASK  0x0002
#define BT_L2CAP_INFO_FIXED_CHAN 0x0003

#define BT_L2CAP_INFO_REQ 0x0a
struct bt_l2cap_info_req
{
    uint16_t type;
} __packed;

/* info result */
#define BT_L2CAP_INFO_SUCCESS 0x0000
#define BT_L2CAP_INFO_NOTSUPP 0x0001

#define BT_L2CAP_INFO_RSP 0x0b
struct bt_l2cap_info_rsp
{
    uint16_t type;
    uint16_t result;
    uint8_t data[0];
} __packed;

#define BT_L2CAP_CONN_PARAM_REQ 0x12
struct bt_l2cap_conn_param_req
{
    uint16_t min_interval;
    uint16_t max_interval;
    uint16_t latency;
    uint16_t timeout;
} __packed;

#define BT_L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define BT_L2CAP_CONN_PARAM_REJECTED 0x0001

#define BT_L2CAP_CONN_PARAM_RSP 0x13
struct bt_l2cap_conn_param_rsp
{
    uint16_t result;
} __packed;

#define BT_L2CAP_LE_CONN_REQ 0x14
struct bt_l2cap_le_conn_req
{
    uint16_t psm;
    uint16_t scid;
    uint16_t mtu;
    uint16_t mps;
    uint16_t credits;
} __packed;

/* valid results in conn response on LE */
#define BT_L2CAP_LE_SUCCESS             0x0000
#define BT_L2CAP_LE_ERR_PSM_NOT_SUPP    0x0002
#define BT_L2CAP_LE_ERR_NO_RESOURCES    0x0004
#define BT_L2CAP_LE_ERR_AUTHENTICATION  0x0005
#define BT_L2CAP_LE_ERR_AUTHORIZATION   0x0006
#define BT_L2CAP_LE_ERR_KEY_SIZE        0x0007
#define BT_L2CAP_LE_ERR_ENCRYPTION      0x0008
#define BT_L2CAP_LE_ERR_INVALID_SCID    0x0009
#define BT_L2CAP_LE_ERR_SCID_IN_USE     0x000A
#define BT_L2CAP_LE_ERR_UNACCEPT_PARAMS 0x000B
#define BT_L2CAP_LE_ERR_INVALID_PARAMS  0x000C

#define BT_L2CAP_LE_CONN_RSP 0x15
struct bt_l2cap_le_conn_rsp
{
    uint16_t dcid;
    uint16_t mtu;
    uint16_t mps;
    uint16_t credits;
    uint16_t result;
} __packed;

#define BT_L2CAP_LE_CREDITS 0x16
struct bt_l2cap_le_credits
{
    uint16_t cid;
    uint16_t credits;
} __packed;

#define BT_L2CAP_ECRED_CONN_REQ 0x17
struct bt_l2cap_ecred_conn_req
{
    uint16_t psm;
    uint16_t mtu;
    uint16_t mps;
    uint16_t credits;
    uint16_t scid[0];
} __packed;

#define BT_L2CAP_ECRED_CONN_RSP 0x18
struct bt_l2cap_ecred_conn_rsp
{
    uint16_t mtu;
    uint16_t mps;
    uint16_t credits;
    uint16_t result;
    uint16_t dcid[0];
} __packed;

#define L2CAP_ECRED_CHAN_MAX_PER_REQ 5

#define BT_L2CAP_ECRED_RECONF_REQ 0x19
struct bt_l2cap_ecred_reconf_req
{
    uint16_t mtu;
    uint16_t mps;
    uint16_t scid[0];
} __packed;

#define BT_L2CAP_RECONF_SUCCESS        0x0000
#define BT_L2CAP_RECONF_INVALID_MTU    0x0001
#define BT_L2CAP_RECONF_INVALID_MPS    0x0002
#define BT_L2CAP_RECONF_INVALID_CID    0x0003
#define BT_L2CAP_RECONF_OTHER_UNACCEPT 0x0004

#define BT_L2CAP_ECRED_RECONF_RSP 0x1a
struct bt_l2cap_ecred_reconf_rsp
{
    uint16_t result;
} __packed;


/* Perform connection parameter update request */
int bt_l2cap_update_conn_param(struct bt_conn *conn, const struct bt_le_conn_param *param);

/* Initialize L2CAP and supported channels */
void bt_l2cap_init(void);

/* Prepare an L2CAP PDU to be sent over a connection */
simple_buf_t *bt_l2cap_create_pdu(simple_buf_pool_t *pool, size_t reserve);

/* Send L2CAP PDU over a connection
 *
 * Buffer ownership is transferred to stack in case of success.
 */
int bt_l2cap_send(struct bt_conn *conn, uint16_t cid, simple_buf_t *buf);

/* Receive a new L2CAP PDU from a connection */
void bt_l2cap_recv(struct bt_conn *conn, simple_buf_t *buf, bool complete);

/* Notify L2CAP channels of a new connection */
void bt_l2cap_connected(struct bt_conn *conn);

/* Notify L2CAP channels of a disconnect event */
void bt_l2cap_disconnected(struct bt_conn *conn);

#if defined (CONFIG_BT_SMP)
/*
 * Notify L2CAP channels of a change in encryption state passing additionally
 * HCI status of performed security procedure.
 */
void bt_l2cap_security_changed(struct bt_conn *conn, uint8_t hci_status);
#endif

#endif