Commit 69ab39ea authored by Johan Hedberg's avatar Johan Hedberg Committed by Gustavo F. Padovan

Bluetooth: Update mgmt_read_info and related mgmt messages

This patch updates the mgmt_read_info and related messages to the latest
management API which uses a bitfield of settings instead of individual
boolean values.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Acked-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent 590051de
...@@ -210,6 +210,7 @@ enum { ...@@ -210,6 +210,7 @@ enum {
#define LMP_EV4 0x01 #define LMP_EV4 0x01
#define LMP_EV5 0x02 #define LMP_EV5 0x02
#define LMP_NO_BREDR 0x20
#define LMP_LE 0x40 #define LMP_LE 0x40
#define LMP_SNIFF_SUBR 0x02 #define LMP_SNIFF_SUBR 0x02
......
...@@ -61,22 +61,29 @@ struct mgmt_rp_read_index_list { ...@@ -61,22 +61,29 @@ struct mgmt_rp_read_index_list {
/* Reserve one extra byte for names in management messages so that they /* Reserve one extra byte for names in management messages so that they
* are always guaranteed to be nul-terminated */ * are always guaranteed to be nul-terminated */
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) #define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
#define MGMT_SETTING_POWERED 0x00000001
#define MGMT_SETTING_CONNECTABLE 0x00000002
#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
#define MGMT_SETTING_DISCOVERABLE 0x00000008
#define MGMT_SETTING_PAIRABLE 0x00000010
#define MGMT_SETTING_LINK_SECURITY 0x00000020
#define MGMT_SETTING_SSP 0x00000040
#define MGMT_SETTING_BREDR 0x00000080
#define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200
#define MGMT_OP_READ_INFO 0x0004 #define MGMT_OP_READ_INFO 0x0004
struct mgmt_rp_read_info { struct mgmt_rp_read_info {
__u8 type;
__u8 powered;
__u8 connectable;
__u8 discoverable;
__u8 pairable;
__u8 sec_mode;
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 version;
__le16 manufacturer;
__le32 supported_settings;
__le32 current_settings;
__u8 dev_class[3]; __u8 dev_class[3];
__u8 features[8];
__u16 manufacturer;
__u8 hci_ver;
__u16 hci_rev;
__u8 name[MGMT_MAX_NAME_LENGTH]; __u8 name[MGMT_MAX_NAME_LENGTH];
__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed; } __packed;
struct mgmt_mode { struct mgmt_mode {
...@@ -285,7 +292,7 @@ struct mgmt_ev_controller_error { ...@@ -285,7 +292,7 @@ struct mgmt_ev_controller_error {
#define MGMT_EV_INDEX_REMOVED 0x0005 #define MGMT_EV_INDEX_REMOVED 0x0005
#define MGMT_EV_POWERED 0x0006 #define MGMT_EV_NEW_SETTINGS 0x0006
#define MGMT_EV_DISCOVERABLE 0x0007 #define MGMT_EV_DISCOVERABLE 0x0007
......
...@@ -242,6 +242,63 @@ static int read_index_list(struct sock *sk) ...@@ -242,6 +242,63 @@ static int read_index_list(struct sock *sk)
return err; return err;
} }
static u32 get_supported_settings(struct hci_dev *hdev)
{
u32 settings = 0;
settings |= MGMT_SETTING_POWERED;
settings |= MGMT_SETTING_CONNECTABLE;
settings |= MGMT_SETTING_FAST_CONNECTABLE;
settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_PAIRABLE;
if (hdev->features[6] & LMP_SIMPLE_PAIR)
settings |= MGMT_SETTING_SSP;
if (!(hdev->features[4] & LMP_NO_BREDR)) {
settings |= MGMT_SETTING_BREDR;
settings |= MGMT_SETTING_LINK_SECURITY;
}
if (hdev->features[4] & LMP_LE)
settings |= MGMT_SETTING_LE;
return settings;
}
static u32 get_current_settings(struct hci_dev *hdev)
{
u32 settings = 0;
if (test_bit(HCI_UP, &hdev->flags))
settings |= MGMT_SETTING_POWERED;
else
return settings;
if (test_bit(HCI_PSCAN, &hdev->flags))
settings |= MGMT_SETTING_CONNECTABLE;
if (test_bit(HCI_ISCAN, &hdev->flags))
settings |= MGMT_SETTING_DISCOVERABLE;
if (test_bit(HCI_PAIRABLE, &hdev->flags))
settings |= MGMT_SETTING_PAIRABLE;
if (!(hdev->features[4] & LMP_NO_BREDR))
settings |= MGMT_SETTING_BREDR;
if (hdev->extfeatures[0] & LMP_HOST_LE)
settings |= MGMT_SETTING_LE;
if (test_bit(HCI_AUTH, &hdev->flags))
settings |= MGMT_SETTING_LINK_SECURITY;
if (hdev->ssp_mode > 0)
settings |= MGMT_SETTING_SSP;
return settings;
}
static int read_controller_info(struct sock *sk, u16 index) static int read_controller_info(struct sock *sk, u16 index)
{ {
struct mgmt_rp_read_info rp; struct mgmt_rp_read_info rp;
...@@ -263,26 +320,16 @@ static int read_controller_info(struct sock *sk, u16 index) ...@@ -263,26 +320,16 @@ static int read_controller_info(struct sock *sk, u16 index)
memset(&rp, 0, sizeof(rp)); memset(&rp, 0, sizeof(rp));
rp.type = hdev->dev_type; bacpy(&rp.bdaddr, &hdev->bdaddr);
rp.powered = test_bit(HCI_UP, &hdev->flags); rp.version = hdev->hci_ver;
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)) put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
rp.sec_mode = 3;
else if (hdev->ssp_mode > 0) rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
rp.sec_mode = 4; rp.current_settings = cpu_to_le32(get_current_settings(hdev));
else
rp.sec_mode = 2;
bacpy(&rp.bdaddr, &hdev->bdaddr);
memcpy(rp.features, hdev->features, 8);
memcpy(rp.dev_class, hdev->dev_class, 3); 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);
memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
...@@ -365,13 +412,11 @@ static void mgmt_pending_remove(struct pending_cmd *cmd) ...@@ -365,13 +412,11 @@ static void mgmt_pending_remove(struct pending_cmd *cmd)
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
} }
static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val) static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
{ {
struct mgmt_mode rp; __le32 settings = cpu_to_le32(get_current_settings(hdev));
rp.val = val; return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
} }
static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
...@@ -398,7 +443,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -398,7 +443,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
up = test_bit(HCI_UP, &hdev->flags); up = test_bit(HCI_UP, &hdev->flags);
if ((cp->val && up) || (!cp->val && !up)) { if ((cp->val && up) || (!cp->val && !up)) {
err = send_mode_rsp(sk, index, MGMT_OP_SET_POWERED, cp->val); err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
goto failed; goto failed;
} }
...@@ -466,8 +511,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, ...@@ -466,8 +511,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) && if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
test_bit(HCI_PSCAN, &hdev->flags)) { test_bit(HCI_PSCAN, &hdev->flags)) {
err = send_mode_rsp(sk, index, MGMT_OP_SET_DISCOVERABLE, err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
cp->val);
goto failed; goto failed;
} }
...@@ -536,8 +580,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, ...@@ -536,8 +580,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
} }
if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
err = send_mode_rsp(sk, index, MGMT_OP_SET_CONNECTABLE, err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
cp->val);
goto failed; goto failed;
} }
...@@ -595,8 +638,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, ...@@ -595,8 +638,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
static int set_pairable(struct sock *sk, u16 index, unsigned char *data, static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
u16 len) u16 len)
{ {
struct mgmt_mode *cp, ev; struct mgmt_mode *cp;
struct hci_dev *hdev; struct hci_dev *hdev;
__le32 ev;
int err; int err;
cp = (void *) data; cp = (void *) data;
...@@ -619,13 +663,13 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, ...@@ -619,13 +663,13 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
else else
clear_bit(HCI_PAIRABLE, &hdev->flags); clear_bit(HCI_PAIRABLE, &hdev->flags);
err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val); err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
if (err < 0) if (err < 0)
goto failed; goto failed;
ev.val = cp->val; ev = cpu_to_le32(get_current_settings(hdev));
err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk); err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
failed: failed:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -2234,17 +2278,14 @@ int mgmt_index_removed(struct hci_dev *hdev) ...@@ -2234,17 +2278,14 @@ int mgmt_index_removed(struct hci_dev *hdev)
struct cmd_lookup { struct cmd_lookup {
u8 val; u8 val;
struct sock *sk; struct sock *sk;
struct hci_dev *hdev;
}; };
static void mode_rsp(struct pending_cmd *cmd, void *data) static void settings_rsp(struct pending_cmd *cmd, void *data)
{ {
struct mgmt_mode *cp = cmd->param;
struct cmd_lookup *match = data; struct cmd_lookup *match = data;
if (cp->val != match->val) send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
return;
send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
list_del(&cmd->list); list_del(&cmd->list);
...@@ -2258,20 +2299,21 @@ static void mode_rsp(struct pending_cmd *cmd, void *data) ...@@ -2258,20 +2299,21 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
int mgmt_powered(struct hci_dev *hdev, u8 powered) int mgmt_powered(struct hci_dev *hdev, u8 powered)
{ {
struct mgmt_mode ev; struct cmd_lookup match = { powered, NULL, hdev };
struct cmd_lookup match = { powered, NULL }; __le32 ev;
int ret; int ret;
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
if (!powered) { if (!powered) {
u8 status = ENETDOWN; u8 status = ENETDOWN;
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
} }
ev.val = powered; ev = cpu_to_le32(get_current_settings(hdev));
ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk); ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
match.sk);
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
...@@ -2281,17 +2323,16 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) ...@@ -2281,17 +2323,16 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
{ {
struct mgmt_mode ev; struct cmd_lookup match = { discoverable, NULL, hdev };
struct cmd_lookup match = { discoverable, NULL }; __le32 ev;
int ret; int ret;
mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
ev.val = discoverable; ev = cpu_to_le32(get_current_settings(hdev));
ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev), ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
match.sk); match.sk);
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
...@@ -2300,15 +2341,16 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) ...@@ -2300,15 +2341,16 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
int mgmt_connectable(struct hci_dev *hdev, u8 connectable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
{ {
struct mgmt_mode ev; __le32 ev;
struct cmd_lookup match = { connectable, NULL }; struct cmd_lookup match = { connectable, NULL, hdev };
int ret; int ret;
mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
&match);
ev.val = connectable; ev = cpu_to_le32(get_current_settings(hdev));
ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk); ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment