blob: 15d1817fe978623a01dd80980875d1308093fbb9 [file] [log] [blame]
/*
Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 and
only version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef __AMP_H
#define __AMP_H
/* AMP defaults */
#define A2MP_RSP_TIMEOUT (8000) /* 8 seconds */
/* A2MP Protocol */
/* A2MP command codes */
#define A2MP_COMMAND_REJ 0x01
#define A2MP_DISCOVER_REQ 0x02
#define A2MP_DISCOVER_RSP 0x03
#define A2MP_CHANGE_NOTIFY 0x04
#define A2MP_CHANGE_RSP 0x05
#define A2MP_GETINFO_REQ 0x06
#define A2MP_GETINFO_RSP 0x07
#define A2MP_GETAMPASSOC_REQ 0x08
#define A2MP_GETAMPASSOC_RSP 0x09
#define A2MP_CREATEPHYSLINK_REQ 0x0A
#define A2MP_CREATEPHYSLINK_RSP 0x0B
#define A2MP_DISCONNPHYSLINK_REQ 0x0C
#define A2MP_DISCONNPHYSLINK_RSP 0x0D
struct a2mp_cmd_hdr {
__u8 code;
__u8 ident;
__le16 len;
} __packed;
struct a2mp_cmd_rej {
__le16 reason;
} __packed;
struct a2mp_discover_req {
__le16 mtu;
__le16 ext_feat;
} __packed;
struct a2mp_cl {
__u8 id;
__u8 type;
__u8 status;
} __packed;
struct a2mp_discover_rsp {
__le16 mtu;
__le16 ext_feat;
struct a2mp_cl cl[0];
} __packed;
struct a2mp_getinfo_req {
__u8 id;
} __packed;
struct a2mp_getinfo_rsp {
__u8 id;
__u8 status;
__le32 total_bw;
__le32 max_bw;
__le32 min_latency;
__le16 pal_cap;
__le16 assoc_size;
} __packed;
struct a2mp_getampassoc_req {
__u8 id;
} __packed;
struct a2mp_getampassoc_rsp {
__u8 id;
__u8 status;
__u8 amp_assoc[0];
} __packed;
struct a2mp_createphyslink_req {
__u8 local_id;
__u8 remote_id;
__u8 amp_assoc[0];
} __packed;
struct a2mp_createphyslink_rsp {
__u8 local_id;
__u8 remote_id;
__u8 status;
} __packed;
struct a2mp_disconnphyslink_req {
__u8 local_id;
__u8 remote_id;
} __packed;
struct a2mp_disconnphyslink_rsp {
__u8 local_id;
__u8 remote_id;
__u8 status;
} __packed;
/* L2CAP-AMP module interface */
int amp_init(void);
void amp_exit(void);
/* L2CAP-AMP fixed channel interface */
void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb);
/* L2CAP-AMP link interface */
void amp_create_physical(struct l2cap_conn *conn, struct sock *sk);
void amp_accept_physical(struct l2cap_conn *conn, u8 id, struct sock *sk);
/* AMP manager internals */
struct amp_ctrl {
struct amp_mgr *mgr;
__u8 id;
__u8 type;
__u8 status;
__u32 total_bw;
__u32 max_bw;
__u32 min_latency;
__u16 pal_cap;
__u16 max_assoc_size;
};
struct amp_mgr {
struct list_head list;
__u8 discovered;
__u8 next_ident;
struct l2cap_conn *l2cap_conn;
struct socket *a2mp_sock;
struct list_head ctx_list;
rwlock_t ctx_list_lock;
struct amp_ctrl *ctrls; /* @@ TODO s.b. list of controllers */
struct sk_buff *skb;
__u8 connected;
};
/* AMP Manager signalling contexts */
#define AMP_GETAMPASSOC 1
#define AMP_CREATEPHYSLINK 2
#define AMP_ACCEPTPHYSLINK 3
#define AMP_CREATELOGLINK 4
#define AMP_ACCEPTLOGLINK 5
/* Get AMP Assoc sequence */
#define AMP_GAA_INIT 0
#define AMP_GAA_RLAA_COMPLETE 1
struct amp_gaa_state {
__u8 req_ident;
__u16 len_so_far;
__u8 *assoc;
};
/* Create Physical Link sequence */
#define AMP_CPL_INIT 0
#define AMP_CPL_DISC_RSP 1
#define AMP_CPL_GETINFO_RSP 2
#define AMP_CPL_GAA_RSP 3
#define AMP_CPL_CPL_STATUS 4
#define AMP_CPL_WRA_COMPLETE 5
#define AMP_CPL_CHANNEL_SELECT 6
#define AMP_CPL_RLA_COMPLETE 7
#define AMP_CPL_PL_COMPLETE 8
#define AMP_CPL_PL_CANCEL 9
struct amp_cpl_state {
__u8 remote_id;
__u16 max_len;
__u8 *remote_assoc;
__u8 *local_assoc;
__u16 len_so_far;
__u16 rem_len;
__u8 phy_handle;
};
/* Accept Physical Link sequence */
#define AMP_APL_INIT 0
#define AMP_APL_APL_STATUS 1
#define AMP_APL_WRA_COMPLETE 2
#define AMP_APL_PL_COMPLETE 3
struct amp_apl_state {
__u8 remote_id;
__u8 req_ident;
__u8 *remote_assoc;
__u16 len_so_far;
__u16 rem_len;
__u8 phy_handle;
};
/* Create/Accept Logical Link sequence */
#define AMP_LOG_INIT 0
#define AMP_LOG_LL_STATUS 1
#define AMP_LOG_LL_COMPLETE 2
struct amp_log_state {
__u8 remote_id;
};
/* Possible event types a context may wait for */
#define AMP_INIT 0x01
#define AMP_HCI_EVENT 0x02
#define AMP_HCI_CMD_CMPLT 0x04
#define AMP_HCI_CMD_STATUS 0x08
#define AMP_A2MP_RSP 0x10
#define AMP_KILLED 0x20
#define AMP_CANCEL 0x40
struct amp_ctx {
struct list_head list;
struct amp_mgr *mgr;
struct hci_dev *hdev;
__u8 type;
__u8 state;
union {
struct amp_gaa_state gaa;
struct amp_cpl_state cpl;
struct amp_apl_state apl;
} d;
__u8 evt_type;
__u8 evt_code;
__u16 opcode;
__u8 id;
__u8 rsp_ident;
struct sock *sk;
struct amp_ctx *deferred;
struct timer_list timer;
};
/* AMP work */
struct amp_work_pl_timeout {
struct work_struct work;
struct amp_ctrl *ctrl;
};
struct amp_work_ctx_timeout {
struct work_struct work;
struct amp_ctx *ctx;
};
struct amp_work_data_ready {
struct work_struct work;
struct sock *sk;
int bytes;
};
struct amp_work_state_change {
struct work_struct work;
struct sock *sk;
};
struct amp_work_conn_ind {
struct work_struct work;
struct hci_conn *hcon;
struct sk_buff *skb;
};
struct amp_work_create_physical {
struct work_struct work;
struct l2cap_conn *conn;
u8 id;
struct sock *sk;
};
struct amp_work_accept_physical {
struct work_struct work;
struct l2cap_conn *conn;
u8 id;
struct sock *sk;
};
struct amp_work_cmd_cmplt {
struct work_struct work;
struct hci_dev *hdev;
u16 opcode;
struct sk_buff *skb;
};
struct amp_work_cmd_status {
struct work_struct work;
struct hci_dev *hdev;
u16 opcode;
u8 status;
};
struct amp_work_event {
struct work_struct work;
struct hci_dev *hdev;
u8 event;
struct sk_buff *skb;
};
#endif /* __AMP_H */