diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2012-02-28 10:18:30 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2012-03-01 16:55:58 -0500 |
commit | 0f4e68cf6e70fc219f219799c799a8a3e3c13100 (patch) | |
tree | 208b69caf263957571c5601c625157f46fea8f81 /net/bluetooth/mgmt.c | |
parent | 6a919082e9b82a0de20f1248a33f3b3f005cebaf (diff) |
Bluetooth: mgmt: Move command handlers into a table
By moving the command handlers into a table (the index being equal to
the opcode) the lookup is made a bit more efficient. Having a struct to
describe each handler also paves the way to add more meta-data for each
handler, e.g. the minimum message size for the command and allow
handling of common tasks like this in a centralized place.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 219 |
1 files changed, 79 insertions, 140 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cf8c8403571e..88a342a12593 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -267,7 +267,8 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, | |||
267 | return err; | 267 | return err; |
268 | } | 268 | } |
269 | 269 | ||
270 | static int read_version(struct sock *sk) | 270 | static int read_version(struct sock *sk, struct hci_dev *hdev, |
271 | void *data, u16 data_len) | ||
271 | { | 272 | { |
272 | struct mgmt_rp_read_version rp; | 273 | struct mgmt_rp_read_version rp; |
273 | 274 | ||
@@ -280,7 +281,8 @@ static int read_version(struct sock *sk) | |||
280 | sizeof(rp)); | 281 | sizeof(rp)); |
281 | } | 282 | } |
282 | 283 | ||
283 | static int read_commands(struct sock *sk) | 284 | static int read_commands(struct sock *sk, struct hci_dev *hdev, |
285 | void *data, u16 data_len) | ||
284 | { | 286 | { |
285 | struct mgmt_rp_read_commands *rp; | 287 | struct mgmt_rp_read_commands *rp; |
286 | u16 num_commands = ARRAY_SIZE(mgmt_commands); | 288 | u16 num_commands = ARRAY_SIZE(mgmt_commands); |
@@ -313,7 +315,8 @@ static int read_commands(struct sock *sk) | |||
313 | return err; | 315 | return err; |
314 | } | 316 | } |
315 | 317 | ||
316 | static int read_index_list(struct sock *sk) | 318 | static int read_index_list(struct sock *sk, struct hci_dev *hdev, |
319 | void *data, u16 data_len) | ||
317 | { | 320 | { |
318 | struct mgmt_rp_read_index_list *rp; | 321 | struct mgmt_rp_read_index_list *rp; |
319 | struct list_head *p; | 322 | struct list_head *p; |
@@ -627,7 +630,8 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) | |||
627 | } | 630 | } |
628 | } | 631 | } |
629 | 632 | ||
630 | static int read_controller_info(struct sock *sk, struct hci_dev *hdev) | 633 | static int read_controller_info(struct sock *sk, struct hci_dev *hdev, |
634 | void *data, u16 data_len) | ||
631 | { | 635 | { |
632 | struct mgmt_rp_read_info rp; | 636 | struct mgmt_rp_read_info rp; |
633 | 637 | ||
@@ -1689,7 +1693,8 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) | |||
1689 | } | 1693 | } |
1690 | } | 1694 | } |
1691 | 1695 | ||
1692 | static int get_connections(struct sock *sk, struct hci_dev *hdev) | 1696 | static int get_connections(struct sock *sk, struct hci_dev *hdev, |
1697 | void *data, u16 data_len) | ||
1693 | { | 1698 | { |
1694 | struct mgmt_rp_get_connections *rp; | 1699 | struct mgmt_rp_get_connections *rp; |
1695 | struct hci_conn *c; | 1700 | struct hci_conn *c; |
@@ -2015,9 +2020,9 @@ unlock: | |||
2015 | } | 2020 | } |
2016 | 2021 | ||
2017 | static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, | 2022 | static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, |
2018 | unsigned char *data, u16 len) | 2023 | void *data, u16 len) |
2019 | { | 2024 | { |
2020 | struct mgmt_addr_info *addr = (void *) data; | 2025 | struct mgmt_addr_info *addr = data; |
2021 | struct pending_cmd *cmd; | 2026 | struct pending_cmd *cmd; |
2022 | struct hci_conn *conn; | 2027 | struct hci_conn *conn; |
2023 | int err; | 2028 | int err; |
@@ -2240,7 +2245,8 @@ failed: | |||
2240 | return err; | 2245 | return err; |
2241 | } | 2246 | } |
2242 | 2247 | ||
2243 | static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev) | 2248 | static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, |
2249 | void *data, u16 data_len) | ||
2244 | { | 2250 | { |
2245 | struct pending_cmd *cmd; | 2251 | struct pending_cmd *cmd; |
2246 | int err; | 2252 | int err; |
@@ -2718,6 +2724,53 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
2718 | return 0; | 2724 | return 0; |
2719 | } | 2725 | } |
2720 | 2726 | ||
2727 | struct mgmt_handler { | ||
2728 | int (*func) (struct sock *sk, struct hci_dev *hdev, | ||
2729 | void *data, u16 data_len); | ||
2730 | } mgmt_handlers[] = { | ||
2731 | { NULL }, /* 0x0000 (no command) */ | ||
2732 | { read_version, }, | ||
2733 | { read_commands, }, | ||
2734 | { read_index_list, }, | ||
2735 | { read_controller_info, }, | ||
2736 | { set_powered, }, | ||
2737 | { set_discoverable, }, | ||
2738 | { set_connectable, }, | ||
2739 | { set_fast_connectable, }, | ||
2740 | { set_pairable, }, | ||
2741 | { set_link_security, }, | ||
2742 | { set_ssp, }, | ||
2743 | { set_hs, }, | ||
2744 | { set_le, }, | ||
2745 | { set_dev_class, }, | ||
2746 | { set_local_name, }, | ||
2747 | { add_uuid, }, | ||
2748 | { remove_uuid, }, | ||
2749 | { load_link_keys, }, | ||
2750 | { load_long_term_keys, }, | ||
2751 | { disconnect, }, | ||
2752 | { get_connections, }, | ||
2753 | { pin_code_reply, }, | ||
2754 | { pin_code_neg_reply, }, | ||
2755 | { set_io_capability, }, | ||
2756 | { pair_device, }, | ||
2757 | { cancel_pair_device, }, | ||
2758 | { unpair_device, }, | ||
2759 | { user_confirm_reply, }, | ||
2760 | { user_confirm_neg_reply, }, | ||
2761 | { user_passkey_reply, }, | ||
2762 | { user_passkey_neg_reply, }, | ||
2763 | { read_local_oob_data, }, | ||
2764 | { add_remote_oob_data, }, | ||
2765 | { remove_remote_oob_data, }, | ||
2766 | { start_discovery, }, | ||
2767 | { stop_discovery, }, | ||
2768 | { confirm_name, }, | ||
2769 | { block_device, }, | ||
2770 | { unblock_device, }, | ||
2771 | }; | ||
2772 | |||
2773 | |||
2721 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 2774 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
2722 | { | 2775 | { |
2723 | void *buf; | 2776 | void *buf; |
@@ -2751,150 +2804,36 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
2751 | goto done; | 2804 | goto done; |
2752 | } | 2805 | } |
2753 | 2806 | ||
2754 | if (opcode < MGMT_OP_READ_INFO) { | 2807 | if (index != MGMT_INDEX_NONE) { |
2755 | if (index != MGMT_INDEX_NONE) { | ||
2756 | err = cmd_status(sk, index, opcode, | ||
2757 | MGMT_STATUS_INVALID_PARAMS); | ||
2758 | goto done; | ||
2759 | } | ||
2760 | } else { | ||
2761 | hdev = hci_dev_get(index); | 2808 | hdev = hci_dev_get(index); |
2762 | if (!hdev) { | 2809 | if (!hdev) { |
2763 | err = cmd_status(sk, index, opcode, | 2810 | err = cmd_status(sk, index, opcode, |
2764 | MGMT_STATUS_INVALID_PARAMS); | 2811 | MGMT_STATUS_INVALID_PARAMS); |
2765 | goto done; | 2812 | goto done; |
2766 | } | 2813 | } |
2767 | |||
2768 | mgmt_init_hdev(sk, hdev); | ||
2769 | } | 2814 | } |
2770 | 2815 | ||
2771 | cp = buf + sizeof(*hdr); | 2816 | if (opcode >= ARRAY_SIZE(mgmt_handlers) || |
2772 | 2817 | mgmt_handlers[opcode].func == NULL) { | |
2773 | switch (opcode) { | ||
2774 | case MGMT_OP_READ_VERSION: | ||
2775 | err = read_version(sk); | ||
2776 | break; | ||
2777 | case MGMT_OP_READ_COMMANDS: | ||
2778 | err = read_commands(sk); | ||
2779 | break; | ||
2780 | case MGMT_OP_READ_INDEX_LIST: | ||
2781 | err = read_index_list(sk); | ||
2782 | break; | ||
2783 | case MGMT_OP_READ_INFO: | ||
2784 | err = read_controller_info(sk, hdev); | ||
2785 | break; | ||
2786 | case MGMT_OP_SET_POWERED: | ||
2787 | err = set_powered(sk, hdev, cp, len); | ||
2788 | break; | ||
2789 | case MGMT_OP_SET_DISCOVERABLE: | ||
2790 | err = set_discoverable(sk, hdev, cp, len); | ||
2791 | break; | ||
2792 | case MGMT_OP_SET_CONNECTABLE: | ||
2793 | err = set_connectable(sk, hdev, cp, len); | ||
2794 | break; | ||
2795 | case MGMT_OP_SET_FAST_CONNECTABLE: | ||
2796 | err = set_fast_connectable(sk, hdev, cp, len); | ||
2797 | break; | ||
2798 | case MGMT_OP_SET_PAIRABLE: | ||
2799 | err = set_pairable(sk, hdev, cp, len); | ||
2800 | break; | ||
2801 | case MGMT_OP_SET_LINK_SECURITY: | ||
2802 | err = set_link_security(sk, hdev, cp, len); | ||
2803 | break; | ||
2804 | case MGMT_OP_SET_SSP: | ||
2805 | err = set_ssp(sk, hdev, cp, len); | ||
2806 | break; | ||
2807 | case MGMT_OP_SET_HS: | ||
2808 | err = set_hs(sk, hdev, cp, len); | ||
2809 | break; | ||
2810 | case MGMT_OP_SET_LE: | ||
2811 | err = set_le(sk, hdev, cp, len); | ||
2812 | break; | ||
2813 | case MGMT_OP_ADD_UUID: | ||
2814 | err = add_uuid(sk, hdev, cp, len); | ||
2815 | break; | ||
2816 | case MGMT_OP_REMOVE_UUID: | ||
2817 | err = remove_uuid(sk, hdev, cp, len); | ||
2818 | break; | ||
2819 | case MGMT_OP_SET_DEV_CLASS: | ||
2820 | err = set_dev_class(sk, hdev, cp, len); | ||
2821 | break; | ||
2822 | case MGMT_OP_LOAD_LINK_KEYS: | ||
2823 | err = load_link_keys(sk, hdev, cp, len); | ||
2824 | break; | ||
2825 | case MGMT_OP_DISCONNECT: | ||
2826 | err = disconnect(sk, hdev, cp, len); | ||
2827 | break; | ||
2828 | case MGMT_OP_GET_CONNECTIONS: | ||
2829 | err = get_connections(sk, hdev); | ||
2830 | break; | ||
2831 | case MGMT_OP_PIN_CODE_REPLY: | ||
2832 | err = pin_code_reply(sk, hdev, cp, len); | ||
2833 | break; | ||
2834 | case MGMT_OP_PIN_CODE_NEG_REPLY: | ||
2835 | err = pin_code_neg_reply(sk, hdev, cp, len); | ||
2836 | break; | ||
2837 | case MGMT_OP_SET_IO_CAPABILITY: | ||
2838 | err = set_io_capability(sk, hdev, cp, len); | ||
2839 | break; | ||
2840 | case MGMT_OP_PAIR_DEVICE: | ||
2841 | err = pair_device(sk, hdev, cp, len); | ||
2842 | break; | ||
2843 | case MGMT_OP_CANCEL_PAIR_DEVICE: | ||
2844 | err = cancel_pair_device(sk, hdev, buf + sizeof(*hdr), len); | ||
2845 | break; | ||
2846 | case MGMT_OP_UNPAIR_DEVICE: | ||
2847 | err = unpair_device(sk, hdev, cp, len); | ||
2848 | break; | ||
2849 | case MGMT_OP_USER_CONFIRM_REPLY: | ||
2850 | err = user_confirm_reply(sk, hdev, cp, len); | ||
2851 | break; | ||
2852 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: | ||
2853 | err = user_confirm_neg_reply(sk, hdev, cp, len); | ||
2854 | break; | ||
2855 | case MGMT_OP_USER_PASSKEY_REPLY: | ||
2856 | err = user_passkey_reply(sk, hdev, cp, len); | ||
2857 | break; | ||
2858 | case MGMT_OP_USER_PASSKEY_NEG_REPLY: | ||
2859 | err = user_passkey_neg_reply(sk, hdev, cp, len); | ||
2860 | break; | ||
2861 | case MGMT_OP_SET_LOCAL_NAME: | ||
2862 | err = set_local_name(sk, hdev, cp, len); | ||
2863 | break; | ||
2864 | case MGMT_OP_READ_LOCAL_OOB_DATA: | ||
2865 | err = read_local_oob_data(sk, hdev); | ||
2866 | break; | ||
2867 | case MGMT_OP_ADD_REMOTE_OOB_DATA: | ||
2868 | err = add_remote_oob_data(sk, hdev, cp, len); | ||
2869 | break; | ||
2870 | case MGMT_OP_REMOVE_REMOTE_OOB_DATA: | ||
2871 | err = remove_remote_oob_data(sk, hdev, cp, len); | ||
2872 | break; | ||
2873 | case MGMT_OP_START_DISCOVERY: | ||
2874 | err = start_discovery(sk, hdev, cp, len); | ||
2875 | break; | ||
2876 | case MGMT_OP_STOP_DISCOVERY: | ||
2877 | err = stop_discovery(sk, hdev, cp, len); | ||
2878 | break; | ||
2879 | case MGMT_OP_CONFIRM_NAME: | ||
2880 | err = confirm_name(sk, hdev, cp, len); | ||
2881 | break; | ||
2882 | case MGMT_OP_BLOCK_DEVICE: | ||
2883 | err = block_device(sk, hdev, cp, len); | ||
2884 | break; | ||
2885 | case MGMT_OP_UNBLOCK_DEVICE: | ||
2886 | err = unblock_device(sk, hdev, cp, len); | ||
2887 | break; | ||
2888 | case MGMT_OP_LOAD_LONG_TERM_KEYS: | ||
2889 | err = load_long_term_keys(sk, hdev, cp, len); | ||
2890 | break; | ||
2891 | default: | ||
2892 | BT_DBG("Unknown op %u", opcode); | 2818 | BT_DBG("Unknown op %u", opcode); |
2893 | err = cmd_status(sk, index, opcode, | 2819 | err = cmd_status(sk, index, opcode, |
2894 | MGMT_STATUS_UNKNOWN_COMMAND); | 2820 | MGMT_STATUS_UNKNOWN_COMMAND); |
2895 | break; | 2821 | goto done; |
2822 | } | ||
2823 | |||
2824 | if ((hdev && opcode < MGMT_OP_READ_INFO) || | ||
2825 | (!hdev && opcode >= MGMT_OP_READ_INFO)) { | ||
2826 | err = cmd_status(sk, index, opcode, | ||
2827 | MGMT_STATUS_INVALID_PARAMS); | ||
2828 | goto done; | ||
2896 | } | 2829 | } |
2897 | 2830 | ||
2831 | if (hdev) | ||
2832 | mgmt_init_hdev(sk, hdev); | ||
2833 | |||
2834 | cp = buf + sizeof(*hdr); | ||
2835 | |||
2836 | err = mgmt_handlers[opcode].func(sk, hdev, cp, len); | ||
2898 | if (err < 0) | 2837 | if (err < 0) |
2899 | goto done; | 2838 | goto done; |
2900 | 2839 | ||