diff options
author | Arman Uguray <armansito@chromium.org> | 2015-03-25 21:53:46 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-03-25 22:30:29 -0400 |
commit | fdf51784cd728e55daa0ca7b0ba16966afbfeae0 (patch) | |
tree | 03079295611a83b333d5e3cf68be069bb644ea61 /net | |
parent | 089fa8c09e7fd36b9db01c23c826fb7956f25a1e (diff) |
Bluetooth: Unify advertising data code paths
This patch simplifies the code paths for assembling the advertising data
used by advertising instances 0 and 1.
Signed-off-by: Arman Uguray <armansito@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/mgmt.c | 155 |
1 files changed, 64 insertions, 91 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index eab09b5a71df..fb2e764c6211 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -941,52 +941,73 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev) | |||
941 | return 0; | 941 | return 0; |
942 | } | 942 | } |
943 | 943 | ||
944 | static u8 create_default_adv_data(struct hci_dev *hdev, u8 *ptr) | 944 | static u8 get_current_adv_instance(struct hci_dev *hdev) |
945 | { | 945 | { |
946 | u8 ad_len = 0, flags = 0; | 946 | /* The "Set Advertising" setting supersedes the "Add Advertising" |
947 | 947 | * setting. Here we set the advertising data based on which | |
948 | flags |= get_adv_discov_flags(hdev); | 948 | * setting was set. When neither apply, default to the global settings, |
949 | * represented by instance "0". | ||
950 | */ | ||
951 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
952 | !hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
953 | return 0x01; | ||
949 | 954 | ||
950 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) | 955 | return 0x00; |
951 | flags |= LE_AD_NO_BREDR; | 956 | } |
952 | 957 | ||
953 | if (flags) { | 958 | static bool get_connectable(struct hci_dev *hdev) |
954 | BT_DBG("adv flags 0x%02x", flags); | 959 | { |
960 | struct mgmt_pending_cmd *cmd; | ||
955 | 961 | ||
956 | ptr[0] = 2; | 962 | /* If there's a pending mgmt command the flag will not yet have |
957 | ptr[1] = EIR_FLAGS; | 963 | * it's final value, so check for this first. |
958 | ptr[2] = flags; | 964 | */ |
965 | cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev); | ||
966 | if (cmd) { | ||
967 | struct mgmt_mode *cp = cmd->param; | ||
959 | 968 | ||
960 | ad_len += 3; | 969 | return cp->val; |
961 | ptr += 3; | ||
962 | } | 970 | } |
963 | 971 | ||
964 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { | 972 | return hci_dev_test_flag(hdev, HCI_CONNECTABLE); |
965 | ptr[0] = 2; | 973 | } |
966 | ptr[1] = EIR_TX_POWER; | ||
967 | ptr[2] = (u8) hdev->adv_tx_power; | ||
968 | 974 | ||
969 | ad_len += 3; | 975 | static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) |
970 | ptr += 3; | 976 | { |
971 | } | 977 | u32 flags; |
972 | 978 | ||
973 | return ad_len; | 979 | if (instance > 0x01) |
980 | return 0; | ||
981 | |||
982 | if (instance == 0x01) | ||
983 | return hdev->adv_instance.flags; | ||
984 | |||
985 | /* Instance 0 always manages the "Tx Power" and "Flags" fields */ | ||
986 | flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS; | ||
987 | |||
988 | /* For instance 0, assemble the flags from global settings */ | ||
989 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) || | ||
990 | get_connectable(hdev)) | ||
991 | flags |= MGMT_ADV_FLAG_CONNECTABLE; | ||
992 | |||
993 | return flags; | ||
974 | } | 994 | } |
975 | 995 | ||
976 | static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr) | 996 | static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) |
977 | { | 997 | { |
978 | u8 ad_len = 0, flags = 0; | 998 | u8 ad_len = 0, flags = 0; |
999 | u32 instance_flags = get_adv_instance_flags(hdev, instance); | ||
979 | 1000 | ||
980 | /* The Add Advertising command allows userspace to set both the general | 1001 | /* The Add Advertising command allows userspace to set both the general |
981 | * and limited discoverable flags. | 1002 | * and limited discoverable flags. |
982 | */ | 1003 | */ |
983 | if (hdev->adv_instance.flags & MGMT_ADV_FLAG_DISCOV) | 1004 | if (instance_flags & MGMT_ADV_FLAG_DISCOV) |
984 | flags |= LE_AD_GENERAL; | 1005 | flags |= LE_AD_GENERAL; |
985 | 1006 | ||
986 | if (hdev->adv_instance.flags & MGMT_ADV_FLAG_LIMITED_DISCOV) | 1007 | if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV) |
987 | flags |= LE_AD_LIMITED; | 1008 | flags |= LE_AD_LIMITED; |
988 | 1009 | ||
989 | if (flags || (hdev->adv_instance.flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) { | 1010 | if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) { |
990 | /* If a discovery flag wasn't provided, simply use the global | 1011 | /* If a discovery flag wasn't provided, simply use the global |
991 | * settings. | 1012 | * settings. |
992 | */ | 1013 | */ |
@@ -996,16 +1017,22 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr) | |||
996 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) | 1017 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) |
997 | flags |= LE_AD_NO_BREDR; | 1018 | flags |= LE_AD_NO_BREDR; |
998 | 1019 | ||
999 | ptr[0] = 0x02; | 1020 | /* If flags would still be empty, then there is no need to |
1000 | ptr[1] = EIR_FLAGS; | 1021 | * include the "Flags" AD field". |
1001 | ptr[2] = flags; | 1022 | */ |
1023 | if (flags) { | ||
1024 | ptr[0] = 0x02; | ||
1025 | ptr[1] = EIR_FLAGS; | ||
1026 | ptr[2] = flags; | ||
1002 | 1027 | ||
1003 | ad_len += 3; | 1028 | ad_len += 3; |
1004 | ptr += 3; | 1029 | ptr += 3; |
1030 | } | ||
1005 | } | 1031 | } |
1006 | 1032 | ||
1033 | /* Provide Tx Power only if we can provide a valid value for it */ | ||
1007 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID && | 1034 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID && |
1008 | (hdev->adv_instance.flags & MGMT_ADV_FLAG_TX_POWER)) { | 1035 | (instance_flags & MGMT_ADV_FLAG_TX_POWER)) { |
1009 | ptr[0] = 0x02; | 1036 | ptr[0] = 0x02; |
1010 | ptr[1] = EIR_TX_POWER; | 1037 | ptr[1] = EIR_TX_POWER; |
1011 | ptr[2] = (u8)hdev->adv_tx_power; | 1038 | ptr[2] = (u8)hdev->adv_tx_power; |
@@ -1014,9 +1041,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr) | |||
1014 | ptr += 3; | 1041 | ptr += 3; |
1015 | } | 1042 | } |
1016 | 1043 | ||
1017 | memcpy(ptr, hdev->adv_instance.adv_data, | 1044 | if (instance) { |
1018 | hdev->adv_instance.adv_data_len); | 1045 | memcpy(ptr, hdev->adv_instance.adv_data, |
1019 | ad_len += hdev->adv_instance.adv_data_len; | 1046 | hdev->adv_instance.adv_data_len); |
1047 | ad_len += hdev->adv_instance.adv_data_len; | ||
1048 | } | ||
1020 | 1049 | ||
1021 | return ad_len; | 1050 | return ad_len; |
1022 | } | 1051 | } |
@@ -1032,10 +1061,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance) | |||
1032 | 1061 | ||
1033 | memset(&cp, 0, sizeof(cp)); | 1062 | memset(&cp, 0, sizeof(cp)); |
1034 | 1063 | ||
1035 | if (instance) | 1064 | len = create_instance_adv_data(hdev, instance, cp.data); |
1036 | len = create_instance_adv_data(hdev, cp.data); | ||
1037 | else | ||
1038 | len = create_default_adv_data(hdev, cp.data); | ||
1039 | 1065 | ||
1040 | /* There's nothing to do if the data hasn't changed */ | 1066 | /* There's nothing to do if the data hasn't changed */ |
1041 | if (hdev->adv_data_len == len && | 1067 | if (hdev->adv_data_len == len && |
@@ -1050,59 +1076,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance) | |||
1050 | hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); | 1076 | hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); |
1051 | } | 1077 | } |
1052 | 1078 | ||
1053 | static u8 get_current_adv_instance(struct hci_dev *hdev) | ||
1054 | { | ||
1055 | /* The "Set Advertising" setting supersedes the "Add Advertising" | ||
1056 | * setting. Here we set the advertising data based on which | ||
1057 | * setting was set. When neither apply, default to the global settings, | ||
1058 | * represented by instance "0". | ||
1059 | */ | ||
1060 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
1061 | !hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
1062 | return 0x01; | ||
1063 | |||
1064 | return 0x00; | ||
1065 | } | ||
1066 | |||
1067 | static bool get_connectable(struct hci_dev *hdev) | ||
1068 | { | ||
1069 | struct mgmt_pending_cmd *cmd; | ||
1070 | |||
1071 | /* If there's a pending mgmt command the flag will not yet have | ||
1072 | * it's final value, so check for this first. | ||
1073 | */ | ||
1074 | cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev); | ||
1075 | if (cmd) { | ||
1076 | struct mgmt_mode *cp = cmd->param; | ||
1077 | |||
1078 | return cp->val; | ||
1079 | } | ||
1080 | |||
1081 | return hci_dev_test_flag(hdev, HCI_CONNECTABLE); | ||
1082 | } | ||
1083 | |||
1084 | static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) | ||
1085 | { | ||
1086 | u32 flags; | ||
1087 | |||
1088 | if (instance > 0x01) | ||
1089 | return 0; | ||
1090 | |||
1091 | if (instance == 1) | ||
1092 | return hdev->adv_instance.flags; | ||
1093 | |||
1094 | flags = 0; | ||
1095 | |||
1096 | /* For instance 0, assemble the flags from global settings */ | ||
1097 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) || | ||
1098 | get_connectable(hdev)) | ||
1099 | flags |= MGMT_ADV_FLAG_CONNECTABLE; | ||
1100 | |||
1101 | /* TODO: Add the rest of the flags */ | ||
1102 | |||
1103 | return flags; | ||
1104 | } | ||
1105 | |||
1106 | static void update_adv_data(struct hci_request *req) | 1079 | static void update_adv_data(struct hci_request *req) |
1107 | { | 1080 | { |
1108 | struct hci_dev *hdev = req->hdev; | 1081 | struct hci_dev *hdev = req->hdev; |