1#include <stdint.h>
2#include <fcntl.h>
3#include <sys/socket.h>
4#include <netlink/genl/genl.h>
5#include <netlink/genl/family.h>
6#include <netlink/genl/ctrl.h>
7#include <linux/rtnetlink.h>
8#include <netpacket/packet.h>
9#include <linux/filter.h>
10#include <linux/errqueue.h>
11
12#include <linux/pkt_sched.h>
13#include <netlink/object-api.h>
14#include <netlink/netlink.h>
15#include <netlink/socket.h>
16#include <netlink-types.h>
17
18#include "nl80211_copy.h"
19
20#include "sync.h"
21
22#define LOG_TAG  "WifiHAL"
23
24#include <utils/Log.h>
25
26#include "wifi_hal.h"
27#include "common.h"
28#include "cpp_bindings.h"
29
30typedef enum {
31
32    RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
33    RTT_SUBCMD_CANCEL_CONFIG,
34    RTT_SUBCMD_GETCAPABILITY,
35} RTT_SUB_COMMAND;
36
37typedef enum {
38    RTT_ATTRIBUTE_TARGET_CNT,
39    RTT_ATTRIBUTE_TARGET_INFO,
40    RTT_ATTRIBUTE_TARGET_MAC,
41    RTT_ATTRIBUTE_TARGET_TYPE,
42    RTT_ATTRIBUTE_TARGET_PEER,
43    RTT_ATTRIBUTE_TARGET_CHAN,
44    RTT_ATTRIBUTE_TARGET_MODE,
45    RTT_ATTRIBUTE_TARGET_INTERVAL,
46    RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT,
47    RTT_ATTRIBUTE_TARGET_NUM_PKT,
48    RTT_ATTRIBUTE_TARGET_NUM_RETRY,
49
50} GSCAN_ATTRIBUTE;
51class GetRttCapabilitiesCommand : public WifiCommand
52{
53    wifi_rtt_capabilities *mCapabilities;
54public:
55    GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
56        : WifiCommand(iface, 0), mCapabilities(capabitlites)
57    {
58        memset(mCapabilities, 0, sizeof(*mCapabilities));
59    }
60
61    virtual int create() {
62        ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
63
64        int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY);
65        if (ret < 0) {
66            return ret;
67        }
68
69        return ret;
70    }
71
72protected:
73    virtual int handleResponse(WifiEvent& reply) {
74
75        ALOGD("In GetRttCapabilitiesCommand::handleResponse");
76
77        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
78            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
79            return NL_SKIP;
80        }
81
82        int id = reply.get_vendor_id();
83        int subcmd = reply.get_vendor_subcmd();
84
85        void *data = reply.get_vendor_data();
86        int len = reply.get_vendor_data_len();
87
88        ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
89                    sizeof(*mCapabilities));
90
91        memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
92
93        return NL_OK;
94    }
95};
96
97
98class RttCommand : public WifiCommand
99{
100    unsigned numRttParams;
101    static const int MAX_RESULTS = 64;
102    wifi_rtt_result rttResults[MAX_RESULTS];
103    wifi_rtt_config *rttParams;
104    wifi_rtt_event_handler rttHandler;
105public:
106    RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
107                wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
108        : WifiCommand(iface, id), numRttParams(num_rtt_config), rttParams(rtt_config),
109         rttHandler(handler)
110    { }
111
112
113    int createSetupRequest(WifiRequest& request) {
114        int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG);
115        if (result < 0) {
116            return result;
117        }
118
119        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
120        result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams);
121        if (result < 0) {
122            return result;
123        }
124        nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO);
125        for (unsigned i = 0; i < numRttParams; i++) {
126
127            nlattr *attr2 = request.attr_start(i);
128            if (attr2 == NULL) {
129                return WIFI_ERROR_OUT_OF_MEMORY;
130            }
131
132            result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
133            if (result < 0) {
134                return result;
135            }
136            result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
137            if (result < 0) {
138                return result;
139            }
140            result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
141            if (result < 0) {
142                return result;
143            }
144            result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel,
145                     sizeof(wifi_channel_info));
146            if (result < 0) {
147                return result;
148            }
149            result = request.put_u8(RTT_ATTRIBUTE_TARGET_MODE, rttParams[i].continuous);
150            if (result < 0) {
151                return result;
152            }
153            result = request.put_u32(RTT_ATTRIBUTE_TARGET_INTERVAL, rttParams[i].interval);
154            if (result < 0) {
155                return result;
156            }
157            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT,
158                     rttParams[i].num_measurements);
159            if (result < 0) {
160                return result;
161            }
162            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_PKT,
163                     rttParams[i].num_samples_per_measurement);
164            if (result < 0) {
165                return result;
166            }
167            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY,
168                     rttParams[i].num_retries_per_measurement);
169            if (result < 0) {
170                return result;
171            }
172            request.attr_end(attr2);
173        }
174
175        request.attr_end(rtt_config);
176        request.attr_end(data);
177        return WIFI_SUCCESS;
178    }
179
180    int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
181        int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG);
182        if (result < 0) {
183            return result;
184        }
185
186        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
187        request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
188        for(unsigned i = 0; i < num_devices; i++) {
189            result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
190            if (result < 0) {
191                return result;
192            }
193        }
194        request.attr_end(data);
195        return result;
196    }
197    int start() {
198        ALOGD("Setting RTT configuration");
199        WifiRequest request(familyId(), ifaceId());
200        int result = createSetupRequest(request);
201        if (result != WIFI_SUCCESS) {
202            ALOGE("failed to create setup request; result = %d", result);
203            return result;
204        }
205
206        result = requestResponse(request);
207        if (result != WIFI_SUCCESS) {
208            ALOGE("failed to configure RTT setup; result = %d", result);
209            return result;
210        }
211
212        registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
213        ALOGI("Successfully started RTT operation");
214        return result;
215    }
216
217    virtual int cancel() {
218        ALOGD("Stopping RTT");
219
220        WifiRequest request(familyId(), ifaceId());
221        int result = createTeardownRequest(request, 0, NULL);
222        if (result != WIFI_SUCCESS) {
223            ALOGE("failed to create stop request; result = %d", result);
224        } else {
225            result = requestResponse(request);
226            if (result != WIFI_SUCCESS) {
227                ALOGE("failed to stop scan; result = %d", result);
228            }
229        }
230
231        unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
232        return WIFI_SUCCESS;
233    }
234
235    int cancel_specific(unsigned num_devices, mac_addr addr[]) {
236        ALOGD("Stopping scan");
237
238        WifiRequest request(familyId(), ifaceId());
239        int result = createTeardownRequest(request, num_devices, addr);
240        if (result != WIFI_SUCCESS) {
241            ALOGE("failed to create stop request; result = %d", result);
242        } else {
243            result = requestResponse(request);
244            if (result != WIFI_SUCCESS) {
245                ALOGE("failed to stop RTT; result = %d", result);
246            }
247        }
248
249        unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
250        return WIFI_SUCCESS;
251    }
252
253    virtual int handleResponse(WifiEvent& reply) {
254        /* Nothing to do on response! */
255        return NL_SKIP;
256    }
257
258    virtual int handleEvent(WifiEvent& event) {
259        ALOGI("Got an RTT event");
260
261        // event.log();
262
263        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
264        int len = event.get_vendor_data_len();
265
266        if (vendor_data == NULL || len == 0) {
267            ALOGI("No rtt results found");
268        }
269
270        unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
271        wifi_unregister_cmd(wifiHandle(), id());
272
273        memset(rttResults, 0, sizeof(wifi_rtt_result) * MAX_RESULTS);
274
275        int num = len / sizeof(wifi_rtt_result);
276        num = min(MAX_RESULTS, num);
277        memcpy(rttResults, event.get_vendor_data(), num * sizeof(wifi_rtt_result));
278        ALOGI("Retrieved %d rtt results", num);
279
280        (*rttHandler.on_rtt_results)(id(), num, rttResults);
281        return NL_SKIP;
282    }
283};
284
285
286/* API to request RTT measurement */
287wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
288        unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
289{
290    wifi_handle handle = getWifiHandle(iface);
291
292    RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
293    wifi_register_cmd(handle, id, cmd);
294    return (wifi_error)cmd->start();
295}
296
297/* API to cancel RTT measurements */
298wifi_error wifi_rtt_range_cancel(wifi_request_id id,  wifi_interface_handle iface,
299        unsigned num_devices, mac_addr addr[])
300{
301    wifi_handle handle = getWifiHandle(iface);
302    RttCommand *cmd = (RttCommand *)wifi_unregister_cmd(handle, id);
303    if (cmd) {
304        cmd->cancel_specific(num_devices, addr);
305        cmd->releaseRef();
306        return WIFI_SUCCESS;
307    }
308
309    return WIFI_ERROR_INVALID_ARGS;
310}
311
312/* API to get RTT capability */
313wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
314        wifi_rtt_capabilities *capabilities)
315{
316    GetRttCapabilitiesCommand command(iface, capabilities);
317    return (wifi_error) command.requestResponse();
318}
319
320
321