1/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *  * Redistributions of source code must retain the above copyright
7 *    notice, this list of conditions and the following disclaimer.
8 *  * Redistributions in binary form must reproduce the above
9 *    copyright notice, this list of conditions and the following
10 *    disclaimer in the documentation and/or other materials provided
11 *    with the distribution.
12 *  * Neither the name of The Linux Foundation nor the names of its
13 *    contributors may be used to endorse or promote products derived
14 *    from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#define LOG_TAG  "WifiHAL"
30#include <cutils/sched_policy.h>
31#include <unistd.h>
32
33#include <utils/Log.h>
34#include <time.h>
35
36#include "common.h"
37#include "cpp_bindings.h"
38#include "rtt.h"
39#include "wifi_hal.h"
40#include "wifihal_internal.h"
41
42/* Implementation of the API functions exposed in rtt.h */
43wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
44                                     wifi_rtt_capabilities *capabilities)
45{
46    int ret = WIFI_SUCCESS;
47    lowi_cb_table_t *lowiWifiHalApi = NULL;
48
49    if (iface == NULL) {
50        ALOGE("wifi_get_rtt_capabilities: NULL iface pointer provided."
51            " Exit.");
52        return WIFI_ERROR_INVALID_ARGS;
53    }
54
55    if (capabilities == NULL) {
56        ALOGE("wifi_get_rtt_capabilities: NULL capabilities pointer provided."
57            " Exit.");
58        return WIFI_ERROR_INVALID_ARGS;
59    }
60
61    /* RTT commands are diverted through LOWI interface. */
62    /* Open LOWI dynamic library, retrieve handler to LOWI APIs and initialize
63     * LOWI if it isn't up yet.
64     */
65    lowiWifiHalApi = getLowiCallbackTable(
66                ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
67    if (lowiWifiHalApi == NULL ||
68        lowiWifiHalApi->get_rtt_capabilities == NULL) {
69        ALOGE("wifi_get_rtt_capabilities: getLowiCallbackTable returned NULL or "
70            "the function pointer is NULL. Exit.");
71        ret = WIFI_ERROR_NOT_SUPPORTED;
72        goto cleanup;
73    }
74
75    ret = lowiWifiHalApi->get_rtt_capabilities(iface, capabilities);
76    if (ret != WIFI_SUCCESS) {
77        ALOGE("wifi_get_rtt_capabilities: lowi_wifihal_get_rtt_capabilities "
78            "returned error:%d. Exit.", ret);
79        goto cleanup;
80    }
81
82cleanup:
83    return (wifi_error)ret;
84}
85
86/* API to request RTT measurement */
87wifi_error wifi_rtt_range_request(wifi_request_id id,
88                                    wifi_interface_handle iface,
89                                    unsigned num_rtt_config,
90                                    wifi_rtt_config rtt_config[],
91                                    wifi_rtt_event_handler handler)
92{
93    int ret = WIFI_SUCCESS;
94    lowi_cb_table_t *lowiWifiHalApi = NULL;
95
96    if (iface == NULL) {
97        ALOGE("wifi_rtt_range_request: NULL iface pointer provided."
98            " Exit.");
99        return WIFI_ERROR_INVALID_ARGS;
100    }
101
102    if (rtt_config == NULL) {
103        ALOGE("wifi_rtt_range_request: NULL rtt_config pointer provided."
104            " Exit.");
105        return WIFI_ERROR_INVALID_ARGS;
106    }
107
108    if (num_rtt_config <= 0) {
109        ALOGE("wifi_rtt_range_request: number of destination BSSIDs to "
110            "measure RTT on = 0. Exit.");
111        return WIFI_ERROR_INVALID_ARGS;
112    }
113
114    if (handler.on_rtt_results == NULL) {
115        ALOGE("wifi_rtt_range_request: NULL capabilities pointer provided."
116            " Exit.");
117        return WIFI_ERROR_INVALID_ARGS;
118    }
119
120    /* RTT commands are diverted through LOWI interface. */
121    /* Open LOWI dynamic library, retrieve handler to LOWI APIs and initialize
122     * LOWI if it isn't up yet.
123     */
124    lowiWifiHalApi = getLowiCallbackTable(
125                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
126    if (lowiWifiHalApi == NULL ||
127        lowiWifiHalApi->rtt_range_request == NULL) {
128        ALOGE("wifi_rtt_range_request: getLowiCallbackTable returned NULL or "
129            "the function pointer is NULL. Exit.");
130        ret = WIFI_ERROR_NOT_SUPPORTED;
131        goto cleanup;
132    }
133
134    ret = lowiWifiHalApi->rtt_range_request(id,
135                                            iface,
136                                            num_rtt_config,
137                                            rtt_config,
138                                            handler);
139    if (ret != WIFI_SUCCESS) {
140        ALOGE("wifi_rtt_range_request: lowi_wifihal_rtt_range_request "
141            "returned error:%d. Exit.", ret);
142        goto cleanup;
143    }
144
145cleanup:
146    return (wifi_error)ret;
147}
148
149/* API to cancel RTT measurements */
150wifi_error wifi_rtt_range_cancel(wifi_request_id id,
151                                   wifi_interface_handle iface,
152                                   unsigned num_devices,
153                                   mac_addr addr[])
154{
155    int ret = WIFI_SUCCESS;
156    lowi_cb_table_t *lowiWifiHalApi = NULL;
157
158    if (iface == NULL) {
159        ALOGE("wifi_rtt_range_cancel: NULL iface pointer provided."
160            " Exit.");
161        return WIFI_ERROR_INVALID_ARGS;
162    }
163
164    if (addr == NULL) {
165        ALOGE("wifi_rtt_range_cancel: NULL addr pointer provided."
166            " Exit.");
167        return WIFI_ERROR_INVALID_ARGS;
168    }
169
170    if (num_devices <= 0) {
171        ALOGE("wifi_rtt_range_cancel: number of destination BSSIDs to "
172            "measure RTT on = 0. Exit.");
173        return WIFI_ERROR_INVALID_ARGS;
174    }
175
176    /* RTT commands are diverted through LOWI interface. */
177    /* Open LOWI dynamic library, retrieve handler to LOWI APIs and initialize
178     * LOWI if it isn't up yet.
179     */
180    lowiWifiHalApi = getLowiCallbackTable(
181                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
182    if (lowiWifiHalApi == NULL ||
183        lowiWifiHalApi->rtt_range_cancel == NULL) {
184        ALOGE("wifi_rtt_range_cancel: getLowiCallbackTable returned NULL or "
185            "the function pointer is NULL. Exit.");
186        ret = WIFI_ERROR_NOT_SUPPORTED;
187        goto cleanup;
188    }
189
190    ret = lowiWifiHalApi->rtt_range_cancel(id, num_devices, addr);
191    if (ret != WIFI_SUCCESS) {
192        ALOGE("wifi_rtt_range_cancel: lowi_wifihal_rtt_range_cancel "
193            "returned error:%d. Exit.", ret);
194        goto cleanup;
195    }
196
197cleanup:
198    return (wifi_error)ret;
199}
200
201// API to configure the LCI. Used in RTT Responder mode only
202wifi_error wifi_set_lci(wifi_request_id id, wifi_interface_handle iface,
203                        wifi_lci_information *lci)
204{
205    int ret = WIFI_SUCCESS;
206    lowi_cb_table_t *lowiWifiHalApi = NULL;
207
208    if (iface == NULL) {
209        ALOGE("%s: NULL iface pointer provided."
210            " Exit.", __FUNCTION__);
211        return WIFI_ERROR_INVALID_ARGS;
212    }
213
214    if (lci == NULL) {
215        ALOGE("%s: NULL lci pointer provided."
216            " Exit.", __FUNCTION__);
217        return WIFI_ERROR_INVALID_ARGS;
218    }
219
220    /* RTT commands are diverted through LOWI interface. */
221    /* Open LOWI dynamic library, retrieve handler to LOWI APIs and initialize
222     * LOWI if it isn't up yet.
223     */
224    lowiWifiHalApi = getLowiCallbackTable(
225                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
226    if (lowiWifiHalApi == NULL ||
227        lowiWifiHalApi->rtt_set_lci == NULL) {
228        ALOGE("%s: getLowiCallbackTable returned NULL or "
229            "the function pointer is NULL. Exit.", __FUNCTION__);
230        ret = WIFI_ERROR_NOT_SUPPORTED;
231        goto cleanup;
232    }
233
234    ret = lowiWifiHalApi->rtt_set_lci(id, iface, lci);
235    if (ret != WIFI_SUCCESS) {
236        ALOGE("%s: returned error:%d. Exit.",
237              __FUNCTION__, ret);
238        goto cleanup;
239    }
240
241cleanup:
242    return (wifi_error)ret;
243}
244
245// API to configure the LCR. Used in RTT Responder mode only.
246wifi_error wifi_set_lcr(wifi_request_id id, wifi_interface_handle iface,
247                        wifi_lcr_information *lcr)
248{
249    int ret = WIFI_SUCCESS;
250    lowi_cb_table_t *lowiWifiHalApi = NULL;
251
252    if (iface == NULL) {
253        ALOGE("%s: NULL iface pointer provided."
254            " Exit.", __FUNCTION__);
255        return WIFI_ERROR_INVALID_ARGS;
256    }
257
258    if (lcr == NULL) {
259        ALOGE("%s: NULL lcr pointer provided."
260            " Exit.", __FUNCTION__);
261        return WIFI_ERROR_INVALID_ARGS;
262    }
263
264    /* RTT commands are diverted through LOWI interface. */
265    /* Open LOWI dynamic library, retrieve handler to LOWI APIs and initialize
266     * LOWI if it isn't up yet.
267     */
268    lowiWifiHalApi = getLowiCallbackTable(
269                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
270    if (lowiWifiHalApi == NULL ||
271        lowiWifiHalApi->rtt_set_lcr == NULL) {
272        ALOGE("%s: getLowiCallbackTable returned NULL or "
273            "the function pointer is NULL. Exit.", __FUNCTION__);
274        ret = WIFI_ERROR_NOT_SUPPORTED;
275        goto cleanup;
276    }
277
278    ret = lowiWifiHalApi->rtt_set_lcr(id, iface, lcr);
279    if (ret != WIFI_SUCCESS) {
280        ALOGE("%s: returned error:%d. Exit.",
281              __FUNCTION__, ret);
282        goto cleanup;
283    }
284
285cleanup:
286    return (wifi_error)ret;
287}
288
289/*
290 * Get RTT responder information e.g. WiFi channel to enable responder on.
291 */
292wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
293                                      wifi_rtt_responder *responder_info)
294{
295    int ret = WIFI_SUCCESS;
296    lowi_cb_table_t *lowiWifiHalApi = NULL;
297
298    if (iface == NULL || responder_info == NULL) {
299        ALOGE("%s: iface : %p responder_info : %p", __FUNCTION__, iface,
300               responder_info);
301        return WIFI_ERROR_INVALID_ARGS;
302    }
303
304    /* Open LOWI dynamic library, retrieve handler to LOWI APIs */
305    lowiWifiHalApi = getLowiCallbackTable(
306                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
307    if (lowiWifiHalApi == NULL ||
308        lowiWifiHalApi->rtt_get_responder_info == NULL) {
309        ALOGE("%s: getLowiCallbackTable returned NULL or "
310            "the function pointer is NULL. Exit.", __FUNCTION__);
311        ret = WIFI_ERROR_NOT_SUPPORTED;
312        goto cleanup;
313    }
314
315    ret = lowiWifiHalApi->rtt_get_responder_info(iface, responder_info);
316    if (ret != WIFI_SUCCESS) {
317        ALOGE("%s: returned error:%d. Exit.",
318              __FUNCTION__, ret);
319        goto cleanup;
320    }
321
322cleanup:
323    return (wifi_error)ret;
324}
325
326/**
327 * Enable RTT responder mode.
328 * channel_hint - hint of the channel information where RTT responder should
329 *                be enabled on.
330 * max_duration_seconds - timeout of responder mode.
331 * responder_info - responder information e.g. channel used for RTT responder,
332 *                  NULL if responder is not enabled.
333 */
334wifi_error wifi_enable_responder(wifi_request_id id,
335                                 wifi_interface_handle iface,
336                                 wifi_channel_info channel_hint,
337                                 unsigned max_duration_seconds,
338                                 wifi_rtt_responder *responder_info)
339{
340    int ret = WIFI_SUCCESS;
341    lowi_cb_table_t *lowiWifiHalApi = NULL;
342
343    if (iface == NULL || responder_info == NULL) {
344        ALOGE("%s: iface : %p responder_info : %p", __FUNCTION__, iface, responder_info);
345        return WIFI_ERROR_INVALID_ARGS;
346    }
347
348    /* Open LOWI dynamic library, retrieve handler to LOWI APIs */
349    lowiWifiHalApi = getLowiCallbackTable(
350                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
351    if (lowiWifiHalApi == NULL ||
352        lowiWifiHalApi->enable_responder == NULL) {
353        ALOGE("%s: getLowiCallbackTable returned NULL or "
354            "the function pointer is NULL. Exit.", __FUNCTION__);
355        ret = WIFI_ERROR_NOT_SUPPORTED;
356        goto cleanup;
357    }
358
359    ret = lowiWifiHalApi->enable_responder(id, iface, channel_hint,
360                                           max_duration_seconds,
361                                           responder_info);
362    if (ret != WIFI_SUCCESS) {
363        ALOGE("%s: returned error:%d. Exit.",
364              __FUNCTION__, ret);
365        goto cleanup;
366    }
367
368cleanup:
369    return (wifi_error)ret;
370}
371
372
373/**
374 * Disable RTT responder mode.
375 */
376wifi_error wifi_disable_responder(wifi_request_id id,
377                                  wifi_interface_handle iface)
378
379{
380    int ret = WIFI_SUCCESS;
381    lowi_cb_table_t *lowiWifiHalApi = NULL;
382
383    if (iface == NULL) {
384        ALOGE("%s: iface : %p", __FUNCTION__, iface);
385        return WIFI_ERROR_INVALID_ARGS;
386    }
387
388    /* Open LOWI dynamic library, retrieve handler to LOWI APIs */
389    lowiWifiHalApi = getLowiCallbackTable(
390                    ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
391    if (lowiWifiHalApi == NULL ||
392        lowiWifiHalApi->disable_responder == NULL) {
393        ALOGE("%s: getLowiCallbackTable returned NULL or "
394            "the function pointer is NULL. Exit.", __FUNCTION__);
395        ret = WIFI_ERROR_NOT_SUPPORTED;
396        goto cleanup;
397    }
398
399    ret = lowiWifiHalApi->disable_responder(id, iface);
400    if (ret != WIFI_SUCCESS) {
401        ALOGE("%s: returned error:%d. Exit.",
402              __FUNCTION__, ret);
403        goto cleanup;
404    }
405
406cleanup:
407    return (wifi_error)ret;
408}
409