diff --git a/[refs] b/[refs]
index b2c5f47efa41..6544f57ff8ce 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: a0019bca04029d25a8bbbaaaf28487e6ccd7878e
+refs/heads/master: ee60833a4f887a09e87be52cdf1247a4963b0aef
diff --git a/trunk/drivers/bluetooth/ath3k.c b/trunk/drivers/bluetooth/ath3k.c
index 41dadacd3d15..a126e614601f 100644
--- a/trunk/drivers/bluetooth/ath3k.c
+++ b/trunk/drivers/bluetooth/ath3k.c
@@ -39,8 +39,6 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3002) },
- /* Atheros AR9285 Malbec with sflash firmware */
- { USB_DEVICE(0x03F0, 0x311D) },
{ } /* Terminating entry */
};
@@ -108,7 +106,6 @@ static int ath3k_probe(struct usb_interface *intf,
{
const struct firmware *firmware;
struct usb_device *udev = interface_to_usbdev(intf);
- int ret;
BT_DBG("intf %p id %p", intf, id);
@@ -119,10 +116,13 @@ static int ath3k_probe(struct usb_interface *intf,
return -EIO;
}
- ret = ath3k_load_firmware(udev, firmware);
+ if (ath3k_load_firmware(udev, firmware)) {
+ release_firmware(firmware);
+ return -EIO;
+ }
release_firmware(firmware);
- return ret;
+ return 0;
}
static void ath3k_disconnect(struct usb_interface *intf)
diff --git a/trunk/drivers/bluetooth/btusb.c b/trunk/drivers/bluetooth/btusb.c
index 4cefa91e6c34..1da773f899a2 100644
--- a/trunk/drivers/bluetooth/btusb.c
+++ b/trunk/drivers/bluetooth/btusb.c
@@ -102,9 +102,6 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
- /* Atheros AR9285 Malbec with sflash firmware */
- { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
-
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
diff --git a/trunk/drivers/net/wireless/wl12xx/acx.c b/trunk/drivers/net/wireless/wl12xx/acx.c
index afdc601aa7ea..84d94b259900 100644
--- a/trunk/drivers/net/wireless/wl12xx/acx.c
+++ b/trunk/drivers/net/wireless/wl12xx/acx.c
@@ -1476,3 +1476,33 @@ int wl1271_acx_max_tx_retry(struct wl1271 *wl)
kfree(acx);
return ret;
}
+
+int wl1271_acx_config_ps(struct wl1271 *wl)
+{
+ struct wl1271_acx_config_ps *config_ps;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx config ps");
+
+ config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL);
+ if (!config_ps) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ config_ps->exit_retries = wl->conf.conn.psm_exit_retries;
+ config_ps->enter_retries = wl->conf.conn.psm_entry_retries;
+ config_ps->null_data_rate = cpu_to_le32(wl->basic_rate);
+
+ ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps,
+ sizeof(*config_ps));
+
+ if (ret < 0) {
+ wl1271_warning("acx config ps failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(config_ps);
+ return ret;
+}
diff --git a/trunk/drivers/net/wireless/wl12xx/acx.h b/trunk/drivers/net/wireless/wl12xx/acx.h
index 4bbaf04f434e..5bc0ca97bec4 100644
--- a/trunk/drivers/net/wireless/wl12xx/acx.h
+++ b/trunk/drivers/net/wireless/wl12xx/acx.h
@@ -1136,6 +1136,15 @@ struct wl1271_acx_max_tx_retry {
u8 padding_1[2];
} __packed;
+struct wl1271_acx_config_ps {
+ struct acx_header header;
+
+ u8 exit_retries;
+ u8 enter_retries;
+ u8 padding[2];
+ __le32 null_data_rate;
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1200,6 +1209,7 @@ enum {
DOT11_RTS_THRESHOLD = 0x1013,
DOT11_GROUP_ADDRESS_TBL = 0x1014,
ACX_PM_CONFIG = 0x1016,
+ ACX_CONFIG_PS = 0x1017,
MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
@@ -1269,5 +1279,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
+int wl1271_acx_config_ps(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
diff --git a/trunk/drivers/net/wireless/wl12xx/conf.h b/trunk/drivers/net/wireless/wl12xx/conf.h
index fd1dac9ab4db..c81aecd755e5 100644
--- a/trunk/drivers/net/wireless/wl12xx/conf.h
+++ b/trunk/drivers/net/wireless/wl12xx/conf.h
@@ -959,6 +959,14 @@ struct conf_conn_settings {
*/
u8 psm_entry_retries;
+ /*
+ * Specifies the maximum number of times to try PSM exit if it fails
+ * (if sending the appropriate null-func message fails.)
+ *
+ * Range 0 - 255
+ */
+ u8 psm_exit_retries;
+
/*
* Specifies the maximum number of times to try transmit the PSM entry
* null-func frame for each PSM entry attempt
diff --git a/trunk/drivers/net/wireless/wl12xx/main.c b/trunk/drivers/net/wireless/wl12xx/main.c
index 254b7daccee1..522bb09c9535 100644
--- a/trunk/drivers/net/wireless/wl12xx/main.c
+++ b/trunk/drivers/net/wireless/wl12xx/main.c
@@ -256,6 +256,7 @@ static struct conf_drv_settings default_conf = {
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 10,
.psm_entry_retries = 5,
+ .psm_exit_retries = 255,
.psm_entry_nullfunc_retries = 3,
.psm_entry_hangover_period = 1,
.keep_alive_interval = 55000,
diff --git a/trunk/include/net/bluetooth/bluetooth.h b/trunk/include/net/bluetooth/bluetooth.h
index ed7d775337e0..0c5e72503b77 100644
--- a/trunk/include/net/bluetooth/bluetooth.h
+++ b/trunk/include/net/bluetooth/bluetooth.h
@@ -64,11 +64,6 @@ struct bt_security {
#define BT_DEFER_SETUP 7
-#define BT_FLUSHABLE 8
-
-#define BT_FLUSHABLE_OFF 0
-#define BT_FLUSHABLE_ON 1
-
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
diff --git a/trunk/include/net/bluetooth/hci.h b/trunk/include/net/bluetooth/hci.h
index 4bee030e4b52..29a7a8ca0438 100644
--- a/trunk/include/net/bluetooth/hci.h
+++ b/trunk/include/net/bluetooth/hci.h
@@ -76,14 +76,6 @@ enum {
HCI_INQUIRY,
HCI_RAW,
-
- HCI_SETUP,
- HCI_AUTO_OFF,
- HCI_MGMT,
- HCI_PAIRABLE,
- HCI_SERVICE_CACHE,
- HCI_LINK_KEYS,
- HCI_DEBUG_KEYS,
};
/* HCI ioctl defines */
@@ -158,7 +150,6 @@ enum {
#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
/* ACL flags */
-#define ACL_START_NO_FLUSH 0x00
#define ACL_CONT 0x01
#define ACL_START 0x02
#define ACL_ACTIVE_BCAST 0x04
@@ -192,25 +183,17 @@ enum {
#define LMP_PSCHEME 0x02
#define LMP_PCONTROL 0x04
-#define LMP_RSSI_INQ 0x40
#define LMP_ESCO 0x80
#define LMP_EV4 0x01
#define LMP_EV5 0x02
-#define LMP_LE 0x40
#define LMP_SNIFF_SUBR 0x02
-#define LMP_PAUSE_ENC 0x04
#define LMP_EDR_ESCO_2M 0x20
#define LMP_EDR_ESCO_3M 0x40
#define LMP_EDR_3S_ESCO 0x80
-#define LMP_EXT_INQ 0x01
#define LMP_SIMPLE_PAIR 0x08
-#define LMP_NO_FLUSH 0x40
-
-#define LMP_LSTO 0x01
-#define LMP_INQ_TX_PWR 0x02
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
@@ -309,19 +292,11 @@ struct hci_cp_pin_code_reply {
__u8 pin_len;
__u8 pin_code[16];
} __packed;
-struct hci_rp_pin_code_reply {
- __u8 status;
- bdaddr_t bdaddr;
-} __packed;
#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
struct hci_cp_pin_code_neg_reply {
bdaddr_t bdaddr;
} __packed;
-struct hci_rp_pin_code_neg_reply {
- __u8 status;
- bdaddr_t bdaddr;
-} __packed;
#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
struct hci_cp_change_conn_ptype {
@@ -402,20 +377,6 @@ struct hci_cp_reject_sync_conn_req {
__u8 reason;
} __packed;
-#define HCI_OP_IO_CAPABILITY_REPLY 0x042b
-struct hci_cp_io_capability_reply {
- bdaddr_t bdaddr;
- __u8 capability;
- __u8 oob_data;
- __u8 authentication;
-} __packed;
-
-#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434
-struct hci_cp_io_capability_neg_reply {
- bdaddr_t bdaddr;
- __u8 reason;
-} __packed;
-
#define HCI_OP_SNIFF_MODE 0x0803
struct hci_cp_sniff_mode {
__le16 handle;
@@ -513,12 +474,6 @@ struct hci_cp_set_event_flt {
#define HCI_CONN_SETUP_AUTO_OFF 0x01
#define HCI_CONN_SETUP_AUTO_ON 0x02
-#define HCI_OP_DELETE_STORED_LINK_KEY 0x0c12
-struct hci_cp_delete_stored_link_key {
- bdaddr_t bdaddr;
- __u8 delete_all;
-} __packed;
-
#define HCI_OP_WRITE_LOCAL_NAME 0x0c13
struct hci_cp_write_local_name {
__u8 name[248];
@@ -582,8 +537,6 @@ struct hci_cp_host_buffer_size {
__le16 sco_max_pkt;
} __packed;
-#define HCI_OP_WRITE_INQUIRY_MODE 0x0c45
-
#define HCI_OP_READ_SSP_MODE 0x0c55
struct hci_rp_read_ssp_mode {
__u8 status;
@@ -595,8 +548,6 @@ struct hci_cp_write_ssp_mode {
__u8 mode;
} __packed;
-#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
-
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version {
__u8 status;
@@ -882,14 +833,6 @@ struct hci_ev_io_capa_request {
bdaddr_t bdaddr;
} __packed;
-#define HCI_EV_IO_CAPA_REPLY 0x32
-struct hci_ev_io_capa_reply {
- bdaddr_t bdaddr;
- __u8 capability;
- __u8 oob_data;
- __u8 authentication;
-} __packed;
-
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete {
__u8 status;
diff --git a/trunk/include/net/bluetooth/hci_core.h b/trunk/include/net/bluetooth/hci_core.h
index 6163bff6fa91..d2cf88407690 100644
--- a/trunk/include/net/bluetooth/hci_core.h
+++ b/trunk/include/net/bluetooth/hci_core.h
@@ -66,21 +66,6 @@ struct bdaddr_list {
struct list_head list;
bdaddr_t bdaddr;
};
-
-struct bt_uuid {
- struct list_head list;
- u8 uuid[16];
- u8 svc_hint;
-};
-
-struct link_key {
- struct list_head list;
- bdaddr_t bdaddr;
- u8 type;
- u8 val[16];
- u8 pin_len;
-};
-
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -95,18 +80,13 @@ struct hci_dev {
bdaddr_t bdaddr;
__u8 dev_name[248];
__u8 dev_class[3];
- __u8 major_class;
- __u8 minor_class;
__u8 features[8];
__u8 commands[64];
__u8 ssp_mode;
__u8 hci_ver;
__u16 hci_rev;
- __u8 lmp_ver;
__u16 manufacturer;
- __le16 lmp_subver;
__u16 voice_setting;
- __u8 io_capability;
__u16 pkt_type;
__u16 esco_type;
@@ -134,10 +114,6 @@ struct hci_dev {
struct workqueue_struct *workqueue;
- struct work_struct power_on;
- struct work_struct power_off;
- struct timer_list off_timer;
-
struct tasklet_struct cmd_task;
struct tasklet_struct rx_task;
struct tasklet_struct tx_task;
@@ -153,17 +129,12 @@ struct hci_dev {
wait_queue_head_t req_wait_q;
__u32 req_status;
__u32 req_result;
-
- __u16 init_last_cmd;
+ __u16 req_last_cmd;
struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
struct list_head blacklist;
- struct list_head uuids;
-
- struct list_head link_keys;
-
struct hci_dev_stats stat;
struct sk_buff_head driver_init;
@@ -214,16 +185,10 @@ struct hci_conn {
__u8 auth_type;
__u8 sec_level;
__u8 pending_sec_level;
- __u8 pin_length;
- __u8 io_capability;
__u8 power_save;
__u16 disc_timeout;
unsigned long pend;
- __u8 remote_cap;
- __u8 remote_oob;
- __u8 remote_auth;
-
unsigned int sent;
struct sk_buff_head data_q;
@@ -472,16 +437,6 @@ int hci_inquiry(void __user *arg);
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_blacklist_clear(struct hci_dev *hdev);
-int hci_uuids_clear(struct hci_dev *hdev);
-
-int hci_link_keys_clear(struct hci_dev *hdev);
-struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
- u8 *key, u8 type, u8 pin_len);
-int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
-
-void hci_del_off_timer(struct hci_dev *hdev);
-
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
@@ -503,7 +458,6 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
-#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
/* ----- HCI protocols ----- */
struct hci_proto {
@@ -706,24 +660,12 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
/* ----- HCI Sockets ----- */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
- struct sock *skip_sk);
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
/* Management interface */
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_index_added(u16 index);
int mgmt_index_removed(u16 index);
-int mgmt_powered(u16 index, u8 powered);
-int mgmt_discoverable(u16 index, u8 discoverable);
-int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
-int mgmt_disconnect_failed(u16 index);
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/trunk/include/net/bluetooth/l2cap.h b/trunk/include/net/bluetooth/l2cap.h
index 75ef0b2948f9..7ad25ca60ec0 100644
--- a/trunk/include/net/bluetooth/l2cap.h
+++ b/trunk/include/net/bluetooth/l2cap.h
@@ -327,7 +327,6 @@ struct l2cap_pinfo {
__u8 sec_level;
__u8 role_switch;
__u8 force_reliable;
- __u8 flushable;
__u8 conf_req[64];
__u8 conf_len;
@@ -424,37 +423,6 @@ static inline int l2cap_tx_window_full(struct sock *sk)
#define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
-extern int disable_ertm;
-extern const struct proto_ops l2cap_sock_ops;
-extern struct bt_sock_list l2cap_sk_list;
-
-int l2cap_init_sockets(void);
-void l2cap_cleanup_sockets(void);
-
-u8 l2cap_get_ident(struct l2cap_conn *conn);
-void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
-int l2cap_build_conf_req(struct sock *sk, void *data);
-int __l2cap_wait_ack(struct sock *sk);
-
-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
-int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len);
-void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
-void l2cap_streaming_send(struct sock *sk);
-int l2cap_ertm_send(struct sock *sk);
-
-void l2cap_sock_set_timer(struct sock *sk, long timeout);
-void l2cap_sock_clear_timer(struct sock *sk);
-void __l2cap_sock_close(struct sock *sk, int reason);
-void l2cap_sock_kill(struct sock *sk);
-void l2cap_sock_init(struct sock *sk, struct sock *parent);
-struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
- int proto, gfp_t prio);
-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
-void l2cap_chan_del(struct sock *sk, int err);
-int l2cap_do_connect(struct sock *sk);
-
void l2cap_load(void);
#endif /* __L2CAP_H */
diff --git a/trunk/include/net/bluetooth/mgmt.h b/trunk/include/net/bluetooth/mgmt.h
index 44ac55c85079..ca29c1367ffd 100644
--- a/trunk/include/net/bluetooth/mgmt.h
+++ b/trunk/include/net/bluetooth/mgmt.h
@@ -47,7 +47,6 @@ struct mgmt_rp_read_info {
__le16 index;
__u8 type;
__u8 powered;
- __u8 connectable;
__u8 discoverable;
__u8 pairable;
__u8 sec_mode;
@@ -59,107 +58,6 @@ struct mgmt_rp_read_info {
__u16 hci_rev;
} __packed;
-struct mgmt_mode {
- __le16 index;
- __u8 val;
-} __packed;
-
-#define MGMT_OP_SET_POWERED 0x0005
-
-#define MGMT_OP_SET_DISCOVERABLE 0x0006
-
-#define MGMT_OP_SET_CONNECTABLE 0x0007
-
-#define MGMT_OP_SET_PAIRABLE 0x0008
-
-#define MGMT_OP_ADD_UUID 0x0009
-struct mgmt_cp_add_uuid {
- __le16 index;
- __u8 uuid[16];
- __u8 svc_hint;
-} __packed;
-
-#define MGMT_OP_REMOVE_UUID 0x000A
-struct mgmt_cp_remove_uuid {
- __le16 index;
- __u8 uuid[16];
-} __packed;
-
-#define MGMT_OP_SET_DEV_CLASS 0x000B
-struct mgmt_cp_set_dev_class {
- __le16 index;
- __u8 major;
- __u8 minor;
-} __packed;
-
-#define MGMT_OP_SET_SERVICE_CACHE 0x000C
-struct mgmt_cp_set_service_cache {
- __le16 index;
- __u8 enable;
-} __packed;
-
-struct mgmt_key_info {
- bdaddr_t bdaddr;
- u8 type;
- u8 val[16];
- u8 pin_len;
-} __packed;
-
-#define MGMT_OP_LOAD_KEYS 0x000D
-struct mgmt_cp_load_keys {
- __le16 index;
- __u8 debug_keys;
- __le16 key_count;
- struct mgmt_key_info keys[0];
-} __packed;
-
-#define MGMT_OP_REMOVE_KEY 0x000E
-struct mgmt_cp_remove_key {
- __le16 index;
- bdaddr_t bdaddr;
- __u8 disconnect;
-} __packed;
-
-#define MGMT_OP_DISCONNECT 0x000F
-struct mgmt_cp_disconnect {
- __le16 index;
- bdaddr_t bdaddr;
-} __packed;
-struct mgmt_rp_disconnect {
- __le16 index;
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_OP_GET_CONNECTIONS 0x0010
-struct mgmt_cp_get_connections {
- __le16 index;
-} __packed;
-struct mgmt_rp_get_connections {
- __le16 index;
- __le16 conn_count;
- bdaddr_t conn[0];
-} __packed;
-
-#define MGMT_OP_PIN_CODE_REPLY 0x0011
-struct mgmt_cp_pin_code_reply {
- __le16 index;
- bdaddr_t bdaddr;
- __u8 pin_len;
- __u8 pin_code[16];
-} __packed;
-
-#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0012
-struct mgmt_cp_pin_code_neg_reply {
- __le16 index;
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_OP_SET_IO_CAPABILITY 0x0013
-struct mgmt_cp_set_io_capability {
- __le16 index;
- __u8 io_capability;
-} __packed;
-
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -187,43 +85,3 @@ struct mgmt_ev_index_added {
struct mgmt_ev_index_removed {
__le16 index;
} __packed;
-
-#define MGMT_EV_POWERED 0x0006
-
-#define MGMT_EV_DISCOVERABLE 0x0007
-
-#define MGMT_EV_CONNECTABLE 0x0008
-
-#define MGMT_EV_PAIRABLE 0x0009
-
-#define MGMT_EV_NEW_KEY 0x000A
-struct mgmt_ev_new_key {
- __le16 index;
- struct mgmt_key_info key;
- __u8 old_key_type;
-} __packed;
-
-#define MGMT_EV_CONNECTED 0x000B
-struct mgmt_ev_connected {
- __le16 index;
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_EV_DISCONNECTED 0x000C
-struct mgmt_ev_disconnected {
- __le16 index;
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_EV_CONNECT_FAILED 0x000D
-struct mgmt_ev_connect_failed {
- __le16 index;
- bdaddr_t bdaddr;
- __u8 status;
-} __packed;
-
-#define MGMT_EV_PIN_CODE_REQUEST 0x000E
-struct mgmt_ev_pin_code_request {
- __le16 index;
- bdaddr_t bdaddr;
-} __packed;
diff --git a/trunk/net/bluetooth/Kconfig b/trunk/net/bluetooth/Kconfig
index e45eae66eaf3..ed371684c133 100644
--- a/trunk/net/bluetooth/Kconfig
+++ b/trunk/net/bluetooth/Kconfig
@@ -27,9 +27,9 @@ menuconfig BT
compile it as module (bluetooth).
To use Linux Bluetooth subsystem, you will need several user-space
- utilities like hciconfig and bluetoothd. These utilities and updates
- to Bluetooth kernel modules are provided in the BlueZ packages. For
- more information, see .
+ utilities like hciconfig and hcid. These utilities and updates to
+ Bluetooth kernel modules are provided in the BlueZ packages.
+ For more information, see .
config BT_L2CAP
tristate "L2CAP protocol support"
diff --git a/trunk/net/bluetooth/Makefile b/trunk/net/bluetooth/Makefile
index 339b42932b33..250f954f0213 100644
--- a/trunk/net/bluetooth/Makefile
+++ b/trunk/net/bluetooth/Makefile
@@ -11,4 +11,3 @@ obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
-l2cap-y := l2cap_core.o l2cap_sock.o
diff --git a/trunk/net/bluetooth/af_bluetooth.c b/trunk/net/bluetooth/af_bluetooth.c
index 2abfe2f30453..c4cf3f595004 100644
--- a/trunk/net/bluetooth/af_bluetooth.c
+++ b/trunk/net/bluetooth/af_bluetooth.c
@@ -199,15 +199,14 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
BT_DBG("parent %p", parent);
- local_bh_disable();
list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
- bh_lock_sock(sk);
+ lock_sock(sk);
/* FIXME: Is this check still needed */
if (sk->sk_state == BT_CLOSED) {
- bh_unlock_sock(sk);
+ release_sock(sk);
bt_accept_unlink(sk);
continue;
}
@@ -217,16 +216,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
bt_accept_unlink(sk);
if (newsock)
sock_graft(sk, newsock);
-
- bh_unlock_sock(sk);
- local_bh_enable();
+ release_sock(sk);
return sk;
}
- bh_unlock_sock(sk);
+ release_sock(sk);
}
- local_bh_enable();
-
return NULL;
}
EXPORT_SYMBOL(bt_accept_dequeue);
@@ -245,8 +240,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (flags & (MSG_OOB))
return -EOPNOTSUPP;
- skb = skb_recv_datagram(sk, flags, noblock, &err);
- if (!skb) {
+ if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
if (sk->sk_shutdown & RCV_SHUTDOWN)
return 0;
return err;
@@ -329,8 +323,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
if (copied >= target)
break;
- err = sock_error(sk);
- if (err)
+ if ((err = sock_error(sk)) != 0)
break;
if (sk->sk_shutdown & RCV_SHUTDOWN)
break;
diff --git a/trunk/net/bluetooth/cmtp/capi.c b/trunk/net/bluetooth/cmtp/capi.c
index 67cff810c77d..3487cfe74aec 100644
--- a/trunk/net/bluetooth/cmtp/capi.c
+++ b/trunk/net/bluetooth/cmtp/capi.c
@@ -155,8 +155,7 @@ static void cmtp_send_interopmsg(struct cmtp_session *session,
BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
- skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
- if (!skb) {
+ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for interoperability packet");
return;
}
diff --git a/trunk/net/bluetooth/cmtp/core.c b/trunk/net/bluetooth/cmtp/core.c
index 2cee71a714c4..8e5f292529ac 100644
--- a/trunk/net/bluetooth/cmtp/core.c
+++ b/trunk/net/bluetooth/cmtp/core.c
@@ -115,8 +115,7 @@ static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const
size = (skb) ? skb->len + count : count;
- nskb = alloc_skb(size, GFP_ATOMIC);
- if (!nskb) {
+ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for CAPI message");
return;
}
@@ -217,8 +216,7 @@ static void cmtp_process_transmit(struct cmtp_session *session)
BT_DBG("session %p", session);
- nskb = alloc_skb(session->mtu, GFP_ATOMIC);
- if (!nskb) {
+ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for new frame");
return;
}
@@ -226,8 +224,7 @@ static void cmtp_process_transmit(struct cmtp_session *session)
while ((skb = skb_dequeue(&session->transmit))) {
struct cmtp_scb *scb = (void *) skb->cb;
- tail = session->mtu - nskb->len;
- if (tail < 5) {
+ if ((tail = (session->mtu - nskb->len)) < 5) {
cmtp_send_frame(session, nskb->data, nskb->len);
skb_trim(nskb, 0);
tail = session->mtu;
diff --git a/trunk/net/bluetooth/hci_conn.c b/trunk/net/bluetooth/hci_conn.c
index 42dc39f25b72..99cd8d9d891b 100644
--- a/trunk/net/bluetooth/hci_conn.c
+++ b/trunk/net/bluetooth/hci_conn.c
@@ -234,7 +234,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;
conn->auth_type = HCI_AT_GENERAL_BONDING;
- conn->io_capability = hdev->io_capability;
conn->power_save = 1;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
diff --git a/trunk/net/bluetooth/hci_core.c b/trunk/net/bluetooth/hci_core.c
index 2f003224d2ea..9c4541bc488a 100644
--- a/trunk/net/bluetooth/hci_core.c
+++ b/trunk/net/bluetooth/hci_core.c
@@ -50,8 +50,6 @@
#include
#include
-#define AUTO_OFF_TIMEOUT 2000
-
static void hci_cmd_task(unsigned long arg);
static void hci_rx_task(unsigned long arg);
static void hci_tx_task(unsigned long arg);
@@ -97,10 +95,11 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
{
BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result);
- /* If this is the init phase check if the completed command matches
- * the last init command, and if not just return.
- */
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd)
+ /* If the request has set req_last_cmd (typical for multi-HCI
+ * command requests) check if the completed command matches
+ * this, and if not just return. Single HCI command requests
+ * typically leave req_last_cmd as 0 */
+ if (hdev->req_last_cmd && cmd != hdev->req_last_cmd)
return;
if (hdev->req_status == HCI_REQ_PEND) {
@@ -157,7 +156,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
break;
}
- hdev->req_status = hdev->req_result = 0;
+ hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0;
BT_DBG("%s end: err %d", hdev->name, err);
@@ -190,7 +189,6 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
{
- struct hci_cp_delete_stored_link_key cp;
struct sk_buff *skb;
__le16 param;
__u8 flt_type;
@@ -254,13 +252,15 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
flt_type = HCI_FLT_CLEAR_ALL;
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+ /* Page timeout ~20 secs */
+ param = cpu_to_le16(0x8000);
+ hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, ¶m);
+
/* Connection accept timeout ~20 secs */
param = cpu_to_le16(0x7d00);
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.delete_all = 1;
- hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+ hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT;
}
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@@ -429,8 +429,7 @@ int hci_inquiry(void __user *arg)
if (copy_from_user(&ir, ptr, sizeof(ir)))
return -EFAULT;
- hdev = hci_dev_get(ir.dev_id);
- if (!hdev)
+ if (!(hdev = hci_dev_get(ir.dev_id)))
return -ENODEV;
hci_dev_lock_bh(hdev);
@@ -490,8 +489,7 @@ int hci_dev_open(__u16 dev)
struct hci_dev *hdev;
int ret = 0;
- hdev = hci_dev_get(dev);
- if (!hdev)
+ if (!(hdev = hci_dev_get(dev)))
return -ENODEV;
BT_DBG("%s %p", hdev->name, hdev);
@@ -523,7 +521,6 @@ int hci_dev_open(__u16 dev)
if (!test_bit(HCI_RAW, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
set_bit(HCI_INIT, &hdev->flags);
- hdev->init_last_cmd = 0;
//__hci_request(hdev, hci_reset_req, 0, HZ);
ret = __hci_request(hdev, hci_init_req, 0,
@@ -536,8 +533,6 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
- if (!test_bit(HCI_SETUP, &hdev->flags))
- mgmt_powered(hdev->id, 1);
} else {
/* Init failed, cleanup */
tasklet_kill(&hdev->rx_task);
@@ -619,8 +614,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */
hdev->close(hdev);
- mgmt_powered(hdev->id, 0);
-
/* Clear flags */
hdev->flags = 0;
@@ -800,17 +793,9 @@ int hci_get_dev_list(void __user *arg)
read_lock_bh(&hci_dev_list_lock);
list_for_each(p, &hci_dev_list) {
struct hci_dev *hdev;
-
hdev = list_entry(p, struct hci_dev, list);
-
- hci_del_off_timer(hdev);
-
- if (!test_bit(HCI_MGMT, &hdev->flags))
- set_bit(HCI_PAIRABLE, &hdev->flags);
-
(dr + n)->dev_id = hdev->id;
(dr + n)->dev_opt = hdev->flags;
-
if (++n >= dev_num)
break;
}
@@ -838,11 +823,6 @@ int hci_get_dev_info(void __user *arg)
if (!hdev)
return -ENODEV;
- hci_del_off_timer(hdev);
-
- if (!test_bit(HCI_MGMT, &hdev->flags))
- set_bit(HCI_PAIRABLE, &hdev->flags);
-
strcpy(di.name, hdev->name);
di.bdaddr = hdev->bdaddr;
di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
@@ -911,149 +891,6 @@ void hci_free_dev(struct hci_dev *hdev)
}
EXPORT_SYMBOL(hci_free_dev);
-static void hci_power_on(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
-
- BT_DBG("%s", hdev->name);
-
- if (hci_dev_open(hdev->id) < 0)
- return;
-
- if (test_bit(HCI_AUTO_OFF, &hdev->flags))
- mod_timer(&hdev->off_timer,
- jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
-
- if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
- mgmt_index_added(hdev->id);
-}
-
-static void hci_power_off(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_close(hdev->id);
-}
-
-static void hci_auto_off(unsigned long data)
-{
- struct hci_dev *hdev = (struct hci_dev *) data;
-
- BT_DBG("%s", hdev->name);
-
- clear_bit(HCI_AUTO_OFF, &hdev->flags);
-
- queue_work(hdev->workqueue, &hdev->power_off);
-}
-
-void hci_del_off_timer(struct hci_dev *hdev)
-{
- BT_DBG("%s", hdev->name);
-
- clear_bit(HCI_AUTO_OFF, &hdev->flags);
- del_timer(&hdev->off_timer);
-}
-
-int hci_uuids_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->uuids) {
- struct bt_uuid *uuid;
-
- uuid = list_entry(p, struct bt_uuid, list);
-
- list_del(p);
- kfree(uuid);
- }
-
- return 0;
-}
-
-int hci_link_keys_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->link_keys) {
- struct link_key *key;
-
- key = list_entry(p, struct link_key, list);
-
- list_del(p);
- kfree(key);
- }
-
- return 0;
-}
-
-struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct list_head *p;
-
- list_for_each(p, &hdev->link_keys) {
- struct link_key *k;
-
- k = list_entry(p, struct link_key, list);
-
- if (bacmp(bdaddr, &k->bdaddr) == 0)
- return k;
- }
-
- return NULL;
-}
-
-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
- u8 *val, u8 type, u8 pin_len)
-{
- struct link_key *key, *old_key;
- u8 old_key_type;
-
- old_key = hci_find_link_key(hdev, bdaddr);
- if (old_key) {
- old_key_type = old_key->type;
- key = old_key;
- } else {
- old_key_type = 0xff;
- key = kzalloc(sizeof(*key), GFP_ATOMIC);
- if (!key)
- return -ENOMEM;
- list_add(&key->list, &hdev->link_keys);
- }
-
- BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
-
- bacpy(&key->bdaddr, bdaddr);
- memcpy(key->val, val, 16);
- key->type = type;
- key->pin_len = pin_len;
-
- if (new_key)
- mgmt_new_key(hdev->id, key, old_key_type);
-
- if (type == 0x06)
- key->type = old_key_type;
-
- return 0;
-}
-
-int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct link_key *key;
-
- key = hci_find_link_key(hdev, bdaddr);
- if (!key)
- return -ENOENT;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&key->list);
- kfree(key);
-
- return 0;
-}
-
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1086,7 +923,6 @@ int hci_register_dev(struct hci_dev *hdev)
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
hdev->esco_type = (ESCO_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
- hdev->io_capability = 0x03; /* No Input No Output */
hdev->idle_timeout = 0;
hdev->sniff_max_interval = 800;
@@ -1112,14 +948,6 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->blacklist);
- INIT_LIST_HEAD(&hdev->uuids);
-
- INIT_LIST_HEAD(&hdev->link_keys);
-
- INIT_WORK(&hdev->power_on, hci_power_on);
- INIT_WORK(&hdev->power_off, hci_power_off);
- setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
-
memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
atomic_set(&hdev->promisc, 0);
@@ -1141,10 +969,7 @@ int hci_register_dev(struct hci_dev *hdev)
}
}
- set_bit(HCI_AUTO_OFF, &hdev->flags);
- set_bit(HCI_SETUP, &hdev->flags);
- queue_work(hdev->workqueue, &hdev->power_on);
-
+ mgmt_index_added(hdev->id);
hci_notify(hdev, HCI_DEV_REG);
return id;
@@ -1174,10 +999,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
for (i = 0; i < NUM_REASSEMBLY; i++)
kfree_skb(hdev->reassembly[i]);
- if (!test_bit(HCI_INIT, &hdev->flags) &&
- !test_bit(HCI_SETUP, &hdev->flags))
- mgmt_index_removed(hdev->id);
-
+ mgmt_index_removed(hdev->id);
hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {
@@ -1191,8 +1013,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_dev_lock_bh(hdev);
hci_blacklist_clear(hdev);
- hci_uuids_clear(hdev);
- hci_link_keys_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
@@ -1493,7 +1313,7 @@ static int hci_send_frame(struct sk_buff *skb)
/* Time stamp */
__net_timestamp(skb);
- hci_send_to_sock(hdev, skb, NULL);
+ hci_send_to_sock(hdev, skb);
}
/* Get rid of skb owner, prior to sending to the driver. */
@@ -1529,9 +1349,6 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->init_last_cmd = opcode;
-
skb_queue_tail(&hdev->cmd_q, skb);
tasklet_schedule(&hdev->cmd_task);
@@ -1578,7 +1395,7 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
+ hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
list = skb_shinfo(skb)->frag_list;
if (!list) {
@@ -1596,15 +1413,12 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
spin_lock_bh(&conn->data_q.lock);
__skb_queue_tail(&conn->data_q, skb);
-
- flags &= ~ACL_START;
- flags |= ACL_CONT;
do {
skb = list; list = list->next;
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
+ hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1886,7 +1700,7 @@ static void hci_rx_task(unsigned long arg)
while ((skb = skb_dequeue(&hdev->rx_q))) {
if (atomic_read(&hdev->promisc)) {
/* Send copy to the sockets */
- hci_send_to_sock(hdev, skb, NULL);
+ hci_send_to_sock(hdev, skb);
}
if (test_bit(HCI_RAW, &hdev->flags)) {
@@ -1942,11 +1756,7 @@ static void hci_cmd_task(unsigned long arg)
}
/* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt)) {
- skb = skb_dequeue(&hdev->cmd_q);
- if (!skb)
- return;
-
+ if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
diff --git a/trunk/net/bluetooth/hci_event.c b/trunk/net/bluetooth/hci_event.c
index cee46cbe7aeb..a290854fdaa6 100644
--- a/trunk/net/bluetooth/hci_event.c
+++ b/trunk/net/bluetooth/hci_event.c
@@ -274,24 +274,15 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (!status) {
__u8 param = *((__u8 *) sent);
- int old_pscan, old_iscan;
- old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
- old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+ clear_bit(HCI_PSCAN, &hdev->flags);
+ clear_bit(HCI_ISCAN, &hdev->flags);
- if (param & SCAN_INQUIRY) {
+ if (param & SCAN_INQUIRY)
set_bit(HCI_ISCAN, &hdev->flags);
- if (!old_iscan)
- mgmt_discoverable(hdev->id, 1);
- } else if (old_iscan)
- mgmt_discoverable(hdev->id, 0);
- if (param & SCAN_PAGE) {
+ if (param & SCAN_PAGE)
set_bit(HCI_PSCAN, &hdev->flags);
- if (!old_pscan)
- mgmt_connectable(hdev->id, 1);
- } else if (old_pscan)
- mgmt_connectable(hdev->id, 0);
}
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
@@ -424,115 +415,6 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
hdev->ssp_mode = *((__u8 *) sent);
}
-static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
-{
- if (hdev->features[6] & LMP_EXT_INQ)
- return 2;
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- return 1;
-
- if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
- hdev->lmp_subver == 0x0757)
- return 1;
-
- if (hdev->manufacturer == 15) {
- if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
- return 1;
- }
-
- if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
- hdev->lmp_subver == 0x1805)
- return 1;
-
- return 0;
-}
-
-static void hci_setup_inquiry_mode(struct hci_dev *hdev)
-{
- u8 mode;
-
- mode = hci_get_inquiry_mode(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
-}
-
-static void hci_setup_event_mask(struct hci_dev *hdev)
-{
- /* The second byte is 0xff instead of 0x9f (two reserved bits
- * disabled) since a Broadcom 1.2 dongle doesn't respond to the
- * command otherwise */
- u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
- /* Events for 1.2 and newer controllers */
- if (hdev->lmp_ver > 1) {
- events[4] |= 0x01; /* Flow Specification Complete */
- events[4] |= 0x02; /* Inquiry Result with RSSI */
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
- }
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- events[4] |= 0x04; /* Inquiry Result with RSSI */
-
- if (hdev->features[5] & LMP_SNIFF_SUBR)
- events[5] |= 0x20; /* Sniff Subrating */
-
- if (hdev->features[5] & LMP_PAUSE_ENC)
- events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
- if (hdev->features[6] & LMP_EXT_INQ)
- events[5] |= 0x40; /* Extended Inquiry Result */
-
- if (hdev->features[6] & LMP_NO_FLUSH)
- events[7] |= 0x01; /* Enhanced Flush Complete */
-
- if (hdev->features[7] & LMP_LSTO)
- events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
- events[6] |= 0x01; /* IO Capability Request */
- events[6] |= 0x02; /* IO Capability Response */
- events[6] |= 0x04; /* User Confirmation Request */
- events[6] |= 0x08; /* User Passkey Request */
- events[6] |= 0x10; /* Remote OOB Data Request */
- events[6] |= 0x20; /* Simple Pairing Complete */
- events[7] |= 0x04; /* User Passkey Notification */
- events[7] |= 0x08; /* Keypress Notification */
- events[7] |= 0x10; /* Remote Host Supported
- * Features Notification */
- }
-
- if (hdev->features[4] & LMP_LE)
- events[7] |= 0x20; /* LE Meta-Event */
-
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
-}
-
-static void hci_setup(struct hci_dev *hdev)
-{
- hci_setup_event_mask(hdev);
-
- if (hdev->lmp_ver > 1)
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
- u8 mode = 0x01;
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
- }
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- hci_setup_inquiry_mode(hdev);
-
- if (hdev->features[7] & LMP_INQ_TX_PWR)
- hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-}
-
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_local_version *rp = (void *) skb->data;
@@ -544,34 +426,11 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
hdev->hci_ver = rp->hci_ver;
hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
- hdev->lmp_ver = rp->lmp_ver;
hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
- hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
hdev->manufacturer,
hdev->hci_ver, hdev->hci_rev);
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hci_setup(hdev);
-}
-
-static void hci_setup_link_policy(struct hci_dev *hdev)
-{
- u16 link_policy = 0;
-
- if (hdev->features[0] & LMP_RSWITCH)
- link_policy |= HCI_LP_RSWITCH;
- if (hdev->features[0] & LMP_HOLD)
- link_policy |= HCI_LP_HOLD;
- if (hdev->features[0] & LMP_SNIFF)
- link_policy |= HCI_LP_SNIFF;
- if (hdev->features[1] & LMP_PARK)
- link_policy |= HCI_LP_PARK;
-
- link_policy = cpu_to_le16(link_policy);
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY,
- sizeof(link_policy), &link_policy);
}
static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
@@ -581,15 +440,9 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
- goto done;
+ return;
memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
-
- if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
- hci_setup_link_policy(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
}
static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
@@ -695,88 +548,6 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
}
-static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
-}
-
-static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status);
-}
-
-static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status);
-}
-
-static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status);
-}
-
-static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
-}
-
-static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_pin_code_reply *rp = (void *) skb->data;
- struct hci_cp_pin_code_reply *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (test_bit(HCI_MGMT, &hdev->flags))
- mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
-
- if (rp->status != 0)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
- if (!cp)
- return;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (conn)
- conn->pin_length = cp->pin_len;
-}
-
-static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (test_bit(HCI_MGMT, &hdev->flags))
- mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
- rp->status);
-}
-
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -851,14 +622,11 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev);
acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
+ if (acl && (sco = acl->link)) {
+ sco->state = BT_CLOSED;
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
+ hci_proto_connect_cfm(sco, status);
+ hci_conn_del(sco);
}
hci_dev_unlock(hdev);
@@ -1040,14 +808,11 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev);
acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
+ if (acl && (sco = acl->link)) {
+ sco->state = BT_CLOSED;
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
+ hci_proto_connect_cfm(sco, status);
+ hci_conn_del(sco);
}
hci_dev_unlock(hdev);
@@ -1177,7 +942,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn->state = BT_CONFIG;
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- mgmt_connected(hdev->id, &ev->bdaddr);
} else
conn->state = BT_CONNECTED;
@@ -1206,11 +970,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
sizeof(cp), &cp);
}
- } else {
+ } else
conn->state = BT_CLOSED;
- if (conn->type == ACL_LINK)
- mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
- }
if (conn->type == ACL_LINK)
hci_sco_setup(conn, ev->status);
@@ -1307,26 +1068,19 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG("%s status %d", hdev->name, ev->status);
- if (ev->status) {
- mgmt_disconnect_failed(hdev->id);
+ if (ev->status)
return;
- }
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- conn->state = BT_CLOSED;
-
- if (conn->type == ACL_LINK)
- mgmt_disconnected(hdev->id, &conn->dst);
+ if (conn) {
+ conn->state = BT_CLOSED;
- hci_proto_disconn_cfm(conn, ev->reason);
- hci_conn_del(conn);
+ hci_proto_disconn_cfm(conn, ev->reason);
+ hci_conn_del(conn);
+ }
-unlock:
hci_dev_unlock(hdev);
}
@@ -1639,34 +1393,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_write_ca_timeout(hdev, skb);
break;
- case HCI_OP_DELETE_STORED_LINK_KEY:
- hci_cc_delete_stored_link_key(hdev, skb);
- break;
-
- case HCI_OP_SET_EVENT_MASK:
- hci_cc_set_event_mask(hdev, skb);
- break;
-
- case HCI_OP_WRITE_INQUIRY_MODE:
- hci_cc_write_inquiry_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_INQ_RSP_TX_POWER:
- hci_cc_read_inq_rsp_tx_power(hdev, skb);
- break;
-
- case HCI_OP_SET_EVENT_FLT:
- hci_cc_set_event_flt(hdev, skb);
- break;
-
- case HCI_OP_PIN_CODE_REPLY:
- hci_cc_pin_code_reply(hdev, skb);
- break;
-
- case HCI_OP_PIN_CODE_NEG_REPLY:
- hci_cc_pin_code_neg_reply(hdev, skb);
- break;
-
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
@@ -1733,11 +1459,6 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_exit_sniff_mode(hdev, ev->status);
break;
- case HCI_OP_DISCONNECT:
- if (ev->status != 0)
- mgmt_disconnect_failed(hdev->id);
- break;
-
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
@@ -1865,72 +1586,18 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
hci_conn_put(conn);
}
- if (!test_bit(HCI_PAIRABLE, &hdev->flags))
- hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
-
- if (test_bit(HCI_MGMT, &hdev->flags))
- mgmt_pin_code_request(hdev->id, &ev->bdaddr);
-
hci_dev_unlock(hdev);
}
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_link_key_req *ev = (void *) skb->data;
- struct hci_cp_link_key_reply cp;
- struct hci_conn *conn;
- struct link_key *key;
-
BT_DBG("%s", hdev->name);
-
- if (!test_bit(HCI_LINK_KEYS, &hdev->flags))
- return;
-
- hci_dev_lock(hdev);
-
- key = hci_find_link_key(hdev, &ev->bdaddr);
- if (!key) {
- BT_DBG("%s link key not found for %s", hdev->name,
- batostr(&ev->bdaddr));
- goto not_found;
- }
-
- BT_DBG("%s found key type %u for %s", hdev->name, key->type,
- batostr(&ev->bdaddr));
-
- if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) {
- BT_DBG("%s ignoring debug key", hdev->name);
- goto not_found;
- }
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-
- if (key->type == 0x04 && conn && conn->auth_type != 0xff &&
- (conn->auth_type & 0x01)) {
- BT_DBG("%s ignoring unauthenticated key", hdev->name);
- goto not_found;
- }
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- memcpy(cp.link_key, key->val, 16);
-
- hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
-
- hci_dev_unlock(hdev);
-
- return;
-
-not_found:
- hci_send_cmd(hdev, HCI_OP_LINK_KEY_NEG_REPLY, 6, &ev->bdaddr);
- hci_dev_unlock(hdev);
}
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_link_key_notify *ev = (void *) skb->data;
struct hci_conn *conn;
- u8 pin_len = 0;
BT_DBG("%s", hdev->name);
@@ -1940,14 +1607,9 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
if (conn) {
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- pin_len = conn->pin_length;
hci_conn_put(conn);
}
- if (test_bit(HCI_LINK_KEYS, &hdev->flags))
- hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key,
- ev->key_type, pin_len);
-
hci_dev_unlock(hdev);
}
@@ -2204,25 +1866,6 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
hci_dev_unlock(hdev);
}
-static inline u8 hci_get_auth_req(struct hci_conn *conn)
-{
- /* If remote requests dedicated bonding follow that lead */
- if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
- /* If both remote and local IO capabilities allow MITM
- * protection then require it, otherwise don't */
- if (conn->remote_cap == 0x03 || conn->io_capability == 0x03)
- return 0x02;
- else
- return 0x03;
- }
-
- /* If remote requests no-bonding follow that lead */
- if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
- return 0x00;
-
- return conn->auth_type;
-}
-
static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_io_capa_request *ev = (void *) skb->data;
@@ -2233,59 +1876,9 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- hci_conn_hold(conn);
-
- if (!test_bit(HCI_MGMT, &hdev->flags))
- goto unlock;
-
- if (test_bit(HCI_PAIRABLE, &hdev->flags) ||
- (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
- struct hci_cp_io_capability_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.capability = conn->io_capability;
- cp.oob_data = 0;
- cp.authentication = hci_get_auth_req(conn);
-
- hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
- sizeof(cp), &cp);
- } else {
- struct hci_cp_io_capability_neg_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.reason = 0x16; /* Pairing not allowed */
-
- hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
- sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_io_capa_reply *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- hci_conn_hold(conn);
-
- conn->remote_cap = ev->capability;
- conn->remote_oob = ev->oob_data;
- conn->remote_auth = ev->authentication;
+ if (conn)
+ hci_conn_hold(conn);
-unlock:
hci_dev_unlock(hdev);
}
@@ -2449,10 +2042,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_io_capa_request_evt(hdev, skb);
break;
- case HCI_EV_IO_CAPA_REPLY:
- hci_io_capa_reply_evt(hdev, skb);
- break;
-
case HCI_EV_SIMPLE_PAIR_COMPLETE:
hci_simple_pair_complete_evt(hdev, skb);
break;
@@ -2494,6 +2083,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
skb->dev = (void *) hdev;
- hci_send_to_sock(hdev, skb, NULL);
+ hci_send_to_sock(hdev, skb);
kfree_skb(skb);
}
diff --git a/trunk/net/bluetooth/hci_sock.c b/trunk/net/bluetooth/hci_sock.c
index d50e96136608..29827c77f6ce 100644
--- a/trunk/net/bluetooth/hci_sock.c
+++ b/trunk/net/bluetooth/hci_sock.c
@@ -85,8 +85,7 @@ static struct bt_sock_list hci_sk_list = {
};
/* Send frame to RAW socket */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
- struct sock *skip_sk)
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
{
struct sock *sk;
struct hlist_node *node;
@@ -98,9 +97,6 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
struct hci_filter *flt;
struct sk_buff *nskb;
- if (sk == skip_sk)
- continue;
-
if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
continue;
diff --git a/trunk/net/bluetooth/hci_sysfs.c b/trunk/net/bluetooth/hci_sysfs.c
index 23471dd9ee2f..5fce3d6d07b4 100644
--- a/trunk/net/bluetooth/hci_sysfs.c
+++ b/trunk/net/bluetooth/hci_sysfs.c
@@ -461,56 +461,6 @@ static const struct file_operations blacklist_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-
-static void print_bt_uuid(struct seq_file *f, u8 *uuid)
-{
- u32 data0, data4;
- u16 data1, data2, data3, data5;
-
- memcpy(&data0, &uuid[0], 4);
- memcpy(&data1, &uuid[4], 2);
- memcpy(&data2, &uuid[6], 2);
- memcpy(&data3, &uuid[8], 2);
- memcpy(&data4, &uuid[10], 4);
- memcpy(&data5, &uuid[14], 2);
-
- seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
- ntohl(data0), ntohs(data1), ntohs(data2),
- ntohs(data3), ntohl(data4), ntohs(data5));
-}
-
-static int uuids_show(struct seq_file *f, void *p)
-{
- struct hci_dev *hdev = f->private;
- struct list_head *l;
-
- hci_dev_lock_bh(hdev);
-
- list_for_each(l, &hdev->uuids) {
- struct bt_uuid *uuid;
-
- uuid = list_entry(l, struct bt_uuid, list);
-
- print_bt_uuid(f, uuid->uuid);
- }
-
- hci_dev_unlock_bh(hdev);
-
- return 0;
-}
-
-static int uuids_open(struct inode *inode, struct file *file)
-{
- return single_open(file, uuids_show, inode->i_private);
-}
-
-static const struct file_operations uuids_fops = {
- .open = uuids_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
int hci_register_sysfs(struct hci_dev *hdev)
{
struct device *dev = &hdev->dev;
@@ -543,8 +493,6 @@ int hci_register_sysfs(struct hci_dev *hdev)
debugfs_create_file("blacklist", 0444, hdev->debugfs,
hdev, &blacklist_fops);
- debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
-
return 0;
}
diff --git a/trunk/net/bluetooth/hidp/core.c b/trunk/net/bluetooth/hidp/core.c
index e0de92952f32..29544c21f4b5 100644
--- a/trunk/net/bluetooth/hidp/core.c
+++ b/trunk/net/bluetooth/hidp/core.c
@@ -157,8 +157,7 @@ static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
session->leds = newleds;
- skb = alloc_skb(3, GFP_ATOMIC);
- if (!skb) {
+ if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
}
@@ -251,8 +250,7 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
BT_DBG("session %p data %p size %d", session, data, size);
- skb = alloc_skb(size + 1, GFP_ATOMIC);
- if (!skb) {
+ if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
}
@@ -285,8 +283,7 @@ static int hidp_queue_report(struct hidp_session *session,
BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
- skb = alloc_skb(size + 1, GFP_ATOMIC);
- if (!skb) {
+ if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
}
diff --git a/trunk/net/bluetooth/l2cap_core.c b/trunk/net/bluetooth/l2cap.c
similarity index 78%
rename from trunk/net/bluetooth/l2cap_core.c
rename to trunk/net/bluetooth/l2cap.c
index ba7f9da68998..7550abb0c96a 100644
--- a/trunk/net/bluetooth/l2cap_core.c
+++ b/trunk/net/bluetooth/l2cap.c
@@ -24,7 +24,7 @@
SOFTWARE IS DISCLAIMED.
*/
-/* Bluetooth L2CAP core. */
+/* Bluetooth L2CAP core and sockets. */
#include
@@ -57,24 +57,77 @@
#define VERSION "2.15"
-int disable_ertm;
+static int disable_ertm;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
+static const struct proto_ops l2cap_sock_ops;
+
static struct workqueue_struct *_busy_wq;
-struct bt_sock_list l2cap_sk_list = {
+static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
static void l2cap_busy_work(struct work_struct *work);
+static void __l2cap_sock_close(struct sock *sk, int reason);
+static void l2cap_sock_close(struct sock *sk);
+static void l2cap_sock_kill(struct sock *sk);
+
+static int l2cap_build_conf_req(struct sock *sk, void *data);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
+/* ---- L2CAP timers ---- */
+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
+{
+ BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
+ sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
+}
+
+static void l2cap_sock_clear_timer(struct sock *sk)
+{
+ BT_DBG("sock %p state %d", sk, sk->sk_state);
+ sk_stop_timer(sk, &sk->sk_timer);
+}
+
+static void l2cap_sock_timeout(unsigned long arg)
+{
+ struct sock *sk = (struct sock *) arg;
+ int reason;
+
+ BT_DBG("sock %p state %d", sk, sk->sk_state);
+
+ bh_lock_sock(sk);
+
+ if (sock_owned_by_user(sk)) {
+ /* sk is owned by user. Try again later */
+ l2cap_sock_set_timer(sk, HZ / 5);
+ bh_unlock_sock(sk);
+ sock_put(sk);
+ return;
+ }
+
+ if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
+ reason = ECONNREFUSED;
+ else if (sk->sk_state == BT_CONNECT &&
+ l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
+ reason = ECONNREFUSED;
+ else
+ reason = ETIMEDOUT;
+
+ __l2cap_sock_close(sk, reason);
+
+ bh_unlock_sock(sk);
+
+ l2cap_sock_kill(sk);
+ sock_put(sk);
+}
+
/* ---- L2CAP channels ---- */
static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
{
@@ -205,7 +258,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
/* Delete channel.
* Must be called on the locked socket. */
-void l2cap_chan_del(struct sock *sk, int err)
+static void l2cap_chan_del(struct sock *sk, int err)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct sock *parent = bt_sk(sk)->parent;
@@ -295,7 +348,7 @@ static inline int l2cap_check_security(struct sock *sk)
auth_type);
}
-u8 l2cap_get_ident(struct l2cap_conn *conn)
+static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
{
u8 id;
@@ -317,22 +370,16 @@ u8 l2cap_get_ident(struct l2cap_conn *conn)
return id;
}
-void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
{
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
- u8 flags;
BT_DBG("code 0x%2.2x", code);
if (!skb)
return;
- if (lmp_no_flush_capable(conn->hcon->hdev))
- flags = ACL_START_NO_FLUSH;
- else
- flags = ACL_START;
-
- hci_send_acl(conn->hcon, skb, flags);
+ hci_send_acl(conn->hcon, skb, 0);
}
static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
@@ -342,7 +389,6 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
struct l2cap_conn *conn = pi->conn;
struct sock *sk = (struct sock *)pi;
int count, hlen = L2CAP_HDR_SIZE + 2;
- u8 flags;
if (sk->sk_state != BT_CONNECTED)
return;
@@ -379,12 +425,7 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
put_unaligned_le16(fcs, skb_put(skb, 2));
}
- if (lmp_no_flush_capable(conn->hcon->hdev))
- flags = ACL_START_NO_FLUSH;
- else
- flags = ACL_START;
-
- hci_send_acl(pi->conn->hcon, skb, flags);
+ hci_send_acl(pi->conn->hcon, skb, 0);
}
static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
@@ -455,7 +496,7 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
}
}
-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
+static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
{
struct l2cap_disconn_req req;
@@ -706,6 +747,17 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
}
/* ---- Socket interface ---- */
+static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
+{
+ struct sock *sk;
+ struct hlist_node *node;
+ sk_for_each(sk, node, &l2cap_sk_list.head)
+ if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
+ goto found;
+ sk = NULL;
+found:
+ return sk;
+}
/* Find socket with psm and source bdaddr.
* Returns closest match.
@@ -737,7 +789,276 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
return node ? sk : sk1;
}
-int l2cap_do_connect(struct sock *sk)
+static void l2cap_sock_destruct(struct sock *sk)
+{
+ BT_DBG("sk %p", sk);
+
+ skb_queue_purge(&sk->sk_receive_queue);
+ skb_queue_purge(&sk->sk_write_queue);
+}
+
+static void l2cap_sock_cleanup_listen(struct sock *parent)
+{
+ struct sock *sk;
+
+ BT_DBG("parent %p", parent);
+
+ /* Close not yet accepted channels */
+ while ((sk = bt_accept_dequeue(parent, NULL)))
+ l2cap_sock_close(sk);
+
+ parent->sk_state = BT_CLOSED;
+ sock_set_flag(parent, SOCK_ZAPPED);
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+static void l2cap_sock_kill(struct sock *sk)
+{
+ if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
+ return;
+
+ BT_DBG("sk %p state %d", sk, sk->sk_state);
+
+ /* Kill poor orphan */
+ bt_sock_unlink(&l2cap_sk_list, sk);
+ sock_set_flag(sk, SOCK_DEAD);
+ sock_put(sk);
+}
+
+static void __l2cap_sock_close(struct sock *sk, int reason)
+{
+ BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
+
+ switch (sk->sk_state) {
+ case BT_LISTEN:
+ l2cap_sock_cleanup_listen(sk);
+ break;
+
+ case BT_CONNECTED:
+ case BT_CONFIG:
+ if (sk->sk_type == SOCK_SEQPACKET ||
+ sk->sk_type == SOCK_STREAM) {
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+
+ l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+ l2cap_send_disconn_req(conn, sk, reason);
+ } else
+ l2cap_chan_del(sk, reason);
+ break;
+
+ case BT_CONNECT2:
+ if (sk->sk_type == SOCK_SEQPACKET ||
+ sk->sk_type == SOCK_STREAM) {
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct l2cap_conn_rsp rsp;
+ __u16 result;
+
+ if (bt_sk(sk)->defer_setup)
+ result = L2CAP_CR_SEC_BLOCK;
+ else
+ result = L2CAP_CR_BAD_PSM;
+
+ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+ rsp.result = cpu_to_le16(result);
+ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+ L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+ } else
+ l2cap_chan_del(sk, reason);
+ break;
+
+ case BT_CONNECT:
+ case BT_DISCONN:
+ l2cap_chan_del(sk, reason);
+ break;
+
+ default:
+ sock_set_flag(sk, SOCK_ZAPPED);
+ break;
+ }
+}
+
+/* Must be called on unlocked socket. */
+static void l2cap_sock_close(struct sock *sk)
+{
+ l2cap_sock_clear_timer(sk);
+ lock_sock(sk);
+ __l2cap_sock_close(sk, ECONNRESET);
+ release_sock(sk);
+ l2cap_sock_kill(sk);
+}
+
+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+
+ BT_DBG("sk %p", sk);
+
+ if (parent) {
+ sk->sk_type = parent->sk_type;
+ bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
+
+ pi->imtu = l2cap_pi(parent)->imtu;
+ pi->omtu = l2cap_pi(parent)->omtu;
+ pi->conf_state = l2cap_pi(parent)->conf_state;
+ pi->mode = l2cap_pi(parent)->mode;
+ pi->fcs = l2cap_pi(parent)->fcs;
+ pi->max_tx = l2cap_pi(parent)->max_tx;
+ pi->tx_win = l2cap_pi(parent)->tx_win;
+ pi->sec_level = l2cap_pi(parent)->sec_level;
+ pi->role_switch = l2cap_pi(parent)->role_switch;
+ pi->force_reliable = l2cap_pi(parent)->force_reliable;
+ } else {
+ pi->imtu = L2CAP_DEFAULT_MTU;
+ pi->omtu = 0;
+ if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
+ pi->mode = L2CAP_MODE_ERTM;
+ pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ } else {
+ pi->mode = L2CAP_MODE_BASIC;
+ }
+ pi->max_tx = L2CAP_DEFAULT_MAX_TX;
+ pi->fcs = L2CAP_FCS_CRC16;
+ pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+ pi->sec_level = BT_SECURITY_LOW;
+ pi->role_switch = 0;
+ pi->force_reliable = 0;
+ }
+
+ /* Default config options */
+ pi->conf_len = 0;
+ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ skb_queue_head_init(TX_QUEUE(sk));
+ skb_queue_head_init(SREJ_QUEUE(sk));
+ skb_queue_head_init(BUSY_QUEUE(sk));
+ INIT_LIST_HEAD(SREJ_LIST(sk));
+}
+
+static struct proto l2cap_proto = {
+ .name = "L2CAP",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct l2cap_pinfo)
+};
+
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+{
+ struct sock *sk;
+
+ sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
+ if (!sk)
+ return NULL;
+
+ sock_init_data(sock, sk);
+ INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+
+ sk->sk_destruct = l2cap_sock_destruct;
+ sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
+
+ sock_reset_flag(sk, SOCK_ZAPPED);
+
+ sk->sk_protocol = proto;
+ sk->sk_state = BT_OPEN;
+
+ setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
+
+ bt_sock_link(&l2cap_sk_list, sk);
+ return sk;
+}
+
+static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
+ int kern)
+{
+ struct sock *sk;
+
+ BT_DBG("sock %p", sock);
+
+ sock->state = SS_UNCONNECTED;
+
+ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
+ sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
+ return -ESOCKTNOSUPPORT;
+
+ if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
+ return -EPERM;
+
+ sock->ops = &l2cap_sock_ops;
+
+ sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC);
+ if (!sk)
+ return -ENOMEM;
+
+ l2cap_sock_init(sk, NULL);
+ return 0;
+}
+
+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_l2 la;
+ int len, err = 0;
+
+ BT_DBG("sk %p", sk);
+
+ if (!addr || addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
+ memset(&la, 0, sizeof(la));
+ len = min_t(unsigned int, sizeof(la), alen);
+ memcpy(&la, addr, len);
+
+ if (la.l2_cid)
+ return -EINVAL;
+
+ lock_sock(sk);
+
+ if (sk->sk_state != BT_OPEN) {
+ err = -EBADFD;
+ goto done;
+ }
+
+ if (la.l2_psm) {
+ __u16 psm = __le16_to_cpu(la.l2_psm);
+
+ /* PSM must be odd and lsb of upper byte must be 0 */
+ if ((psm & 0x0101) != 0x0001) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ /* Restrict usage of well-known PSMs */
+ if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
+ err = -EACCES;
+ goto done;
+ }
+ }
+
+ write_lock_bh(&l2cap_sk_list.lock);
+
+ if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
+ err = -EADDRINUSE;
+ } else {
+ /* Save source address */
+ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
+ l2cap_pi(sk)->psm = la.l2_psm;
+ l2cap_pi(sk)->sport = la.l2_psm;
+ sk->sk_state = BT_BOUND;
+
+ if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
+ __le16_to_cpu(la.l2_psm) == 0x0003)
+ l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+ }
+
+ write_unlock_bh(&l2cap_sk_list.lock);
+
+done:
+ release_sock(sk);
+ return err;
+}
+
+static int l2cap_do_connect(struct sock *sk)
{
bdaddr_t *src = &bt_sk(sk)->src;
bdaddr_t *dst = &bt_sk(sk)->dst;
@@ -797,109 +1118,325 @@ int l2cap_do_connect(struct sock *sk)
return err;
}
-int __l2cap_wait_ack(struct sock *sk)
+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
- int timeo = HZ/5;
-
- add_wait_queue(sk_sleep(sk), &wait);
- while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
- set_current_state(TASK_INTERRUPTIBLE);
+ struct sock *sk = sock->sk;
+ struct sockaddr_l2 la;
+ int len, err = 0;
- if (!timeo)
- timeo = HZ/5;
+ BT_DBG("sk %p", sk);
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
+ if (!addr || alen < sizeof(addr->sa_family) ||
+ addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
+ memset(&la, 0, sizeof(la));
+ len = min_t(unsigned int, sizeof(la), alen);
+ memcpy(&la, addr, len);
- err = sock_error(sk);
- if (err)
- break;
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return err;
-}
+ if (la.l2_cid)
+ return -EINVAL;
-static void l2cap_monitor_timeout(unsigned long arg)
-{
- struct sock *sk = (void *) arg;
+ lock_sock(sk);
- BT_DBG("sk %p", sk);
+ if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
+ && !la.l2_psm) {
+ err = -EINVAL;
+ goto done;
+ }
- bh_lock_sock(sk);
- if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
- l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
- bh_unlock_sock(sk);
- return;
+ switch (l2cap_pi(sk)->mode) {
+ case L2CAP_MODE_BASIC:
+ break;
+ case L2CAP_MODE_ERTM:
+ case L2CAP_MODE_STREAMING:
+ if (!disable_ertm)
+ break;
+ /* fall through */
+ default:
+ err = -ENOTSUPP;
+ goto done;
}
- l2cap_pi(sk)->retry_count++;
- __mod_monitor_timer();
+ switch (sk->sk_state) {
+ case BT_CONNECT:
+ case BT_CONNECT2:
+ case BT_CONFIG:
+ /* Already connecting */
+ goto wait;
- l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
- bh_unlock_sock(sk);
-}
+ case BT_CONNECTED:
+ /* Already connected */
+ err = -EISCONN;
+ goto done;
-static void l2cap_retrans_timeout(unsigned long arg)
-{
- struct sock *sk = (void *) arg;
+ case BT_OPEN:
+ case BT_BOUND:
+ /* Can connect */
+ break;
- BT_DBG("sk %p", sk);
+ default:
+ err = -EBADFD;
+ goto done;
+ }
- bh_lock_sock(sk);
- l2cap_pi(sk)->retry_count = 1;
- __mod_monitor_timer();
+ /* PSM must be odd and lsb of upper byte must be 0 */
+ if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
+ sk->sk_type != SOCK_RAW) {
+ err = -EINVAL;
+ goto done;
+ }
- l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
+ /* Set destination address and psm */
+ bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
+ l2cap_pi(sk)->psm = la.l2_psm;
- l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
- bh_unlock_sock(sk);
+ err = l2cap_do_connect(sk);
+ if (err)
+ goto done;
+
+wait:
+ err = bt_sock_wait_state(sk, BT_CONNECTED,
+ sock_sndtimeo(sk, flags & O_NONBLOCK));
+done:
+ release_sock(sk);
+ return err;
}
-static void l2cap_drop_acked_frames(struct sock *sk)
+static int l2cap_sock_listen(struct socket *sock, int backlog)
{
- struct sk_buff *skb;
+ struct sock *sk = sock->sk;
+ int err = 0;
- while ((skb = skb_peek(TX_QUEUE(sk))) &&
- l2cap_pi(sk)->unacked_frames) {
- if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq)
- break;
+ BT_DBG("sk %p backlog %d", sk, backlog);
- skb = skb_dequeue(TX_QUEUE(sk));
- kfree_skb(skb);
+ lock_sock(sk);
- l2cap_pi(sk)->unacked_frames--;
+ if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
+ || sk->sk_state != BT_BOUND) {
+ err = -EBADFD;
+ goto done;
}
- if (!l2cap_pi(sk)->unacked_frames)
+ switch (l2cap_pi(sk)->mode) {
+ case L2CAP_MODE_BASIC:
+ break;
+ case L2CAP_MODE_ERTM:
+ case L2CAP_MODE_STREAMING:
+ if (!disable_ertm)
+ break;
+ /* fall through */
+ default:
+ err = -ENOTSUPP;
+ goto done;
+ }
+
+ if (!l2cap_pi(sk)->psm) {
+ bdaddr_t *src = &bt_sk(sk)->src;
+ u16 psm;
+
+ err = -EINVAL;
+
+ write_lock_bh(&l2cap_sk_list.lock);
+
+ for (psm = 0x1001; psm < 0x1100; psm += 2)
+ if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
+ l2cap_pi(sk)->psm = cpu_to_le16(psm);
+ l2cap_pi(sk)->sport = cpu_to_le16(psm);
+ err = 0;
+ break;
+ }
+
+ write_unlock_bh(&l2cap_sk_list.lock);
+
+ if (err < 0)
+ goto done;
+ }
+
+ sk->sk_max_ack_backlog = backlog;
+ sk->sk_ack_backlog = 0;
+ sk->sk_state = BT_LISTEN;
+
+done:
+ release_sock(sk);
+ return err;
+}
+
+static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct sock *sk = sock->sk, *nsk;
+ long timeo;
+ int err = 0;
+
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
+ goto done;
+ }
+
+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+ BT_DBG("sk %p timeo %ld", sk, timeo);
+
+ /* Wait for an incoming connection. (wake-one). */
+ add_wait_queue_exclusive(sk_sleep(sk), &wait);
+ while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk_sleep(sk), &wait);
+
+ if (err)
+ goto done;
+
+ newsock->state = SS_CONNECTED;
+
+ BT_DBG("new socket %p", nsk);
+
+done:
+ release_sock(sk);
+ return err;
+}
+
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+ struct sock *sk = sock->sk;
+
+ BT_DBG("sock %p, sk %p", sock, sk);
+
+ addr->sa_family = AF_BLUETOOTH;
+ *len = sizeof(struct sockaddr_l2);
+
+ if (peer) {
+ la->l2_psm = l2cap_pi(sk)->psm;
+ bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
+ la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ } else {
+ la->l2_psm = l2cap_pi(sk)->sport;
+ bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
+ la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid);
+ }
+
+ return 0;
+}
+
+static int __l2cap_wait_ack(struct sock *sk)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int err = 0;
+ int timeo = HZ/5;
+
+ add_wait_queue(sk_sleep(sk), &wait);
+ while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (!timeo)
+ timeo = HZ/5;
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+
+ err = sock_error(sk);
+ if (err)
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk_sleep(sk), &wait);
+ return err;
+}
+
+static void l2cap_monitor_timeout(unsigned long arg)
+{
+ struct sock *sk = (void *) arg;
+
+ BT_DBG("sk %p", sk);
+
+ bh_lock_sock(sk);
+ if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
+ l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
+ bh_unlock_sock(sk);
+ return;
+ }
+
+ l2cap_pi(sk)->retry_count++;
+ __mod_monitor_timer();
+
+ l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
+ bh_unlock_sock(sk);
+}
+
+static void l2cap_retrans_timeout(unsigned long arg)
+{
+ struct sock *sk = (void *) arg;
+
+ BT_DBG("sk %p", sk);
+
+ bh_lock_sock(sk);
+ l2cap_pi(sk)->retry_count = 1;
+ __mod_monitor_timer();
+
+ l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
+
+ l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
+ bh_unlock_sock(sk);
+}
+
+static void l2cap_drop_acked_frames(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_peek(TX_QUEUE(sk))) &&
+ l2cap_pi(sk)->unacked_frames) {
+ if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq)
+ break;
+
+ skb = skb_dequeue(TX_QUEUE(sk));
+ kfree_skb(skb);
+
+ l2cap_pi(sk)->unacked_frames--;
+ }
+
+ if (!l2cap_pi(sk)->unacked_frames)
del_timer(&l2cap_pi(sk)->retrans_timer);
}
-void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
+static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
- struct hci_conn *hcon = pi->conn->hcon;
- u16 flags;
BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len);
- if (!pi->flushable && lmp_no_flush_capable(hcon->hdev))
- flags = ACL_START_NO_FLUSH;
- else
- flags = ACL_START;
-
- hci_send_acl(hcon, skb, flags);
+ hci_send_acl(pi->conn->hcon, skb, 0);
}
-void l2cap_streaming_send(struct sock *sk)
+static void l2cap_streaming_send(struct sock *sk)
{
struct sk_buff *skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -968,7 +1505,7 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
l2cap_do_send(sk, tx_skb);
}
-int l2cap_ertm_send(struct sock *sk)
+static int l2cap_ertm_send(struct sock *sk)
{
struct sk_buff *skb, *tx_skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -1022,238 +1559,719 @@ int l2cap_ertm_send(struct sock *sk)
else
sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
- nsent++;
- }
+ nsent++;
+ }
+
+ return nsent;
+}
+
+static int l2cap_retransmit_frames(struct sock *sk)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ int ret;
+
+ if (!skb_queue_empty(TX_QUEUE(sk)))
+ sk->sk_send_head = TX_QUEUE(sk)->next;
+
+ pi->next_tx_seq = pi->expected_ack_seq;
+ ret = l2cap_ertm_send(sk);
+ return ret;
+}
+
+static void l2cap_send_ack(struct l2cap_pinfo *pi)
+{
+ struct sock *sk = (struct sock *)pi;
+ u16 control = 0;
+
+ control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+ if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+ control |= L2CAP_SUPER_RCV_NOT_READY;
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
+ l2cap_send_sframe(pi, control);
+ return;
+ }
+
+ if (l2cap_ertm_send(sk) > 0)
+ return;
+
+ control |= L2CAP_SUPER_RCV_READY;
+ l2cap_send_sframe(pi, control);
+}
+
+static void l2cap_send_srejtail(struct sock *sk)
+{
+ struct srej_list *tail;
+ u16 control;
+
+ control = L2CAP_SUPER_SELECT_REJECT;
+ control |= L2CAP_CTRL_FINAL;
+
+ tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list);
+ control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+ l2cap_send_sframe(l2cap_pi(sk), control);
+}
+
+static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
+{
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sk_buff **frag;
+ int err, sent = 0;
+
+ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
+ return -EFAULT;
+
+ sent += count;
+ len -= count;
+
+ /* Continuation fragments (no L2CAP header) */
+ frag = &skb_shinfo(skb)->frag_list;
+ while (len) {
+ count = min_t(unsigned int, conn->mtu, len);
+
+ *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!*frag)
+ return err;
+ if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
+ return -EFAULT;
+
+ sent += count;
+ len -= count;
+
+ frag = &(*frag)->next;
+ }
+
+ return sent;
+}
+
+static struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len)
+{
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sk_buff *skb;
+ int err, count, hlen = L2CAP_HDR_SIZE + 2;
+ struct l2cap_hdr *lh;
+
+ BT_DBG("sk %p len %d", sk, (int)len);
+
+ count = min_t(unsigned int, (conn->mtu - hlen), len);
+ skb = bt_skb_send_alloc(sk, count + hlen,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!skb)
+ return ERR_PTR(err);
+
+ /* Create L2CAP header */
+ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+ lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+ put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2));
+
+ err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+ if (unlikely(err < 0)) {
+ kfree_skb(skb);
+ return ERR_PTR(err);
+ }
+ return skb;
+}
+
+static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len)
+{
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sk_buff *skb;
+ int err, count, hlen = L2CAP_HDR_SIZE;
+ struct l2cap_hdr *lh;
+
+ BT_DBG("sk %p len %d", sk, (int)len);
+
+ count = min_t(unsigned int, (conn->mtu - hlen), len);
+ skb = bt_skb_send_alloc(sk, count + hlen,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!skb)
+ return ERR_PTR(err);
+
+ /* Create L2CAP header */
+ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+ lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+
+ err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+ if (unlikely(err < 0)) {
+ kfree_skb(skb);
+ return ERR_PTR(err);
+ }
+ return skb;
+}
+
+static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+{
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sk_buff *skb;
+ int err, count, hlen = L2CAP_HDR_SIZE + 2;
+ struct l2cap_hdr *lh;
+
+ BT_DBG("sk %p len %d", sk, (int)len);
+
+ if (!conn)
+ return ERR_PTR(-ENOTCONN);
+
+ if (sdulen)
+ hlen += 2;
+
+ if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
+ hlen += 2;
+
+ count = min_t(unsigned int, (conn->mtu - hlen), len);
+ skb = bt_skb_send_alloc(sk, count + hlen,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!skb)
+ return ERR_PTR(err);
+
+ /* Create L2CAP header */
+ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+ lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+ put_unaligned_le16(control, skb_put(skb, 2));
+ if (sdulen)
+ put_unaligned_le16(sdulen, skb_put(skb, 2));
+
+ err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+ if (unlikely(err < 0)) {
+ kfree_skb(skb);
+ return ERR_PTR(err);
+ }
+
+ if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
+ put_unaligned_le16(0, skb_put(skb, 2));
+
+ bt_cb(skb)->retries = 0;
+ return skb;
+}
+
+static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ struct sk_buff *skb;
+ struct sk_buff_head sar_queue;
+ u16 control;
+ size_t size = 0;
+
+ skb_queue_head_init(&sar_queue);
+ control = L2CAP_SDU_START;
+ skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ __skb_queue_tail(&sar_queue, skb);
+ len -= pi->remote_mps;
+ size += pi->remote_mps;
+
+ while (len > 0) {
+ size_t buflen;
+
+ if (len > pi->remote_mps) {
+ control = L2CAP_SDU_CONTINUE;
+ buflen = pi->remote_mps;
+ } else {
+ control = L2CAP_SDU_END;
+ buflen = len;
+ }
+
+ skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0);
+ if (IS_ERR(skb)) {
+ skb_queue_purge(&sar_queue);
+ return PTR_ERR(skb);
+ }
+
+ __skb_queue_tail(&sar_queue, skb);
+ len -= buflen;
+ size += buflen;
+ }
+ skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
+ if (sk->sk_send_head == NULL)
+ sk->sk_send_head = sar_queue.next;
+
+ return size;
+}
+
+static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
+{
+ struct sock *sk = sock->sk;
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ struct sk_buff *skb;
+ u16 control;
+ int err;
+
+ BT_DBG("sock %p, sk %p", sock, sk);
+
+ err = sock_error(sk);
+ if (err)
+ return err;
+
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ lock_sock(sk);
+
+ if (sk->sk_state != BT_CONNECTED) {
+ err = -ENOTCONN;
+ goto done;
+ }
+
+ /* Connectionless channel */
+ if (sk->sk_type == SOCK_DGRAM) {
+ skb = l2cap_create_connless_pdu(sk, msg, len);
+ if (IS_ERR(skb)) {
+ err = PTR_ERR(skb);
+ } else {
+ l2cap_do_send(sk, skb);
+ err = len;
+ }
+ goto done;
+ }
+
+ switch (pi->mode) {
+ case L2CAP_MODE_BASIC:
+ /* Check outgoing MTU */
+ if (len > pi->omtu) {
+ err = -EMSGSIZE;
+ goto done;
+ }
+
+ /* Create a basic PDU */
+ skb = l2cap_create_basic_pdu(sk, msg, len);
+ if (IS_ERR(skb)) {
+ err = PTR_ERR(skb);
+ goto done;
+ }
+
+ l2cap_do_send(sk, skb);
+ err = len;
+ break;
+
+ case L2CAP_MODE_ERTM:
+ case L2CAP_MODE_STREAMING:
+ /* Entire SDU fits into one PDU */
+ if (len <= pi->remote_mps) {
+ control = L2CAP_SDU_UNSEGMENTED;
+ skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
+ if (IS_ERR(skb)) {
+ err = PTR_ERR(skb);
+ goto done;
+ }
+ __skb_queue_tail(TX_QUEUE(sk), skb);
+
+ if (sk->sk_send_head == NULL)
+ sk->sk_send_head = skb;
+
+ } else {
+ /* Segment SDU into multiples PDUs */
+ err = l2cap_sar_segment_sdu(sk, msg, len);
+ if (err < 0)
+ goto done;
+ }
+
+ if (pi->mode == L2CAP_MODE_STREAMING) {
+ l2cap_streaming_send(sk);
+ } else {
+ if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+ (pi->conn_state & L2CAP_CONN_WAIT_F)) {
+ err = len;
+ break;
+ }
+ err = l2cap_ertm_send(sk);
+ }
+
+ if (err >= 0)
+ err = len;
+ break;
+
+ default:
+ BT_DBG("bad state %1.1x", pi->mode);
+ err = -EBADFD;
+ }
+
+done:
+ release_sock(sk);
+ return err;
+}
+
+static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ lock_sock(sk);
+
+ if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
+ struct l2cap_conn_rsp rsp;
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ u8 buf[128];
+
+ sk->sk_state = BT_CONFIG;
+
+ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+ rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+ l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
+ L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
+ release_sock(sk);
+ return 0;
+ }
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
+
+ release_sock(sk);
+ return 0;
+ }
+
+ release_sock(sk);
+
+ if (sock->type == SOCK_STREAM)
+ return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
+
+ return bt_sock_recvmsg(iocb, sock, msg, len, flags);
+}
+
+static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
+{
+ struct sock *sk = sock->sk;
+ struct l2cap_options opts;
+ int len, err = 0;
+ u32 opt;
+
+ BT_DBG("sk %p", sk);
+
+ lock_sock(sk);
+
+ switch (optname) {
+ case L2CAP_OPTIONS:
+ if (sk->sk_state == BT_CONNECTED) {
+ err = -EINVAL;
+ break;
+ }
+
+ opts.imtu = l2cap_pi(sk)->imtu;
+ opts.omtu = l2cap_pi(sk)->omtu;
+ opts.flush_to = l2cap_pi(sk)->flush_to;
+ opts.mode = l2cap_pi(sk)->mode;
+ opts.fcs = l2cap_pi(sk)->fcs;
+ opts.max_tx = l2cap_pi(sk)->max_tx;
+ opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+
+ len = min_t(unsigned int, sizeof(opts), optlen);
+ if (copy_from_user((char *) &opts, optval, len)) {
+ err = -EFAULT;
+ break;
+ }
+
+ if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+ err = -EINVAL;
+ break;
+ }
+
+ l2cap_pi(sk)->mode = opts.mode;
+ switch (l2cap_pi(sk)->mode) {
+ case L2CAP_MODE_BASIC:
+ l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
+ break;
+ case L2CAP_MODE_ERTM:
+ case L2CAP_MODE_STREAMING:
+ if (!disable_ertm)
+ break;
+ /* fall through */
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ l2cap_pi(sk)->imtu = opts.imtu;
+ l2cap_pi(sk)->omtu = opts.omtu;
+ l2cap_pi(sk)->fcs = opts.fcs;
+ l2cap_pi(sk)->max_tx = opts.max_tx;
+ l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
+ break;
+
+ case L2CAP_LM:
+ if (get_user(opt, (u32 __user *) optval)) {
+ err = -EFAULT;
+ break;
+ }
+
+ if (opt & L2CAP_LM_AUTH)
+ l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
+ if (opt & L2CAP_LM_ENCRYPT)
+ l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
+ if (opt & L2CAP_LM_SECURE)
+ l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
+
+ l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER);
+ l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ release_sock(sk);
+ return err;
+}
+
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
+{
+ struct sock *sk = sock->sk;
+ struct bt_security sec;
+ int len, err = 0;
+ u32 opt;
+
+ BT_DBG("sk %p", sk);
+
+ if (level == SOL_L2CAP)
+ return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
+
+ if (level != SOL_BLUETOOTH)
+ return -ENOPROTOOPT;
+
+ lock_sock(sk);
+
+ switch (optname) {
+ case BT_SECURITY:
+ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
+ && sk->sk_type != SOCK_RAW) {
+ err = -EINVAL;
+ break;
+ }
+
+ sec.level = BT_SECURITY_LOW;
+
+ len = min_t(unsigned int, sizeof(sec), optlen);
+ if (copy_from_user((char *) &sec, optval, len)) {
+ err = -EFAULT;
+ break;
+ }
+
+ if (sec.level < BT_SECURITY_LOW ||
+ sec.level > BT_SECURITY_HIGH) {
+ err = -EINVAL;
+ break;
+ }
+
+ l2cap_pi(sk)->sec_level = sec.level;
+ break;
- return nsent;
-}
+ case BT_DEFER_SETUP:
+ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+ err = -EINVAL;
+ break;
+ }
-static int l2cap_retransmit_frames(struct sock *sk)
-{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- int ret;
+ if (get_user(opt, (u32 __user *) optval)) {
+ err = -EFAULT;
+ break;
+ }
- if (!skb_queue_empty(TX_QUEUE(sk)))
- sk->sk_send_head = TX_QUEUE(sk)->next;
+ bt_sk(sk)->defer_setup = opt;
+ break;
- pi->next_tx_seq = pi->expected_ack_seq;
- ret = l2cap_ertm_send(sk);
- return ret;
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ release_sock(sk);
+ return err;
}
-static void l2cap_send_ack(struct l2cap_pinfo *pi)
+static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
- struct sock *sk = (struct sock *)pi;
- u16 control = 0;
+ struct sock *sk = sock->sk;
+ struct l2cap_options opts;
+ struct l2cap_conninfo cinfo;
+ int len, err = 0;
+ u32 opt;
- control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ BT_DBG("sk %p", sk);
- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
- control |= L2CAP_SUPER_RCV_NOT_READY;
- pi->conn_state |= L2CAP_CONN_RNR_SENT;
- l2cap_send_sframe(pi, control);
- return;
- }
+ if (get_user(len, optlen))
+ return -EFAULT;
- if (l2cap_ertm_send(sk) > 0)
- return;
+ lock_sock(sk);
- control |= L2CAP_SUPER_RCV_READY;
- l2cap_send_sframe(pi, control);
-}
+ switch (optname) {
+ case L2CAP_OPTIONS:
+ opts.imtu = l2cap_pi(sk)->imtu;
+ opts.omtu = l2cap_pi(sk)->omtu;
+ opts.flush_to = l2cap_pi(sk)->flush_to;
+ opts.mode = l2cap_pi(sk)->mode;
+ opts.fcs = l2cap_pi(sk)->fcs;
+ opts.max_tx = l2cap_pi(sk)->max_tx;
+ opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
-static void l2cap_send_srejtail(struct sock *sk)
-{
- struct srej_list *tail;
- u16 control;
+ len = min_t(unsigned int, len, sizeof(opts));
+ if (copy_to_user(optval, (char *) &opts, len))
+ err = -EFAULT;
- control = L2CAP_SUPER_SELECT_REJECT;
- control |= L2CAP_CTRL_FINAL;
+ break;
- tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list);
- control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ case L2CAP_LM:
+ switch (l2cap_pi(sk)->sec_level) {
+ case BT_SECURITY_LOW:
+ opt = L2CAP_LM_AUTH;
+ break;
+ case BT_SECURITY_MEDIUM:
+ opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
+ break;
+ case BT_SECURITY_HIGH:
+ opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+ L2CAP_LM_SECURE;
+ break;
+ default:
+ opt = 0;
+ break;
+ }
- l2cap_send_sframe(l2cap_pi(sk), control);
-}
+ if (l2cap_pi(sk)->role_switch)
+ opt |= L2CAP_LM_MASTER;
-static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
-{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sk_buff **frag;
- int err, sent = 0;
+ if (l2cap_pi(sk)->force_reliable)
+ opt |= L2CAP_LM_RELIABLE;
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
- return -EFAULT;
+ if (put_user(opt, (u32 __user *) optval))
+ err = -EFAULT;
+ break;
- sent += count;
- len -= count;
+ case L2CAP_CONNINFO:
+ if (sk->sk_state != BT_CONNECTED &&
+ !(sk->sk_state == BT_CONNECT2 &&
+ bt_sk(sk)->defer_setup)) {
+ err = -ENOTCONN;
+ break;
+ }
- /* Continuation fragments (no L2CAP header) */
- frag = &skb_shinfo(skb)->frag_list;
- while (len) {
- count = min_t(unsigned int, conn->mtu, len);
+ cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
+ memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
- *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
- if (!*frag)
- return err;
- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
- return -EFAULT;
+ len = min_t(unsigned int, len, sizeof(cinfo));
+ if (copy_to_user(optval, (char *) &cinfo, len))
+ err = -EFAULT;
- sent += count;
- len -= count;
+ break;
- frag = &(*frag)->next;
+ default:
+ err = -ENOPROTOOPT;
+ break;
}
- return sent;
+ release_sock(sk);
+ return err;
}
-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len)
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sk_buff *skb;
- int err, count, hlen = L2CAP_HDR_SIZE + 2;
- struct l2cap_hdr *lh;
+ struct sock *sk = sock->sk;
+ struct bt_security sec;
+ int len, err = 0;
- BT_DBG("sk %p len %d", sk, (int)len);
+ BT_DBG("sk %p", sk);
- count = min_t(unsigned int, (conn->mtu - hlen), len);
- skb = bt_skb_send_alloc(sk, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return ERR_PTR(err);
+ if (level == SOL_L2CAP)
+ return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
- put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2));
+ if (level != SOL_BLUETOOTH)
+ return -ENOPROTOOPT;
- err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
- if (unlikely(err < 0)) {
- kfree_skb(skb);
- return ERR_PTR(err);
- }
- return skb;
-}
+ if (get_user(len, optlen))
+ return -EFAULT;
-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len)
-{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sk_buff *skb;
- int err, count, hlen = L2CAP_HDR_SIZE;
- struct l2cap_hdr *lh;
+ lock_sock(sk);
- BT_DBG("sk %p len %d", sk, (int)len);
+ switch (optname) {
+ case BT_SECURITY:
+ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
+ && sk->sk_type != SOCK_RAW) {
+ err = -EINVAL;
+ break;
+ }
- count = min_t(unsigned int, (conn->mtu - hlen), len);
- skb = bt_skb_send_alloc(sk, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return ERR_PTR(err);
+ sec.level = l2cap_pi(sk)->sec_level;
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+ len = min_t(unsigned int, len, sizeof(sec));
+ if (copy_to_user(optval, (char *) &sec, len))
+ err = -EFAULT;
- err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
- if (unlikely(err < 0)) {
- kfree_skb(skb);
- return ERR_PTR(err);
+ break;
+
+ case BT_DEFER_SETUP:
+ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+ err = -EFAULT;
+
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
}
- return skb;
+
+ release_sock(sk);
+ return err;
}
-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+static int l2cap_sock_shutdown(struct socket *sock, int how)
{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sk_buff *skb;
- int err, count, hlen = L2CAP_HDR_SIZE + 2;
- struct l2cap_hdr *lh;
-
- BT_DBG("sk %p len %d", sk, (int)len);
-
- if (!conn)
- return ERR_PTR(-ENOTCONN);
+ struct sock *sk = sock->sk;
+ int err = 0;
- if (sdulen)
- hlen += 2;
+ BT_DBG("sock %p, sk %p", sock, sk);
- if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
- hlen += 2;
+ if (!sk)
+ return 0;
- count = min_t(unsigned int, (conn->mtu - hlen), len);
- skb = bt_skb_send_alloc(sk, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return ERR_PTR(err);
+ lock_sock(sk);
+ if (!sk->sk_shutdown) {
+ if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
+ err = __l2cap_wait_ack(sk);
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
- put_unaligned_le16(control, skb_put(skb, 2));
- if (sdulen)
- put_unaligned_le16(sdulen, skb_put(skb, 2));
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ l2cap_sock_clear_timer(sk);
+ __l2cap_sock_close(sk, 0);
- err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
- if (unlikely(err < 0)) {
- kfree_skb(skb);
- return ERR_PTR(err);
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+ err = bt_sock_wait_state(sk, BT_CLOSED,
+ sk->sk_lingertime);
}
- if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
- put_unaligned_le16(0, skb_put(skb, 2));
+ if (!err && sk->sk_err)
+ err = -sk->sk_err;
- bt_cb(skb)->retries = 0;
- return skb;
+ release_sock(sk);
+ return err;
}
-int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
+static int l2cap_sock_release(struct socket *sock)
{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- struct sk_buff *skb;
- struct sk_buff_head sar_queue;
- u16 control;
- size_t size = 0;
-
- skb_queue_head_init(&sar_queue);
- control = L2CAP_SDU_START;
- skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- __skb_queue_tail(&sar_queue, skb);
- len -= pi->remote_mps;
- size += pi->remote_mps;
-
- while (len > 0) {
- size_t buflen;
+ struct sock *sk = sock->sk;
+ int err;
- if (len > pi->remote_mps) {
- control = L2CAP_SDU_CONTINUE;
- buflen = pi->remote_mps;
- } else {
- control = L2CAP_SDU_END;
- buflen = len;
- }
+ BT_DBG("sock %p, sk %p", sock, sk);
- skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0);
- if (IS_ERR(skb)) {
- skb_queue_purge(&sar_queue);
- return PTR_ERR(skb);
- }
+ if (!sk)
+ return 0;
- __skb_queue_tail(&sar_queue, skb);
- len -= buflen;
- size += buflen;
- }
- skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
- if (sk->sk_send_head == NULL)
- sk->sk_send_head = sar_queue.next;
+ err = l2cap_sock_shutdown(sock, 2);
- return size;
+ sock_orphan(sk);
+ l2cap_sock_kill(sk);
+ return err;
}
static void l2cap_chan_ready(struct sock *sk)
@@ -1474,7 +2492,7 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
}
}
-int l2cap_build_conf_req(struct sock *sk, void *data)
+static int l2cap_build_conf_req(struct sock *sk, void *data)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_conf_req *req = data;
@@ -1499,11 +2517,11 @@ int l2cap_build_conf_req(struct sock *sk, void *data)
}
done:
- if (pi->imtu != L2CAP_DEFAULT_MTU)
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
-
switch (pi->mode) {
case L2CAP_MODE_BASIC:
+ if (pi->imtu != L2CAP_DEFAULT_MTU)
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) &&
!(pi->conn->feat_mask & L2CAP_FEAT_STREAMING))
break;
@@ -3654,15 +4672,12 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
{
struct l2cap_conn *conn = hcon->l2cap_data;
- if (!conn)
- conn = l2cap_conn_add(hcon, 0);
-
- if (!conn)
+ if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
goto drop;
BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
- if (!(flags & ACL_CONT)) {
+ if (flags & ACL_START) {
struct l2cap_hdr *hdr;
struct sock *sk;
u16 cid;
@@ -3795,6 +4810,32 @@ static const struct file_operations l2cap_debugfs_fops = {
static struct dentry *l2cap_debugfs;
+static const struct proto_ops l2cap_sock_ops = {
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .release = l2cap_sock_release,
+ .bind = l2cap_sock_bind,
+ .connect = l2cap_sock_connect,
+ .listen = l2cap_sock_listen,
+ .accept = l2cap_sock_accept,
+ .getname = l2cap_sock_getname,
+ .sendmsg = l2cap_sock_sendmsg,
+ .recvmsg = l2cap_sock_recvmsg,
+ .poll = bt_sock_poll,
+ .ioctl = bt_sock_ioctl,
+ .mmap = sock_no_mmap,
+ .socketpair = sock_no_socketpair,
+ .shutdown = l2cap_sock_shutdown,
+ .setsockopt = l2cap_sock_setsockopt,
+ .getsockopt = l2cap_sock_getsockopt
+};
+
+static const struct net_proto_family l2cap_sock_family_ops = {
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .create = l2cap_sock_create,
+};
+
static struct hci_proto l2cap_hci_proto = {
.name = "L2CAP",
.id = HCI_PROTO_L2CAP,
@@ -3810,13 +4851,19 @@ static int __init l2cap_init(void)
{
int err;
- err = l2cap_init_sockets();
+ err = proto_register(&l2cap_proto, 0);
if (err < 0)
return err;
_busy_wq = create_singlethread_workqueue("l2cap");
if (!_busy_wq) {
- err = -ENOMEM;
+ proto_unregister(&l2cap_proto);
+ return -ENOMEM;
+ }
+
+ err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
+ if (err < 0) {
+ BT_ERR("L2CAP socket registration failed");
goto error;
}
@@ -3841,7 +4888,7 @@ static int __init l2cap_init(void)
error:
destroy_workqueue(_busy_wq);
- l2cap_cleanup_sockets();
+ proto_unregister(&l2cap_proto);
return err;
}
@@ -3852,10 +4899,13 @@ static void __exit l2cap_exit(void)
flush_workqueue(_busy_wq);
destroy_workqueue(_busy_wq);
+ if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
+ BT_ERR("L2CAP socket unregistration failed");
+
if (hci_unregister_proto(&l2cap_hci_proto) < 0)
BT_ERR("L2CAP protocol unregistration failed");
- l2cap_cleanup_sockets();
+ proto_unregister(&l2cap_proto);
}
void l2cap_load(void)
diff --git a/trunk/net/bluetooth/l2cap_sock.c b/trunk/net/bluetooth/l2cap_sock.c
deleted file mode 100644
index adf41692daf3..000000000000
--- a/trunk/net/bluetooth/l2cap_sock.c
+++ /dev/null
@@ -1,1150 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright (C) 2009-2010 Gustavo F. Padovan
- Copyright (C) 2010 Google Inc.
-
- Written 2000,2001 by Maxim Krasnyansky
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth L2CAP sockets. */
-
-#include
-#include
-#include
-
-/* ---- L2CAP timers ---- */
-static void l2cap_sock_timeout(unsigned long arg)
-{
- struct sock *sk = (struct sock *) arg;
- int reason;
-
- BT_DBG("sock %p state %d", sk, sk->sk_state);
-
- bh_lock_sock(sk);
-
- if (sock_owned_by_user(sk)) {
- /* sk is owned by user. Try again later */
- l2cap_sock_set_timer(sk, HZ / 5);
- bh_unlock_sock(sk);
- sock_put(sk);
- return;
- }
-
- if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
- reason = ECONNREFUSED;
- else if (sk->sk_state == BT_CONNECT &&
- l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
- reason = ECONNREFUSED;
- else
- reason = ETIMEDOUT;
-
- __l2cap_sock_close(sk, reason);
-
- bh_unlock_sock(sk);
-
- l2cap_sock_kill(sk);
- sock_put(sk);
-}
-
-void l2cap_sock_set_timer(struct sock *sk, long timeout)
-{
- BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
- sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
-}
-
-void l2cap_sock_clear_timer(struct sock *sk)
-{
- BT_DBG("sock %p state %d", sk, sk->sk_state);
- sk_stop_timer(sk, &sk->sk_timer);
-}
-
-static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
-{
- struct sock *sk;
- struct hlist_node *node;
- sk_for_each(sk, node, &l2cap_sk_list.head)
- if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
- goto found;
- sk = NULL;
-found:
- return sk;
-}
-
-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
-{
- struct sock *sk = sock->sk;
- struct sockaddr_l2 la;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (!addr || addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- memset(&la, 0, sizeof(la));
- len = min_t(unsigned int, sizeof(la), alen);
- memcpy(&la, addr, len);
-
- if (la.l2_cid)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_OPEN) {
- err = -EBADFD;
- goto done;
- }
-
- if (la.l2_psm) {
- __u16 psm = __le16_to_cpu(la.l2_psm);
-
- /* PSM must be odd and lsb of upper byte must be 0 */
- if ((psm & 0x0101) != 0x0001) {
- err = -EINVAL;
- goto done;
- }
-
- /* Restrict usage of well-known PSMs */
- if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
- err = -EACCES;
- goto done;
- }
- }
-
- write_lock_bh(&l2cap_sk_list.lock);
-
- if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
- err = -EADDRINUSE;
- } else {
- /* Save source address */
- bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
- l2cap_pi(sk)->psm = la.l2_psm;
- l2cap_pi(sk)->sport = la.l2_psm;
- sk->sk_state = BT_BOUND;
-
- if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
- __le16_to_cpu(la.l2_psm) == 0x0003)
- l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
- }
-
- write_unlock_bh(&l2cap_sk_list.lock);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-{
- struct sock *sk = sock->sk;
- struct sockaddr_l2 la;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (!addr || alen < sizeof(addr->sa_family) ||
- addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- memset(&la, 0, sizeof(la));
- len = min_t(unsigned int, sizeof(la), alen);
- memcpy(&la, addr, len);
-
- if (la.l2_cid)
- return -EINVAL;
-
- lock_sock(sk);
-
- if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
- && !la.l2_psm) {
- err = -EINVAL;
- goto done;
- }
-
- switch (l2cap_pi(sk)->mode) {
- case L2CAP_MODE_BASIC:
- break;
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- if (!disable_ertm)
- break;
- /* fall through */
- default:
- err = -ENOTSUPP;
- goto done;
- }
-
- switch (sk->sk_state) {
- case BT_CONNECT:
- case BT_CONNECT2:
- case BT_CONFIG:
- /* Already connecting */
- goto wait;
-
- case BT_CONNECTED:
- /* Already connected */
- err = -EISCONN;
- goto done;
-
- case BT_OPEN:
- case BT_BOUND:
- /* Can connect */
- break;
-
- default:
- err = -EBADFD;
- goto done;
- }
-
- /* PSM must be odd and lsb of upper byte must be 0 */
- if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
- sk->sk_type != SOCK_RAW) {
- err = -EINVAL;
- goto done;
- }
-
- /* Set destination address and psm */
- bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
- l2cap_pi(sk)->psm = la.l2_psm;
-
- err = l2cap_do_connect(sk);
- if (err)
- goto done;
-
-wait:
- err = bt_sock_wait_state(sk, BT_CONNECTED,
- sock_sndtimeo(sk, flags & O_NONBLOCK));
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sk %p backlog %d", sk, backlog);
-
- lock_sock(sk);
-
- if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
- || sk->sk_state != BT_BOUND) {
- err = -EBADFD;
- goto done;
- }
-
- switch (l2cap_pi(sk)->mode) {
- case L2CAP_MODE_BASIC:
- break;
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- if (!disable_ertm)
- break;
- /* fall through */
- default:
- err = -ENOTSUPP;
- goto done;
- }
-
- if (!l2cap_pi(sk)->psm) {
- bdaddr_t *src = &bt_sk(sk)->src;
- u16 psm;
-
- err = -EINVAL;
-
- write_lock_bh(&l2cap_sk_list.lock);
-
- for (psm = 0x1001; psm < 0x1100; psm += 2)
- if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
- l2cap_pi(sk)->psm = cpu_to_le16(psm);
- l2cap_pi(sk)->sport = cpu_to_le16(psm);
- err = 0;
- break;
- }
-
- write_unlock_bh(&l2cap_sk_list.lock);
-
- if (err < 0)
- goto done;
- }
-
- sk->sk_max_ack_backlog = backlog;
- sk->sk_ack_backlog = 0;
- sk->sk_state = BT_LISTEN;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct sock *sk = sock->sk, *nsk;
- long timeo;
- int err = 0;
-
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
-
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-
- BT_DBG("sk %p timeo %ld", sk, timeo);
-
- /* Wait for an incoming connection. (wake-one). */
- add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
-
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- break;
- }
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- if (err)
- goto done;
-
- newsock->state = SS_CONNECTED;
-
- BT_DBG("new socket %p", nsk);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-{
- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- addr->sa_family = AF_BLUETOOTH;
- *len = sizeof(struct sockaddr_l2);
-
- if (peer) {
- la->l2_psm = l2cap_pi(sk)->psm;
- bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
- la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid);
- } else {
- la->l2_psm = l2cap_pi(sk)->sport;
- bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
- la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid);
- }
-
- return 0;
-}
-
-static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_options opts;
- struct l2cap_conninfo cinfo;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case L2CAP_OPTIONS:
- opts.imtu = l2cap_pi(sk)->imtu;
- opts.omtu = l2cap_pi(sk)->omtu;
- opts.flush_to = l2cap_pi(sk)->flush_to;
- opts.mode = l2cap_pi(sk)->mode;
- opts.fcs = l2cap_pi(sk)->fcs;
- opts.max_tx = l2cap_pi(sk)->max_tx;
- opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
-
- len = min_t(unsigned int, len, sizeof(opts));
- if (copy_to_user(optval, (char *) &opts, len))
- err = -EFAULT;
-
- break;
-
- case L2CAP_LM:
- switch (l2cap_pi(sk)->sec_level) {
- case BT_SECURITY_LOW:
- opt = L2CAP_LM_AUTH;
- break;
- case BT_SECURITY_MEDIUM:
- opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
- break;
- case BT_SECURITY_HIGH:
- opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
- L2CAP_LM_SECURE;
- break;
- default:
- opt = 0;
- break;
- }
-
- if (l2cap_pi(sk)->role_switch)
- opt |= L2CAP_LM_MASTER;
-
- if (l2cap_pi(sk)->force_reliable)
- opt |= L2CAP_LM_RELIABLE;
-
- if (put_user(opt, (u32 __user *) optval))
- err = -EFAULT;
- break;
-
- case L2CAP_CONNINFO:
- if (sk->sk_state != BT_CONNECTED &&
- !(sk->sk_state == BT_CONNECT2 &&
- bt_sk(sk)->defer_setup)) {
- err = -ENOTCONN;
- break;
- }
-
- cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
- memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
-
- len = min_t(unsigned int, len, sizeof(cinfo));
- if (copy_to_user(optval, (char *) &cinfo, len))
- err = -EFAULT;
-
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct bt_security sec;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_L2CAP)
- return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
-
- if (level != SOL_BLUETOOTH)
- return -ENOPROTOOPT;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case BT_SECURITY:
- if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
- && sk->sk_type != SOCK_RAW) {
- err = -EINVAL;
- break;
- }
-
- sec.level = l2cap_pi(sk)->sec_level;
-
- len = min_t(unsigned int, len, sizeof(sec));
- if (copy_to_user(optval, (char *) &sec, len))
- err = -EFAULT;
-
- break;
-
- case BT_DEFER_SETUP:
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
- err = -EINVAL;
- break;
- }
-
- if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
- err = -EFAULT;
-
- break;
-
- case BT_FLUSHABLE:
- if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval))
- err = -EFAULT;
-
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_options opts;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- lock_sock(sk);
-
- switch (optname) {
- case L2CAP_OPTIONS:
- if (sk->sk_state == BT_CONNECTED) {
- err = -EINVAL;
- break;
- }
-
- opts.imtu = l2cap_pi(sk)->imtu;
- opts.omtu = l2cap_pi(sk)->omtu;
- opts.flush_to = l2cap_pi(sk)->flush_to;
- opts.mode = l2cap_pi(sk)->mode;
- opts.fcs = l2cap_pi(sk)->fcs;
- opts.max_tx = l2cap_pi(sk)->max_tx;
- opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
-
- len = min_t(unsigned int, sizeof(opts), optlen);
- if (copy_from_user((char *) &opts, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
- err = -EINVAL;
- break;
- }
-
- l2cap_pi(sk)->mode = opts.mode;
- switch (l2cap_pi(sk)->mode) {
- case L2CAP_MODE_BASIC:
- l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
- break;
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- if (!disable_ertm)
- break;
- /* fall through */
- default:
- err = -EINVAL;
- break;
- }
-
- l2cap_pi(sk)->imtu = opts.imtu;
- l2cap_pi(sk)->omtu = opts.omtu;
- l2cap_pi(sk)->fcs = opts.fcs;
- l2cap_pi(sk)->max_tx = opts.max_tx;
- l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
- break;
-
- case L2CAP_LM:
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt & L2CAP_LM_AUTH)
- l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
- if (opt & L2CAP_LM_ENCRYPT)
- l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
- if (opt & L2CAP_LM_SECURE)
- l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
-
- l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER);
- l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct bt_security sec;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_L2CAP)
- return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
-
- if (level != SOL_BLUETOOTH)
- return -ENOPROTOOPT;
-
- lock_sock(sk);
-
- switch (optname) {
- case BT_SECURITY:
- if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
- && sk->sk_type != SOCK_RAW) {
- err = -EINVAL;
- break;
- }
-
- sec.level = BT_SECURITY_LOW;
-
- len = min_t(unsigned int, sizeof(sec), optlen);
- if (copy_from_user((char *) &sec, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (sec.level < BT_SECURITY_LOW ||
- sec.level > BT_SECURITY_HIGH) {
- err = -EINVAL;
- break;
- }
-
- l2cap_pi(sk)->sec_level = sec.level;
- break;
-
- case BT_DEFER_SETUP:
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
- err = -EINVAL;
- break;
- }
-
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- bt_sk(sk)->defer_setup = opt;
- break;
-
- case BT_FLUSHABLE:
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt > BT_FLUSHABLE_ON) {
- err = -EINVAL;
- break;
- }
-
- if (opt == BT_FLUSHABLE_OFF) {
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- /* proceed futher only when we have l2cap_conn and
- No Flush support in the LM */
- if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
- err = -EINVAL;
- break;
- }
- }
-
- l2cap_pi(sk)->flushable = opt;
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- struct sk_buff *skb;
- u16 control;
- int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- err = sock_error(sk);
- if (err)
- return err;
-
- if (msg->msg_flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_CONNECTED) {
- err = -ENOTCONN;
- goto done;
- }
-
- /* Connectionless channel */
- if (sk->sk_type == SOCK_DGRAM) {
- skb = l2cap_create_connless_pdu(sk, msg, len);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- } else {
- l2cap_do_send(sk, skb);
- err = len;
- }
- goto done;
- }
-
- switch (pi->mode) {
- case L2CAP_MODE_BASIC:
- /* Check outgoing MTU */
- if (len > pi->omtu) {
- err = -EMSGSIZE;
- goto done;
- }
-
- /* Create a basic PDU */
- skb = l2cap_create_basic_pdu(sk, msg, len);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- goto done;
- }
-
- l2cap_do_send(sk, skb);
- err = len;
- break;
-
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- /* Entire SDU fits into one PDU */
- if (len <= pi->remote_mps) {
- control = L2CAP_SDU_UNSEGMENTED;
- skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- goto done;
- }
- __skb_queue_tail(TX_QUEUE(sk), skb);
-
- if (sk->sk_send_head == NULL)
- sk->sk_send_head = skb;
-
- } else {
- /* Segment SDU into multiples PDUs */
- err = l2cap_sar_segment_sdu(sk, msg, len);
- if (err < 0)
- goto done;
- }
-
- if (pi->mode == L2CAP_MODE_STREAMING) {
- l2cap_streaming_send(sk);
- } else {
- if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
- (pi->conn_state & L2CAP_CONN_WAIT_F)) {
- err = len;
- break;
- }
- err = l2cap_ertm_send(sk);
- }
-
- if (err >= 0)
- err = len;
- break;
-
- default:
- BT_DBG("bad state %1.1x", pi->mode);
- err = -EBADFD;
- }
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
-{
- struct sock *sk = sock->sk;
-
- lock_sock(sk);
-
- if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
- struct l2cap_conn_rsp rsp;
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- u8 buf[128];
-
- sk->sk_state = BT_CONFIG;
-
- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
- rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
- l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
-
- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
- release_sock(sk);
- return 0;
- }
-
- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(sk, buf), buf);
- l2cap_pi(sk)->num_conf_req++;
-
- release_sock(sk);
- return 0;
- }
-
- release_sock(sk);
-
- if (sock->type == SOCK_STREAM)
- return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
-
- return bt_sock_recvmsg(iocb, sock, msg, len, flags);
-}
-
-/* Kill socket (only if zapped and orphan)
- * Must be called on unlocked socket.
- */
-void l2cap_sock_kill(struct sock *sk)
-{
- if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
- return;
-
- BT_DBG("sk %p state %d", sk, sk->sk_state);
-
- /* Kill poor orphan */
- bt_sock_unlink(&l2cap_sk_list, sk);
- sock_set_flag(sk, SOCK_DEAD);
- sock_put(sk);
-}
-
-/* Must be called on unlocked socket. */
-static void l2cap_sock_close(struct sock *sk)
-{
- l2cap_sock_clear_timer(sk);
- lock_sock(sk);
- __l2cap_sock_close(sk, ECONNRESET);
- release_sock(sk);
- l2cap_sock_kill(sk);
-}
-
-static void l2cap_sock_cleanup_listen(struct sock *parent)
-{
- struct sock *sk;
-
- BT_DBG("parent %p", parent);
-
- /* Close not yet accepted channels */
- while ((sk = bt_accept_dequeue(parent, NULL)))
- l2cap_sock_close(sk);
-
- parent->sk_state = BT_CLOSED;
- sock_set_flag(parent, SOCK_ZAPPED);
-}
-
-void __l2cap_sock_close(struct sock *sk, int reason)
-{
- BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
-
- switch (sk->sk_state) {
- case BT_LISTEN:
- l2cap_sock_cleanup_listen(sk);
- break;
-
- case BT_CONNECTED:
- case BT_CONFIG:
- if (sk->sk_type == SOCK_SEQPACKET ||
- sk->sk_type == SOCK_STREAM) {
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-
- l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
- l2cap_send_disconn_req(conn, sk, reason);
- } else
- l2cap_chan_del(sk, reason);
- break;
-
- case BT_CONNECT2:
- if (sk->sk_type == SOCK_SEQPACKET ||
- sk->sk_type == SOCK_STREAM) {
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct l2cap_conn_rsp rsp;
- __u16 result;
-
- if (bt_sk(sk)->defer_setup)
- result = L2CAP_CR_SEC_BLOCK;
- else
- result = L2CAP_CR_BAD_PSM;
-
- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
- rsp.result = cpu_to_le16(result);
- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
- } else
- l2cap_chan_del(sk, reason);
- break;
-
- case BT_CONNECT:
- case BT_DISCONN:
- l2cap_chan_del(sk, reason);
- break;
-
- default:
- sock_set_flag(sk, SOCK_ZAPPED);
- break;
- }
-}
-
-static int l2cap_sock_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- lock_sock(sk);
- if (!sk->sk_shutdown) {
- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
- err = __l2cap_wait_ack(sk);
-
- sk->sk_shutdown = SHUTDOWN_MASK;
- l2cap_sock_clear_timer(sk);
- __l2cap_sock_close(sk, 0);
-
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
- err = bt_sock_wait_state(sk, BT_CLOSED,
- sk->sk_lingertime);
- }
-
- if (!err && sk->sk_err)
- err = -sk->sk_err;
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- err = l2cap_sock_shutdown(sock, 2);
-
- sock_orphan(sk);
- l2cap_sock_kill(sk);
- return err;
-}
-
-static void l2cap_sock_destruct(struct sock *sk)
-{
- BT_DBG("sk %p", sk);
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-}
-
-void l2cap_sock_init(struct sock *sk, struct sock *parent)
-{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
-
- BT_DBG("sk %p", sk);
-
- if (parent) {
- sk->sk_type = parent->sk_type;
- bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
-
- pi->imtu = l2cap_pi(parent)->imtu;
- pi->omtu = l2cap_pi(parent)->omtu;
- pi->conf_state = l2cap_pi(parent)->conf_state;
- pi->mode = l2cap_pi(parent)->mode;
- pi->fcs = l2cap_pi(parent)->fcs;
- pi->max_tx = l2cap_pi(parent)->max_tx;
- pi->tx_win = l2cap_pi(parent)->tx_win;
- pi->sec_level = l2cap_pi(parent)->sec_level;
- pi->role_switch = l2cap_pi(parent)->role_switch;
- pi->force_reliable = l2cap_pi(parent)->force_reliable;
- pi->flushable = l2cap_pi(parent)->flushable;
- } else {
- pi->imtu = L2CAP_DEFAULT_MTU;
- pi->omtu = 0;
- if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
- pi->mode = L2CAP_MODE_ERTM;
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
- } else {
- pi->mode = L2CAP_MODE_BASIC;
- }
- pi->max_tx = L2CAP_DEFAULT_MAX_TX;
- pi->fcs = L2CAP_FCS_CRC16;
- pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
- pi->sec_level = BT_SECURITY_LOW;
- pi->role_switch = 0;
- pi->force_reliable = 0;
- pi->flushable = BT_FLUSHABLE_OFF;
- }
-
- /* Default config options */
- pi->conf_len = 0;
- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
- skb_queue_head_init(TX_QUEUE(sk));
- skb_queue_head_init(SREJ_QUEUE(sk));
- skb_queue_head_init(BUSY_QUEUE(sk));
- INIT_LIST_HEAD(SREJ_LIST(sk));
-}
-
-static struct proto l2cap_proto = {
- .name = "L2CAP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct l2cap_pinfo)
-};
-
-struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
-{
- struct sock *sk;
-
- sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
- if (!sk)
- return NULL;
-
- sock_init_data(sock, sk);
- INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-
- sk->sk_destruct = l2cap_sock_destruct;
- sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
-
- setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
-
- bt_sock_link(&l2cap_sk_list, sk);
- return sk;
-}
-
-static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- sock->state = SS_UNCONNECTED;
-
- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
- sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
- return -EPERM;
-
- sock->ops = &l2cap_sock_ops;
-
- sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC);
- if (!sk)
- return -ENOMEM;
-
- l2cap_sock_init(sk, NULL);
- return 0;
-}
-
-const struct proto_ops l2cap_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = l2cap_sock_release,
- .bind = l2cap_sock_bind,
- .connect = l2cap_sock_connect,
- .listen = l2cap_sock_listen,
- .accept = l2cap_sock_accept,
- .getname = l2cap_sock_getname,
- .sendmsg = l2cap_sock_sendmsg,
- .recvmsg = l2cap_sock_recvmsg,
- .poll = bt_sock_poll,
- .ioctl = bt_sock_ioctl,
- .mmap = sock_no_mmap,
- .socketpair = sock_no_socketpair,
- .shutdown = l2cap_sock_shutdown,
- .setsockopt = l2cap_sock_setsockopt,
- .getsockopt = l2cap_sock_getsockopt
-};
-
-static const struct net_proto_family l2cap_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = l2cap_sock_create,
-};
-
-int __init l2cap_init_sockets(void)
-{
- int err;
-
- err = proto_register(&l2cap_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
- if (err < 0)
- goto error;
-
- BT_INFO("L2CAP socket layer initialized");
-
- return 0;
-
-error:
- BT_ERR("L2CAP socket registration failed");
- proto_unregister(&l2cap_proto);
- return err;
-}
-
-void l2cap_cleanup_sockets(void)
-{
- if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
- BT_ERR("L2CAP socket unregistration failed");
-
- proto_unregister(&l2cap_proto);
-}
diff --git a/trunk/net/bluetooth/mgmt.c b/trunk/net/bluetooth/mgmt.c
index b2bda83050a4..f827fd908380 100644
--- a/trunk/net/bluetooth/mgmt.c
+++ b/trunk/net/bluetooth/mgmt.c
@@ -32,16 +32,6 @@
#define MGMT_VERSION 0
#define MGMT_REVISION 1
-struct pending_cmd {
- struct list_head list;
- __u16 opcode;
- int index;
- void *cmd;
- struct sock *sk;
-};
-
-LIST_HEAD(cmd_list);
-
static int cmd_status(struct sock *sk, u16 cmd, u8 status)
{
struct sk_buff *skb;
@@ -69,26 +59,29 @@ static int cmd_status(struct sock *sk, u16 cmd, u8 status)
return 0;
}
-static int cmd_complete(struct sock *sk, u16 cmd, void *rp, size_t rp_len)
+static int read_version(struct sock *sk)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_complete *ev;
+ struct mgmt_rp_read_version *rp;
BT_DBG("sock %p", sk);
- skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
+ skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = (void *) skb_put(skb, sizeof(*hdr));
-
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
- hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
+ hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
- ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
- put_unaligned_le16(cmd, &ev->opcode);
- memcpy(ev->data, rp, rp_len);
+ ev = (void *) skb_put(skb, sizeof(*ev));
+ put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
+
+ rp = (void *) skb_put(skb, sizeof(*rp));
+ rp->version = MGMT_VERSION;
+ put_unaligned_le16(MGMT_REVISION, &rp->revision);
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
@@ -96,25 +89,16 @@ static int cmd_complete(struct sock *sk, u16 cmd, void *rp, size_t rp_len)
return 0;
}
-static int read_version(struct sock *sk)
-{
- struct mgmt_rp_read_version rp;
-
- BT_DBG("sock %p", sk);
-
- rp.version = MGMT_VERSION;
- put_unaligned_le16(MGMT_REVISION, &rp.revision);
-
- return cmd_complete(sk, MGMT_OP_READ_VERSION, &rp, sizeof(rp));
-}
-
static int read_index_list(struct sock *sk)
{
+ struct sk_buff *skb;
+ struct mgmt_hdr *hdr;
+ struct mgmt_ev_cmd_complete *ev;
struct mgmt_rp_read_index_list *rp;
struct list_head *p;
- size_t rp_len;
+ size_t body_len;
u16 count;
- int i, err;
+ int i;
BT_DBG("sock %p", sk);
@@ -125,43 +109,43 @@ static int read_index_list(struct sock *sk)
count++;
}
- rp_len = sizeof(*rp) + (2 * count);
- rp = kmalloc(rp_len, GFP_ATOMIC);
- if (!rp) {
- read_unlock(&hci_dev_list_lock);
+ body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
+ skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
+ if (!skb)
return -ENOMEM;
- }
+ hdr = (void *) skb_put(skb, sizeof(*hdr));
+ hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+ hdr->len = cpu_to_le16(body_len);
+
+ ev = (void *) skb_put(skb, sizeof(*ev));
+ put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
+
+ rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
put_unaligned_le16(count, &rp->num_controllers);
i = 0;
list_for_each(p, &hci_dev_list) {
struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
- hci_del_off_timer(d);
-
- set_bit(HCI_MGMT, &d->flags);
-
- if (test_bit(HCI_SETUP, &d->flags))
- continue;
-
put_unaligned_le16(d->id, &rp->index[i++]);
BT_DBG("Added hci%u", d->id);
}
read_unlock(&hci_dev_list_lock);
- err = cmd_complete(sk, MGMT_OP_READ_INDEX_LIST, rp, rp_len);
-
- kfree(rp);
+ if (sock_queue_rcv_skb(sk, skb) < 0)
+ kfree_skb(skb);
- return err;
+ return 0;
}
static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
{
- struct mgmt_rp_read_info rp;
- struct mgmt_cp_read_info *cp = (void *) data;
+ struct sk_buff *skb;
+ struct mgmt_hdr *hdr;
+ struct mgmt_ev_cmd_complete *ev;
+ struct mgmt_rp_read_info *rp;
+ struct mgmt_cp_read_info *cp;
struct hci_dev *hdev;
u16 dev_id;
@@ -170,143 +154,18 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
if (len != 2)
return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
-
- hci_del_off_timer(hdev);
-
- hci_dev_lock_bh(hdev);
-
- set_bit(HCI_MGMT, &hdev->flags);
-
- put_unaligned_le16(hdev->id, &rp.index);
- rp.type = hdev->dev_type;
-
- rp.powered = test_bit(HCI_UP, &hdev->flags);
- rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
- rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
- rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
-
- if (test_bit(HCI_AUTH, &hdev->flags))
- rp.sec_mode = 3;
- else if (hdev->ssp_mode > 0)
- rp.sec_mode = 4;
- else
- rp.sec_mode = 2;
-
- bacpy(&rp.bdaddr, &hdev->bdaddr);
- memcpy(rp.features, hdev->features, 8);
- memcpy(rp.dev_class, hdev->dev_class, 3);
- put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
- rp.hci_ver = hdev->hci_ver;
- put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return cmd_complete(sk, MGMT_OP_READ_INFO, &rp, sizeof(rp));
-}
-
-static void mgmt_pending_free(struct pending_cmd *cmd)
-{
- sock_put(cmd->sk);
- kfree(cmd->cmd);
- kfree(cmd);
-}
-
-static int mgmt_pending_add(struct sock *sk, u16 opcode, int index,
- void *data, u16 len)
-{
- struct pending_cmd *cmd;
-
- cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
- if (!cmd)
- return -ENOMEM;
-
- cmd->opcode = opcode;
- cmd->index = index;
-
- cmd->cmd = kmalloc(len, GFP_ATOMIC);
- if (!cmd->cmd) {
- kfree(cmd);
+ skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
+ if (!skb)
return -ENOMEM;
- }
-
- memcpy(cmd->cmd, data, len);
-
- cmd->sk = sk;
- sock_hold(sk);
-
- list_add(&cmd->list, &cmd_list);
-
- return 0;
-}
-
-static void mgmt_pending_foreach(u16 opcode, int index,
- void (*cb)(struct pending_cmd *cmd, void *data),
- void *data)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &cmd_list) {
- struct pending_cmd *cmd;
-
- cmd = list_entry(p, struct pending_cmd, list);
-
- if (cmd->opcode != opcode)
- continue;
-
- if (index >= 0 && cmd->index != index)
- continue;
-
- cb(cmd, data);
- }
-}
-
-static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
-{
- struct list_head *p;
-
- list_for_each(p, &cmd_list) {
- struct pending_cmd *cmd;
-
- cmd = list_entry(p, struct pending_cmd, list);
-
- if (cmd->opcode != opcode)
- continue;
-
- if (index >= 0 && cmd->index != index)
- continue;
-
- return cmd;
- }
-
- return NULL;
-}
-
-static void mgmt_pending_remove(u16 opcode, int index)
-{
- struct pending_cmd *cmd;
- cmd = mgmt_pending_find(opcode, index);
- if (cmd == NULL)
- return;
+ hdr = (void *) skb_put(skb, sizeof(*hdr));
+ hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+ hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
- list_del(&cmd->list);
- mgmt_pending_free(cmd);
-}
+ ev = (void *) skb_put(skb, sizeof(*ev));
+ put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
-static int set_powered(struct sock *sk, unsigned char *data, u16 len)
-{
- struct mgmt_mode *cp;
- struct hci_dev *hdev;
- u16 dev_id;
- int ret, up;
+ rp = (void *) skb_put(skb, sizeof(*rp));
cp = (void *) data;
dev_id = get_unaligned_le16(&cp->index);
@@ -314,151 +173,100 @@ static int set_powered(struct sock *sk, unsigned char *data, u16 len)
BT_DBG("request for hci%u", dev_id);
hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
+ if (!hdev) {
+ kfree_skb(skb);
+ return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
+ }
hci_dev_lock_bh(hdev);
- up = test_bit(HCI_UP, &hdev->flags);
- if ((cp->val && up) || (!cp->val && !up)) {
- ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
- ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
- goto failed;
- }
+ put_unaligned_le16(hdev->id, &rp->index);
+ rp->type = hdev->dev_type;
- ret = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
- if (ret < 0)
- goto failed;
+ rp->powered = test_bit(HCI_UP, &hdev->flags);
+ rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
+ rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
- if (cp->val)
- queue_work(hdev->workqueue, &hdev->power_on);
+ if (test_bit(HCI_AUTH, &hdev->flags))
+ rp->sec_mode = 3;
+ else if (hdev->ssp_mode > 0)
+ rp->sec_mode = 4;
else
- queue_work(hdev->workqueue, &hdev->power_off);
+ rp->sec_mode = 2;
- ret = 0;
+ bacpy(&rp->bdaddr, &hdev->bdaddr);
+ memcpy(rp->features, hdev->features, 8);
+ memcpy(rp->dev_class, hdev->dev_class, 3);
+ put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
+ rp->hci_ver = hdev->hci_ver;
+ put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
-failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
- return ret;
-}
-
-static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
-{
- struct mgmt_mode *cp;
- struct hci_dev *hdev;
- u16 dev_id;
- u8 scan;
- int err;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
- mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
- err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
- goto failed;
- }
-
- if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
- test_bit(HCI_PSCAN, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
- goto failed;
- }
-
- err = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
- if (err < 0)
- goto failed;
-
- scan = SCAN_PAGE;
-
- if (cp->val)
- scan |= SCAN_INQUIRY;
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
- if (err < 0)
- mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
+ if (sock_queue_rcv_skb(sk, skb) < 0)
+ kfree_skb(skb);
- return err;
+ return 0;
}
-static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
+int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
- struct mgmt_mode *cp;
- struct hci_dev *hdev;
- u16 dev_id;
- u8 scan;
+ unsigned char *buf;
+ struct mgmt_hdr *hdr;
+ u16 opcode, len;
int err;
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
+ BT_DBG("got %zu bytes", msglen);
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
+ if (msglen < sizeof(*hdr))
+ return -EINVAL;
- hci_dev_lock_bh(hdev);
+ buf = kmalloc(msglen, GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
- goto failed;
+ if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
+ err = -EFAULT;
+ goto done;
}
- if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
- mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
- err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
- goto failed;
- }
+ hdr = (struct mgmt_hdr *) buf;
+ opcode = get_unaligned_le16(&hdr->opcode);
+ len = get_unaligned_le16(&hdr->len);
- if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
- goto failed;
+ if (len != msglen - sizeof(*hdr)) {
+ err = -EINVAL;
+ goto done;
}
- err = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
- if (err < 0)
- goto failed;
-
- if (cp->val)
- scan = SCAN_PAGE;
- else
- scan = 0;
+ switch (opcode) {
+ case MGMT_OP_READ_VERSION:
+ err = read_version(sk);
+ break;
+ case MGMT_OP_READ_INDEX_LIST:
+ err = read_index_list(sk);
+ break;
+ case MGMT_OP_READ_INFO:
+ err = read_controller_info(sk, buf + sizeof(*hdr), len);
+ break;
+ default:
+ BT_DBG("Unknown op %u", opcode);
+ err = cmd_status(sk, opcode, 0x01);
+ break;
+ }
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
if (err < 0)
- mgmt_pending_remove(MGMT_OP_SET_CONNECTABLE, dev_id);
+ goto done;
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
+ err = msglen;
+done:
+ kfree(buf);
return err;
}
-static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
+static int mgmt_event(u16 event, void *data, u16 data_len)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
@@ -475,918 +283,26 @@ static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
memcpy(skb_put(skb, data_len), data, data_len);
- hci_send_to_sock(NULL, skb, skip_sk);
+ hci_send_to_sock(NULL, skb);
kfree_skb(skb);
return 0;
}
-static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
-{
- struct mgmt_mode rp;
-
- put_unaligned_le16(index, &rp.index);
- rp.val = val;
-
- return cmd_complete(sk, opcode, &rp, sizeof(rp));
-}
-
-static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
-{
- struct mgmt_mode *cp, ev;
- struct hci_dev *hdev;
- u16 dev_id;
- int err;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- if (cp->val)
- set_bit(HCI_PAIRABLE, &hdev->flags);
- else
- clear_bit(HCI_PAIRABLE, &hdev->flags);
-
- err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
- if (err < 0)
- goto failed;
-
- put_unaligned_le16(dev_id, &ev.index);
- ev.val = cp->val;
-
- err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
-
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static u8 get_service_classes(struct hci_dev *hdev)
-{
- struct list_head *p;
- u8 val = 0;
-
- list_for_each(p, &hdev->uuids) {
- struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
-
- val |= uuid->svc_hint;
- }
-
- return val;
-}
-
-static int update_class(struct hci_dev *hdev)
+int mgmt_index_added(u16 index)
{
- u8 cod[3];
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
- return 0;
-
- cod[0] = hdev->minor_class;
- cod[1] = hdev->major_class;
- cod[2] = get_service_classes(hdev);
+ struct mgmt_ev_index_added ev;
- if (memcmp(cod, hdev->dev_class, 3) == 0)
- return 0;
+ put_unaligned_le16(index, &ev.index);
- return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+ return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
}
-static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
+int mgmt_index_removed(u16 index)
{
- struct mgmt_cp_add_uuid *cp;
- struct hci_dev *hdev;
- struct bt_uuid *uuid;
- u16 dev_id;
- int err;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
+ struct mgmt_ev_index_added ev;
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
+ put_unaligned_le16(index, &ev.index);
- hci_dev_lock_bh(hdev);
-
- uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
- if (!uuid) {
- err = -ENOMEM;
- goto failed;
- }
-
- memcpy(uuid->uuid, cp->uuid, 16);
- uuid->svc_hint = cp->svc_hint;
-
- list_add(&uuid->list, &hdev->uuids);
-
- err = update_class(hdev);
- if (err < 0)
- goto failed;
-
- err = cmd_complete(sk, MGMT_OP_ADD_UUID, &dev_id, sizeof(dev_id));
-
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
-{
- struct list_head *p, *n;
- struct mgmt_cp_add_uuid *cp;
- struct hci_dev *hdev;
- u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- u16 dev_id;
- int err, found;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
- err = hci_uuids_clear(hdev);
- goto unlock;
- }
-
- found = 0;
-
- list_for_each_safe(p, n, &hdev->uuids) {
- struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
-
- if (memcmp(match->uuid, cp->uuid, 16) != 0)
- continue;
-
- list_del(&match->list);
- found++;
- }
-
- if (found == 0) {
- err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
- goto unlock;
- }
-
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
-
- err = cmd_complete(sk, MGMT_OP_REMOVE_UUID, &dev_id, sizeof(dev_id));
-
-unlock:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int set_dev_class(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_set_dev_class *cp;
- u16 dev_id;
- int err;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- BT_DBG("request for hci%u", dev_id);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- hdev->major_class = cp->major;
- hdev->minor_class = cp->minor;
-
- err = update_class(hdev);
-
- if (err == 0)
- err = cmd_complete(sk, MGMT_OP_SET_DEV_CLASS, &dev_id,
- sizeof(dev_id));
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_set_service_cache *cp;
- u16 dev_id;
- int err;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- BT_DBG("hci%u enable %d", dev_id, cp->enable);
-
- if (cp->enable) {
- set_bit(HCI_SERVICE_CACHE, &hdev->flags);
- err = 0;
- } else {
- clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
- err = update_class(hdev);
- }
-
- if (err == 0)
- err = cmd_complete(sk, MGMT_OP_SET_SERVICE_CACHE, &dev_id,
- sizeof(dev_id));
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int load_keys(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_load_keys *cp;
- u16 dev_id, key_count, expected_len;
- int i;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
- key_count = get_unaligned_le16(&cp->key_count);
-
- expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
- if (expected_len != len) {
- BT_ERR("load_keys: expected %u bytes, got %u bytes",
- len, expected_len);
- return -EINVAL;
- }
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
-
- BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
- key_count);
-
- hci_dev_lock_bh(hdev);
-
- hci_link_keys_clear(hdev);
-
- set_bit(HCI_LINK_KEYS, &hdev->flags);
-
- if (cp->debug_keys)
- set_bit(HCI_DEBUG_KEYS, &hdev->flags);
- else
- clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
-
- for (i = 0; i < key_count; i++) {
- struct mgmt_key_info *key = &cp->keys[i];
-
- hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
- key->pin_len);
- }
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return 0;
-}
-
-static int remove_key(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_remove_key *cp;
- struct hci_conn *conn;
- u16 dev_id;
- int err;
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- err = hci_remove_link_key(hdev, &cp->bdaddr);
- if (err < 0) {
- err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
- goto unlock;
- }
-
- err = 0;
-
- if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (conn) {
- struct hci_cp_disconnect dc;
-
- put_unaligned_le16(conn->handle, &dc.handle);
- dc.reason = 0x13; /* Remote User Terminated Connection */
- err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
- }
-
-unlock:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int disconnect(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_disconnect *cp;
- struct hci_cp_disconnect dc;
- struct hci_conn *conn;
- u16 dev_id;
- int err;
-
- BT_DBG("");
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN);
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_DISCONNECT, dev_id)) {
- err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY);
- goto failed;
- }
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (!conn) {
- err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN);
- goto failed;
- }
-
- err = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, dev_id, data, len);
- if (err < 0)
- goto failed;
-
- put_unaligned_le16(conn->handle, &dc.handle);
- dc.reason = 0x13; /* Remote User Terminated Connection */
-
- err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
- if (err < 0)
- mgmt_pending_remove(MGMT_OP_DISCONNECT, dev_id);
-
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int get_connections(struct sock *sk, unsigned char *data, u16 len)
-{
- struct mgmt_cp_get_connections *cp;
- struct mgmt_rp_get_connections *rp;
- struct hci_dev *hdev;
- struct list_head *p;
- size_t rp_len;
- u16 dev_id, count;
- int i, err;
-
- BT_DBG("");
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- count = 0;
- list_for_each(p, &hdev->conn_hash.list) {
- count++;
- }
-
- rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
- rp = kmalloc(rp_len, GFP_ATOMIC);
- if (!rp) {
- err = -ENOMEM;
- goto unlock;
- }
-
- put_unaligned_le16(dev_id, &rp->index);
- put_unaligned_le16(count, &rp->conn_count);
-
- read_lock(&hci_dev_list_lock);
-
- i = 0;
- list_for_each(p, &hdev->conn_hash.list) {
- struct hci_conn *c = list_entry(p, struct hci_conn, list);
-
- bacpy(&rp->conn[i++], &c->dst);
- }
-
- read_unlock(&hci_dev_list_lock);
-
- err = cmd_complete(sk, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
-
-unlock:
- kfree(rp);
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
- return err;
-}
-
-static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_pin_code_reply *cp;
- struct hci_cp_pin_code_reply reply;
- u16 dev_id;
- int err;
-
- BT_DBG("");
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
- goto failed;
- }
-
- err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
- if (err < 0)
- goto failed;
-
- bacpy(&reply.bdaddr, &cp->bdaddr);
- reply.pin_len = cp->pin_len;
- memcpy(reply.pin_code, cp->pin_code, 16);
-
- err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
- if (err < 0)
- mgmt_pending_remove(MGMT_OP_PIN_CODE_REPLY, dev_id);
-
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_pin_code_neg_reply *cp;
- u16 dev_id;
- int err;
-
- BT_DBG("");
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
- goto failed;
- }
-
- err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
- data, len);
- if (err < 0)
- goto failed;
-
- err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
- &cp->bdaddr);
- if (err < 0)
- mgmt_pending_remove(MGMT_OP_PIN_CODE_NEG_REPLY, dev_id);
-
-failed:
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return err;
-}
-
-static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
-{
- struct hci_dev *hdev;
- struct mgmt_cp_set_io_capability *cp;
- u16 dev_id;
-
- BT_DBG("");
-
- cp = (void *) data;
- dev_id = get_unaligned_le16(&cp->index);
-
- hdev = hci_dev_get(dev_id);
- if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
-
- hci_dev_lock_bh(hdev);
-
- hdev->io_capability = cp->io_capability;
-
- BT_DBG("%s IO capability set to 0x%02x", hdev->name,
- hdev->io_capability);
-
- hci_dev_unlock_bh(hdev);
- hci_dev_put(hdev);
-
- return cmd_complete(sk, MGMT_OP_SET_IO_CAPABILITY,
- &dev_id, sizeof(dev_id));
-}
-
-int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
-{
- unsigned char *buf;
- struct mgmt_hdr *hdr;
- u16 opcode, len;
- int err;
-
- BT_DBG("got %zu bytes", msglen);
-
- if (msglen < sizeof(*hdr))
- return -EINVAL;
-
- buf = kmalloc(msglen, GFP_ATOMIC);
- if (!buf)
- return -ENOMEM;
-
- if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
- err = -EFAULT;
- goto done;
- }
-
- hdr = (struct mgmt_hdr *) buf;
- opcode = get_unaligned_le16(&hdr->opcode);
- len = get_unaligned_le16(&hdr->len);
-
- if (len != msglen - sizeof(*hdr)) {
- err = -EINVAL;
- goto done;
- }
-
- switch (opcode) {
- case MGMT_OP_READ_VERSION:
- err = read_version(sk);
- break;
- case MGMT_OP_READ_INDEX_LIST:
- err = read_index_list(sk);
- break;
- case MGMT_OP_READ_INFO:
- err = read_controller_info(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_POWERED:
- err = set_powered(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_DISCOVERABLE:
- err = set_discoverable(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_CONNECTABLE:
- err = set_connectable(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_PAIRABLE:
- err = set_pairable(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_ADD_UUID:
- err = add_uuid(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_REMOVE_UUID:
- err = remove_uuid(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_DEV_CLASS:
- err = set_dev_class(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_SERVICE_CACHE:
- err = set_service_cache(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_LOAD_KEYS:
- err = load_keys(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_REMOVE_KEY:
- err = remove_key(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_DISCONNECT:
- err = disconnect(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_GET_CONNECTIONS:
- err = get_connections(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_PIN_CODE_REPLY:
- err = pin_code_reply(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_PIN_CODE_NEG_REPLY:
- err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
- break;
- case MGMT_OP_SET_IO_CAPABILITY:
- err = set_io_capability(sk, buf + sizeof(*hdr), len);
- break;
- default:
- BT_DBG("Unknown op %u", opcode);
- err = cmd_status(sk, opcode, 0x01);
- break;
- }
-
- if (err < 0)
- goto done;
-
- err = msglen;
-
-done:
- kfree(buf);
- return err;
-}
-
-int mgmt_index_added(u16 index)
-{
- struct mgmt_ev_index_added ev;
-
- put_unaligned_le16(index, &ev.index);
-
- return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_index_removed(u16 index)
-{
- struct mgmt_ev_index_added ev;
-
- put_unaligned_le16(index, &ev.index);
-
- return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
-}
-
-struct cmd_lookup {
- u8 val;
- struct sock *sk;
-};
-
-static void mode_rsp(struct pending_cmd *cmd, void *data)
-{
- struct mgmt_mode *cp = cmd->cmd;
- struct cmd_lookup *match = data;
-
- if (cp->val != match->val)
- return;
-
- send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
-
- list_del(&cmd->list);
-
- if (match->sk == NULL) {
- match->sk = cmd->sk;
- sock_hold(match->sk);
- }
-
- mgmt_pending_free(cmd);
-}
-
-int mgmt_powered(u16 index, u8 powered)
-{
- struct mgmt_mode ev;
- struct cmd_lookup match = { powered, NULL };
- int ret;
-
- mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
-
- put_unaligned_le16(index, &ev.index);
- ev.val = powered;
-
- ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return ret;
-}
-
-int mgmt_discoverable(u16 index, u8 discoverable)
-{
- struct mgmt_mode ev;
- struct cmd_lookup match = { discoverable, NULL };
- int ret;
-
- mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
- mode_rsp, &match);
-
- put_unaligned_le16(index, &ev.index);
- ev.val = discoverable;
-
- ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return ret;
-}
-
-int mgmt_connectable(u16 index, u8 connectable)
-{
- struct mgmt_mode ev;
- struct cmd_lookup match = { connectable, NULL };
- int ret;
-
- mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
-
- put_unaligned_le16(index, &ev.index);
- ev.val = connectable;
-
- ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return ret;
-}
-
-int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
-{
- struct mgmt_ev_new_key ev;
-
- memset(&ev, 0, sizeof(ev));
-
- put_unaligned_le16(index, &ev.index);
-
- bacpy(&ev.key.bdaddr, &key->bdaddr);
- ev.key.type = key->type;
- memcpy(ev.key.val, key->val, 16);
- ev.key.pin_len = key->pin_len;
- ev.old_key_type = old_key_type;
-
- return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_connected(u16 index, bdaddr_t *bdaddr)
-{
- struct mgmt_ev_connected ev;
-
- put_unaligned_le16(index, &ev.index);
- bacpy(&ev.bdaddr, bdaddr);
-
- return mgmt_event(MGMT_EV_CONNECTED, &ev, sizeof(ev), NULL);
-}
-
-static void disconnect_rsp(struct pending_cmd *cmd, void *data)
-{
- struct mgmt_cp_disconnect *cp = cmd->cmd;
- struct sock **sk = data;
- struct mgmt_rp_disconnect rp;
-
- put_unaligned_le16(cmd->index, &rp.index);
- bacpy(&rp.bdaddr, &cp->bdaddr);
-
- cmd_complete(cmd->sk, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
-
- *sk = cmd->sk;
- sock_hold(*sk);
-
- list_del(&cmd->list);
- mgmt_pending_free(cmd);
-}
-
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
-{
- struct mgmt_ev_disconnected ev;
- struct sock *sk = NULL;
- int err;
-
- mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
-
- put_unaligned_le16(index, &ev.index);
- bacpy(&ev.bdaddr, bdaddr);
-
- err = mgmt_event(MGMT_EV_DISCONNECTED, &ev, sizeof(ev), sk);
-
- if (sk)
- sock_put(sk);
-
- return err;
-}
-
-int mgmt_disconnect_failed(u16 index)
-{
- struct pending_cmd *cmd;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
- if (!cmd)
- return -ENOENT;
-
- err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
-
- list_del(&cmd->list);
- mgmt_pending_free(cmd);
-
- return err;
-}
-
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
-{
- struct mgmt_ev_connect_failed ev;
-
- put_unaligned_le16(index, &ev.index);
- bacpy(&ev.bdaddr, bdaddr);
- ev.status = status;
-
- return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
-{
- struct mgmt_ev_pin_code_request ev;
-
- put_unaligned_le16(index, &ev.index);
- bacpy(&ev.bdaddr, bdaddr);
-
- return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
-{
- struct pending_cmd *cmd;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
- if (!cmd)
- return -ENOENT;
-
- if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
- else
- err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
- bdaddr, sizeof(*bdaddr));
-
- list_del(&cmd->list);
- mgmt_pending_free(cmd);
-
- return err;
-}
-
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
-{
- struct pending_cmd *cmd;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
- if (!cmd)
- return -ENOENT;
-
- if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
- else
- err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
- bdaddr, sizeof(*bdaddr));
-
- list_del(&cmd->list);
- mgmt_pending_free(cmd);
-
- return err;
+ return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
}