| /* |
| * WPA Supplicant - auto scan |
| * Copyright (c) 2012, Intel Corporation. All rights reserved. |
| * Copyright 2015 Intel Deutschland GmbH |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "includes.h" |
| |
| #include "common.h" |
| #include "config.h" |
| #include "wpa_supplicant_i.h" |
| #include "bss.h" |
| #include "scan.h" |
| #include "autoscan.h" |
| |
| |
| static const struct autoscan_ops * autoscan_modules[] = { |
| #ifdef CONFIG_AUTOSCAN_EXPONENTIAL |
| &autoscan_exponential_ops, |
| #endif /* CONFIG_AUTOSCAN_EXPONENTIAL */ |
| #ifdef CONFIG_AUTOSCAN_PERIODIC |
| &autoscan_periodic_ops, |
| #endif /* CONFIG_AUTOSCAN_PERIODIC */ |
| NULL |
| }; |
| |
| |
| static void request_scan(struct wpa_supplicant *wpa_s) |
| { |
| wpa_s->scan_req = MANUAL_SCAN_REQ; |
| |
| if (wpa_supplicant_req_sched_scan(wpa_s)) |
| wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0); |
| } |
| |
| |
| int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) |
| { |
| const char *name = wpa_s->conf->autoscan; |
| const char *params; |
| size_t nlen; |
| int i; |
| const struct autoscan_ops *ops = NULL; |
| struct sched_scan_plan *scan_plans; |
| |
| /* Give preference to scheduled scan plans if supported/configured */ |
| if (wpa_s->sched_scan_plans) { |
| wpa_printf(MSG_DEBUG, |
| "autoscan: sched_scan_plans set - use it instead"); |
| return 0; |
| } |
| |
| if (wpa_s->autoscan && wpa_s->autoscan_priv) { |
| wpa_printf(MSG_DEBUG, "autoscan: Already initialized"); |
| return 0; |
| } |
| |
| if (name == NULL) |
| return 0; |
| |
| params = os_strchr(name, ':'); |
| if (params == NULL) { |
| params = ""; |
| nlen = os_strlen(name); |
| } else { |
| nlen = params - name; |
| params++; |
| } |
| |
| for (i = 0; autoscan_modules[i]; i++) { |
| if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) { |
| ops = autoscan_modules[i]; |
| break; |
| } |
| } |
| |
| if (ops == NULL) { |
| wpa_printf(MSG_ERROR, "autoscan: Could not find module " |
| "matching the parameter '%s'", name); |
| return -1; |
| } |
| |
| scan_plans = os_malloc(sizeof(*wpa_s->sched_scan_plans)); |
| if (!scan_plans) |
| return -1; |
| |
| wpa_s->autoscan_params = NULL; |
| |
| wpa_s->autoscan_priv = ops->init(wpa_s, params); |
| if (!wpa_s->autoscan_priv) { |
| os_free(scan_plans); |
| return -1; |
| } |
| |
| scan_plans[0].interval = 5; |
| scan_plans[0].iterations = 0; |
| os_free(wpa_s->sched_scan_plans); |
| wpa_s->sched_scan_plans = scan_plans; |
| wpa_s->sched_scan_plans_num = 1; |
| wpa_s->autoscan = ops; |
| |
| wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with " |
| "parameters '%s'", ops->name, params); |
| if (!req_scan) |
| return 0; |
| |
| /* |
| * Cancelling existing scan requests, if any. |
| */ |
| wpa_supplicant_cancel_sched_scan(wpa_s); |
| wpa_supplicant_cancel_scan(wpa_s); |
| |
| /* |
| * Firing first scan, which will lead to call autoscan_notify_scan. |
| */ |
| request_scan(wpa_s); |
| |
| return 0; |
| } |
| |
| |
| void autoscan_deinit(struct wpa_supplicant *wpa_s) |
| { |
| if (wpa_s->autoscan && wpa_s->autoscan_priv) { |
| wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'", |
| wpa_s->autoscan->name); |
| wpa_s->autoscan->deinit(wpa_s->autoscan_priv); |
| wpa_s->autoscan = NULL; |
| wpa_s->autoscan_priv = NULL; |
| |
| wpa_s->scan_interval = 5; |
| |
| os_free(wpa_s->sched_scan_plans); |
| wpa_s->sched_scan_plans = NULL; |
| wpa_s->sched_scan_plans_num = 0; |
| } |
| } |
| |
| |
| int autoscan_notify_scan(struct wpa_supplicant *wpa_s, |
| struct wpa_scan_results *scan_res) |
| { |
| int interval; |
| |
| if (wpa_s->autoscan && wpa_s->autoscan_priv) { |
| interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv, |
| scan_res); |
| |
| if (interval <= 0) |
| return -1; |
| |
| wpa_s->scan_interval = interval; |
| wpa_s->sched_scan_plans[0].interval = interval; |
| |
| request_scan(wpa_s); |
| } |
| |
| return 0; |
| } |