device: Set disconnect timer to zero for fast disconnection
[platform/upstream/bluez.git] / monitor / msft.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011-2014  Intel Corporation
6  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2.1 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
30 #define _GNU_SOURCE
31 #endif
32 #include <stdio.h>
33 #include <inttypes.h>
34
35 #include "lib/bluetooth.h"
36 #include "lib/uuid.h"
37
38 #include "src/shared/util.h"
39 #include "display.h"
40 #include "packet.h"
41 #include "vendor.h"
42 #include "msft.h"
43
44 #define COLOR_COMMAND           COLOR_BLUE
45 #define COLOR_COMMAND_UNKNOWN   COLOR_WHITE_BG
46
47 static void null_cmd(const void *data, uint16_t size)
48 {
49 }
50
51 static void null_rsp(const void *data, uint16_t size)
52 {
53 }
54
55 static void read_supported_features_rsp(const void *data, uint16_t size)
56 {
57         const struct msft_rsp_read_supported_features *rsp = data;
58
59         packet_print_features_msft(rsp->features);
60         print_field("Event prefix length: %u", rsp->evt_prefix_len);
61         print_field("Event prefix:");
62         packet_hexdump(rsp->evt_prefix, rsp->evt_prefix_len);
63         packet_set_msft_evt_prefix(rsp->evt_prefix, rsp->evt_prefix_len);
64 }
65
66 static void monitor_rssi_cmd(const void *data, uint16_t size)
67 {
68         const struct msft_cmd_monitor_rssi *cmd = data;
69
70         print_field("Connection handle: 0x%04x", cmd->handle);
71         packet_print_rssi("RSSI threshold high", cmd->rssi_high);
72         packet_print_rssi("RSSI threshold low", cmd->rssi_low);
73         print_field("RSSI threshold low time interval: %u sec (0x%2.2x)",
74                                                 cmd->rssi_low_interval,
75                                                 cmd->rssi_low_interval);
76         print_field("RSSI sampling period: %u msec (0x%2.2x)",
77                                                 cmd->rssi_period * 100,
78                                                 cmd->rssi_period);
79 }
80
81 static void cancel_monitor_rssi_cmd(const void *data, uint16_t size)
82 {
83         const struct msft_cmd_cancel_monitor_rssi *cmd = data;
84
85         print_field("Connection handle: 0x%04x", cmd->handle);
86 }
87
88 static void le_monitor_advertisement_cmd(const void *data, uint16_t size)
89 {
90         const struct msft_cmd_le_monitor_adv *cmd = data;
91         const struct msft_le_monitor_adv_patterns *patterns;
92         const struct msft_le_monitor_adv_uuid *uuid;
93         const struct msft_le_monitor_adv_irk *irk;
94         const struct msft_le_monitor_adv_addr *addr;
95         const char *str;
96         char uuidstr[MAX_LEN_UUID_STR];
97
98         packet_print_rssi("RSSI threshold high", cmd->rssi_high);
99         packet_print_rssi("RSSI threshold low", cmd->rssi_low);
100         print_field("RSSI threshold low time interval: %u sec (0x%2.2x)",
101                                                 cmd->rssi_low_interval,
102                                                 cmd->rssi_low_interval);
103         print_field("RSSI sampling period: %u msec (0x%2.2x)",
104                                                 cmd->rssi_period * 100,
105                                                 cmd->rssi_period);
106
107         switch (cmd->type) {
108         case MSFT_LE_MONITOR_ADV_PATTERN:
109                 print_field("Type: Pattern (0x%2.2x)", cmd->type);
110                 patterns = (void *)cmd->data;
111                 print_field("Number of patterns: %u", patterns->num);
112                 packet_hexdump((void *)patterns->data,
113                                size - (sizeof(*cmd) + sizeof(*patterns)));
114                 break;
115         case MSFT_LE_MONITOR_ADV_UUID:
116                 print_field("Type: UUID (0x%2.2x)", cmd->type);
117                 uuid = (void *)cmd->data;
118
119                 switch (uuid->type) {
120                 case 0x01:
121                         str = bt_uuid16_to_str(uuid->value.u16);
122                         print_field("UUID: %s (0x%4.4x)", str, uuid->value.u16);
123                         break;
124                 case 0x02:
125                         str = bt_uuid32_to_str(uuid->value.u32);
126                         print_field("UUID: %s (0x%8.8x)", str, uuid->value.u32);
127                         break;
128                 case 0x03:
129                         sprintf(uuidstr, "%8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x",
130                                 get_le32(uuid->value.u128 + 12),
131                                 get_le16(uuid->value.u128 + 10),
132                                 get_le16(uuid->value.u128 + 8),
133                                 get_le16(uuid->value.u128 + 6),
134                                 get_le32(uuid->value.u128 + 2),
135                                 get_le16(uuid->value.u128 + 0));
136                         str = bt_uuidstr_to_str(uuidstr);
137                         print_field("UUID: %s (%s)", str, uuidstr);
138                         break;
139                 default:
140                         packet_hexdump((void *)&uuid->value,
141                                         size - sizeof(*cmd));
142                         break;
143                 }
144                 break;
145         case MSFT_LE_MONITOR_ADV_IRK:
146                 print_field("Type: IRK (0x%2.2x)", cmd->type);
147                 irk = (void *)cmd->data;
148                 print_field("IRK:");
149                 packet_hexdump(irk->irk, size - sizeof(*cmd));
150                 break;
151         case MSFT_LE_MONITOR_ADV_ADDR:
152                 print_field("Type: Adderss (0x%2.2x)", cmd->type);
153                 addr = (void *)cmd->data;
154                 packet_print_addr(NULL, addr->addr, addr->type);
155                 break;
156         default:
157                 print_field("Type: Unknown (0x%2.2x)", cmd->type);
158                 packet_hexdump(cmd->data, size - sizeof(*cmd));
159                 break;
160         }
161 }
162
163 static void le_monitor_advertisement_rsp(const void *data, uint16_t size)
164 {
165         const struct msft_rsp_le_monitor_adv *rsp = data;
166
167         print_field("Monitor handle: %u", rsp->handle);
168 }
169
170 static void le_cancel_monitor_adv_cmd(const void *data, uint16_t size)
171 {
172         const struct msft_cmd_le_cancel_monitor_adv *cmd = data;
173
174         print_field("Monitor handle: %u", cmd->handle);
175 }
176
177 static void set_adv_filter_enable_cmd(const void *data, uint16_t size)
178 {
179         const struct msft_cmd_le_monitor_adv_enable *cmd = data;
180         const char *str;
181
182         switch (cmd->enable) {
183         case 0x00:
184                 str = "Current allow list";
185                 break;
186         case 0x01:
187                 str = "All filter conditions";
188                 break;
189         default:
190                 str = "Reserved";
191                 break;
192         }
193
194         print_field("Enable: %s (0x%2.2x)", str, cmd->enable);
195 }
196
197 typedef void (*func_t) (const void *data, uint16_t size);
198
199 static const struct {
200         uint8_t code;
201         const char *str;
202         func_t cmd_func;
203         func_t rsp_func;
204 } cmd_table[] = {
205         { 0x00, "Read Supported Features",
206                         null_cmd,
207                         read_supported_features_rsp },
208         { 0x01, "Monitor RSSI",
209                         monitor_rssi_cmd },
210         { 0x02, "Cancel Monitor RSSI",
211                         cancel_monitor_rssi_cmd },
212         { 0x03, "LE Monitor Advertisement",
213                         le_monitor_advertisement_cmd,
214                         le_monitor_advertisement_rsp },
215         { 0x04, "LE Cancel Monitor Advertisement",
216                         le_cancel_monitor_adv_cmd },
217         { 0x05, "LE Set Advertisement Filter Enable",
218                         set_adv_filter_enable_cmd,
219                         null_rsp },
220         { 0x06, "Read Absolute RSSI" },
221         { }
222 };
223
224 static void msft_cmd(uint16_t index, const void *data, uint8_t size)
225 {
226         uint8_t code = get_u8(data);
227         const char *code_color, *code_str = NULL;
228         func_t code_func = NULL;
229         int i;
230
231         for (i = 0; cmd_table[i].str; i++) {
232                 if (cmd_table[i].code == code) {
233                         code_str = cmd_table[i].str;
234                         code_func = cmd_table[i].cmd_func;
235                         break;
236                 }
237         }
238
239         if (code_str) {
240                 if (code_func)
241                         code_color = COLOR_COMMAND;
242                 else
243                         code_color = COLOR_COMMAND_UNKNOWN;
244         } else {
245                 code_color = COLOR_COMMAND_UNKNOWN;
246                 code_str = "Unknown";
247         }
248
249         print_indent(6, code_color, "", code_str, COLOR_OFF,
250                                                 " (0x%2.2x)", code);
251
252         if (code_func)
253                 code_func(data, size);
254         else
255                 packet_hexdump(data + 1, size - 1);
256 }
257
258 static void msft_rsp(uint16_t index, const void *data, uint8_t size)
259 {
260         uint8_t status = get_u8(data);
261         uint8_t code = get_u8(data + 1);
262         const char *code_color, *code_str = NULL;
263         func_t code_func = NULL;
264         int i;
265
266         for (i = 0; cmd_table[i].str; i++) {
267                 if (cmd_table[i].code == code) {
268                         code_str = cmd_table[i].str;
269                         code_func = cmd_table[i].rsp_func;
270                         break;
271                 }
272         }
273
274         if (code_str) {
275                 if (code_func)
276                         code_color = COLOR_COMMAND;
277                 else
278                         code_color = COLOR_COMMAND_UNKNOWN;
279         } else {
280                 code_color = COLOR_COMMAND_UNKNOWN;
281                 code_str = "Unknown";
282         }
283
284         print_indent(6, code_color, "", code_str, COLOR_OFF,
285                                                 " (0x%2.2x)", code);
286
287         packet_print_error("Status", status);
288
289         if (code_func)
290                 code_func(data, size);
291         else
292                 packet_hexdump(data + 2, size - 2);
293 }
294
295 static const struct vendor_ocf vendor_ocf_entry = {
296         0x000, "Extension", msft_cmd, 1, false, msft_rsp, 2, false
297 };
298
299 const struct vendor_ocf *msft_vendor_ocf(void)
300 {
301         return &vendor_ocf_entry;
302 }
303
304 static void msft_evt(struct timeval *tv, uint16_t index,
305                         const void *data, uint8_t size)
306 {
307         packet_hexdump(data, size);
308 }
309
310 static const struct vendor_evt vendor_evt_entry = {
311         0x00, "Extension", msft_evt, 1, false
312 };
313
314 const struct vendor_evt *msft_vendor_evt(void)
315 {
316         return &vendor_evt_entry;
317 }