2016-05-05 19:13:45 +02:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Wireless daemon for Linux
|
|
|
|
*
|
2018-01-18 22:36:38 +01:00
|
|
|
* Copyright (C) 2013-2018 Intel Corporation. All rights reserved.
|
2016-05-05 19:13:45 +02:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2016-06-14 18:31:48 +02:00
|
|
|
#include <stdio.h>
|
2016-06-16 22:37:50 +02:00
|
|
|
#include <errno.h>
|
2017-01-18 12:36:32 +01:00
|
|
|
#include <linux/if_ether.h>
|
2016-06-14 18:31:48 +02:00
|
|
|
|
2016-05-05 19:13:45 +02:00
|
|
|
#include <ell/ell.h>
|
|
|
|
|
2016-06-15 17:54:13 +02:00
|
|
|
#include "src/iwd.h"
|
2016-06-14 18:14:45 +02:00
|
|
|
#include "src/common.h"
|
2016-06-16 22:37:50 +02:00
|
|
|
#include "src/util.h"
|
2016-06-15 17:54:13 +02:00
|
|
|
#include "src/ie.h"
|
2016-11-02 23:46:19 +01:00
|
|
|
#include "src/handshake.h"
|
2016-06-15 17:54:13 +02:00
|
|
|
#include "src/wiphy.h"
|
|
|
|
#include "src/scan.h"
|
2016-06-14 18:19:05 +02:00
|
|
|
#include "src/netdev.h"
|
2016-06-14 18:14:45 +02:00
|
|
|
#include "src/dbus.h"
|
|
|
|
#include "src/network.h"
|
2018-07-22 14:15:18 +02:00
|
|
|
#include "src/knownnetworks.h"
|
2016-05-05 19:13:45 +02:00
|
|
|
#include "src/device.h"
|
2016-09-14 16:09:44 +02:00
|
|
|
#include "src/watchlist.h"
|
2017-09-22 05:06:45 +02:00
|
|
|
#include "src/ap.h"
|
2018-07-17 23:16:03 +02:00
|
|
|
#include "src/adhoc.h"
|
2018-09-01 00:44:10 +02:00
|
|
|
#include "src/station.h"
|
2016-05-05 19:13:45 +02:00
|
|
|
|
2016-06-16 23:23:00 +02:00
|
|
|
struct device {
|
|
|
|
uint32_t index;
|
|
|
|
struct l_dbus_message *connect_pending;
|
|
|
|
struct l_dbus_message *disconnect_pending;
|
2017-04-29 03:53:28 +02:00
|
|
|
uint8_t preauth_bssid[ETH_ALEN];
|
2017-05-20 01:39:38 +02:00
|
|
|
struct signal_agent *signal_agent;
|
2016-06-16 23:23:00 +02:00
|
|
|
|
|
|
|
struct wiphy *wiphy;
|
|
|
|
struct netdev *netdev;
|
2018-09-01 00:44:10 +02:00
|
|
|
struct station *station;
|
2016-09-22 19:57:10 +02:00
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
bool powered : 1;
|
2018-01-18 22:36:38 +01:00
|
|
|
|
|
|
|
uint32_t ap_roam_watch;
|
2016-06-16 23:23:00 +02:00
|
|
|
};
|
|
|
|
|
2017-05-20 01:39:38 +02:00
|
|
|
struct signal_agent {
|
|
|
|
char *owner;
|
|
|
|
char *path;
|
|
|
|
unsigned int disconnect_watch;
|
|
|
|
};
|
|
|
|
|
2018-08-18 06:40:49 +02:00
|
|
|
static uint32_t netdev_watch;
|
2016-06-16 22:37:50 +02:00
|
|
|
|
2017-08-14 14:31:19 +02:00
|
|
|
static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
|
|
|
|
void *user_data);
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
/* TODO: Remove when Station/Device is split */
|
2018-09-04 23:26:33 +02:00
|
|
|
static bool device_is_busy(struct device *device)
|
2016-06-14 18:34:35 +02:00
|
|
|
{
|
2018-09-04 17:40:45 +02:00
|
|
|
if (!device->powered || !device->station)
|
|
|
|
return false;
|
|
|
|
|
2018-09-04 23:26:33 +02:00
|
|
|
return station_is_busy(device->station);
|
2016-06-14 18:34:35 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 20:48:18 +02:00
|
|
|
void device_disassociated(struct device *device)
|
2016-12-23 11:38:08 +01:00
|
|
|
{
|
2018-09-05 01:00:48 +02:00
|
|
|
struct station *station = device->station;
|
|
|
|
|
2016-12-23 11:38:08 +01:00
|
|
|
l_debug("%d", device->index);
|
|
|
|
|
2018-09-05 01:25:31 +02:00
|
|
|
station_reset_connection_state(station);
|
2016-06-14 18:14:45 +02:00
|
|
|
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_DISCONNECTED);
|
2016-10-10 22:38:03 +02:00
|
|
|
|
2018-09-05 01:00:48 +02:00
|
|
|
if (station->autoconnect)
|
|
|
|
station_enter_state(station, STATION_STATE_AUTOCONNECT);
|
2016-06-14 18:14:45 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 07:03:21 +02:00
|
|
|
static void device_disconnect_event(struct device *device)
|
2016-06-16 18:21:12 +02:00
|
|
|
{
|
2018-09-04 21:07:44 +02:00
|
|
|
struct station *station = device->station;
|
|
|
|
|
2016-06-16 18:21:12 +02:00
|
|
|
l_debug("%d", device->index);
|
|
|
|
|
|
|
|
if (device->connect_pending) {
|
2018-09-04 21:07:44 +02:00
|
|
|
struct network *network = station->connected_network;
|
2016-06-16 18:21:12 +02:00
|
|
|
|
|
|
|
dbus_pending_reply(&device->connect_pending,
|
|
|
|
dbus_error_failed(device->connect_pending));
|
|
|
|
|
|
|
|
network_connect_failed(network);
|
|
|
|
}
|
|
|
|
|
|
|
|
device_disassociated(device);
|
|
|
|
}
|
|
|
|
|
2017-03-31 14:43:02 +02:00
|
|
|
static void device_reassociate_cb(struct netdev *netdev,
|
|
|
|
enum netdev_result result,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
struct station *station = device->station;
|
2017-03-31 14:43:02 +02:00
|
|
|
|
|
|
|
l_debug("%d, result: %d", device->index, result);
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (station->state != STATION_STATE_ROAMING)
|
2017-03-31 14:43:02 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (result == NETDEV_RESULT_OK) {
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roamed(station);
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_CONNECTED);
|
2017-03-31 14:43:02 +02:00
|
|
|
} else
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-03-31 14:43:02 +02:00
|
|
|
}
|
|
|
|
|
2017-01-23 12:38:39 +01:00
|
|
|
static void device_fast_transition_cb(struct netdev *netdev,
|
|
|
|
enum netdev_result result,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
struct station *station = device->station;
|
2017-01-23 12:38:39 +01:00
|
|
|
|
|
|
|
l_debug("%d, result: %d", device->index, result);
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (station->state != STATION_STATE_ROAMING)
|
2017-01-23 12:38:39 +01:00
|
|
|
return;
|
|
|
|
|
2017-02-18 03:30:49 +01:00
|
|
|
if (result == NETDEV_RESULT_OK) {
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roamed(station);
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_CONNECTED);
|
2017-02-18 03:30:49 +01:00
|
|
|
} else
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-01-23 12:38:39 +01:00
|
|
|
}
|
|
|
|
|
2017-04-29 03:53:28 +02:00
|
|
|
static void device_transition_reassociate(struct device *device,
|
|
|
|
struct scan_bss *bss,
|
|
|
|
struct handshake_state *new_hs)
|
|
|
|
{
|
2018-09-01 23:21:28 +02:00
|
|
|
struct station *station = device->station;
|
|
|
|
|
2018-09-04 21:09:22 +02:00
|
|
|
if (netdev_reassociate(device->netdev, bss, station->connected_bss,
|
2017-08-14 14:31:19 +02:00
|
|
|
new_hs, device_netdev_event,
|
|
|
|
device_reassociate_cb, device) < 0) {
|
2017-04-29 03:53:28 +02:00
|
|
|
handshake_state_free(new_hs);
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-04-29 03:53:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-01 23:21:28 +02:00
|
|
|
station->connected_bss = bss;
|
2018-09-04 20:48:18 +02:00
|
|
|
station->preparing_roam = false;
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_ROAMING);
|
2017-04-29 03:53:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool bss_match_bssid(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const struct scan_bss *bss = a;
|
|
|
|
const uint8_t *bssid = b;
|
|
|
|
|
|
|
|
return !memcmp(bss->addr, bssid, sizeof(bss->addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void device_preauthenticate_cb(struct netdev *netdev,
|
|
|
|
enum netdev_result result,
|
|
|
|
const uint8_t *pmk, void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-01 00:44:10 +02:00
|
|
|
struct station *station = device->station;
|
2018-09-04 21:07:44 +02:00
|
|
|
struct network *connected = station->connected_network;
|
2017-04-29 03:53:28 +02:00
|
|
|
struct scan_bss *bss;
|
|
|
|
struct handshake_state *new_hs;
|
|
|
|
|
|
|
|
l_debug("%d, result: %d", device->index, result);
|
|
|
|
|
2018-09-04 20:48:18 +02:00
|
|
|
if (!station->preparing_roam || result == NETDEV_RESULT_ABORTED)
|
2017-04-29 03:53:28 +02:00
|
|
|
return;
|
|
|
|
|
2018-09-01 23:21:28 +02:00
|
|
|
bss = l_queue_find(device->station->bss_list, bss_match_bssid,
|
2017-04-29 03:53:28 +02:00
|
|
|
device->preauth_bssid);
|
|
|
|
if (!bss) {
|
|
|
|
l_error("Roam target BSS not found");
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-04-29 03:53:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-01 00:44:10 +02:00
|
|
|
new_hs = station_handshake_setup(station, connected, bss);
|
2017-04-29 03:53:28 +02:00
|
|
|
if (!new_hs) {
|
|
|
|
l_error("device_handshake_setup failed");
|
|
|
|
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-04-29 03:53:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == NETDEV_RESULT_OK) {
|
|
|
|
uint8_t pmkid[16];
|
|
|
|
uint8_t rsne_buf[300];
|
|
|
|
struct ie_rsn_info rsn_info;
|
|
|
|
|
2018-03-15 12:06:53 +01:00
|
|
|
handshake_state_set_pmk(new_hs, pmk, 32);
|
2017-04-29 03:53:28 +02:00
|
|
|
handshake_state_set_authenticator_address(new_hs,
|
|
|
|
device->preauth_bssid);
|
|
|
|
handshake_state_set_supplicant_address(new_hs,
|
|
|
|
netdev_get_address(device->netdev));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rebuild the RSNE to include the negotiated PMKID. Note
|
2018-08-25 03:54:24 +02:00
|
|
|
* supplicant_ie can't be a WPA IE here, including because
|
|
|
|
* the WPA IE doesn't have a capabilities field and
|
2017-04-29 03:53:28 +02:00
|
|
|
* target_rsne->preauthentication would have been false in
|
|
|
|
* device_transition_start.
|
|
|
|
*/
|
2018-08-25 03:54:24 +02:00
|
|
|
ie_parse_rsne_from_data(new_hs->supplicant_ie,
|
|
|
|
new_hs->supplicant_ie[1] + 2,
|
2017-04-29 03:53:28 +02:00
|
|
|
&rsn_info);
|
|
|
|
|
|
|
|
handshake_state_get_pmkid(new_hs, pmkid);
|
|
|
|
|
|
|
|
rsn_info.num_pmkids = 1;
|
|
|
|
rsn_info.pmkids = pmkid;
|
|
|
|
|
|
|
|
ie_build_rsne(&rsn_info, rsne_buf);
|
2018-08-25 03:54:24 +02:00
|
|
|
handshake_state_set_supplicant_rsn(new_hs, rsne_buf);
|
2017-04-29 03:53:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
device_transition_reassociate(device, bss, new_hs);
|
|
|
|
}
|
|
|
|
|
2018-09-04 20:48:18 +02:00
|
|
|
void device_transition_start(struct device *device, struct scan_bss *bss)
|
2017-01-23 12:38:38 +01:00
|
|
|
{
|
2018-09-04 21:07:44 +02:00
|
|
|
struct station *station = device->station;
|
2017-01-23 12:38:39 +01:00
|
|
|
struct handshake_state *hs = netdev_get_handshake(device->netdev);
|
2018-09-04 21:07:44 +02:00
|
|
|
struct network *connected = station->connected_network;
|
2018-09-01 00:44:10 +02:00
|
|
|
enum security security = network_get_security(connected);
|
2017-01-23 12:38:39 +01:00
|
|
|
uint16_t mdid;
|
2017-03-31 14:43:02 +02:00
|
|
|
struct handshake_state *new_hs;
|
2017-04-29 03:53:28 +02:00
|
|
|
struct ie_rsn_info cur_rsne, target_rsne;
|
2017-01-23 12:38:39 +01:00
|
|
|
|
|
|
|
l_debug("%d, target %s", device->index,
|
|
|
|
util_address_to_string(bss->addr));
|
|
|
|
|
2018-01-18 22:36:38 +01:00
|
|
|
/* Reset AP roam flag, at this point the roaming behaves the same */
|
2018-09-04 20:48:18 +02:00
|
|
|
station->ap_directed_roaming = false;
|
2018-01-18 22:36:38 +01:00
|
|
|
|
2017-01-23 12:38:39 +01:00
|
|
|
if (hs->mde)
|
|
|
|
ie_parse_mobility_domain_from_data(hs->mde, hs->mde[1] + 2,
|
|
|
|
&mdid, NULL, NULL);
|
|
|
|
|
|
|
|
/* Can we use Fast Transition? */
|
|
|
|
if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid) {
|
|
|
|
/*
|
|
|
|
* There's no need to regenerate the RSNE because neither
|
|
|
|
* the AKM nor cipher suite can change:
|
|
|
|
*
|
|
|
|
* 12.5.2: "If the FTO selects a pairwise cipher suite in
|
|
|
|
* the RSNE that is different from the ones used in the
|
|
|
|
* Initial mobility domain association, then the AP shall
|
|
|
|
* reject the Authentication Request with status code 19
|
|
|
|
* (i.e., Invalid Pairwise Cipher)."
|
|
|
|
*/
|
|
|
|
if (netdev_fast_transition(device->netdev, bss,
|
|
|
|
device_fast_transition_cb) < 0) {
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-01-23 12:38:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-01 23:21:28 +02:00
|
|
|
station->connected_bss = bss;
|
2018-09-04 20:48:18 +02:00
|
|
|
station->preparing_roam = false;
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_ROAMING);
|
2017-01-23 12:38:39 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-31 14:43:02 +02:00
|
|
|
/* Non-FT transition */
|
|
|
|
|
2017-04-29 03:53:28 +02:00
|
|
|
/*
|
|
|
|
* FT not available, we can try preauthentication if available.
|
|
|
|
* 802.11-2012 section 11.5.9.2:
|
|
|
|
* "A STA shall not use preauthentication within the same mobility
|
|
|
|
* domain if AKM suite type 00-0F-AC:3 or 00-0F-AC:4 is used in
|
|
|
|
* the current association."
|
|
|
|
*/
|
|
|
|
if (security == SECURITY_8021X &&
|
2018-09-04 20:48:18 +02:00
|
|
|
!station->roam_no_orig_ap &&
|
2018-09-04 21:09:22 +02:00
|
|
|
scan_bss_get_rsn_info(station->connected_bss,
|
2017-04-29 03:53:28 +02:00
|
|
|
&cur_rsne) >= 0 &&
|
|
|
|
scan_bss_get_rsn_info(bss, &target_rsne) >= 0 &&
|
|
|
|
cur_rsne.preauthentication &&
|
|
|
|
target_rsne.preauthentication) {
|
|
|
|
/*
|
|
|
|
* Both the current and the target AP support
|
|
|
|
* pre-authentication and we're using 8021x authentication so
|
|
|
|
* attempt to pre-authenticate and reassociate afterwards.
|
|
|
|
* If the pre-authentication fails or times out we simply
|
|
|
|
* won't supply any PMKID when reassociating.
|
|
|
|
* Remain in the preparing_roam state.
|
|
|
|
*/
|
|
|
|
memcpy(device->preauth_bssid, bss->addr, ETH_ALEN);
|
2017-03-31 14:43:02 +02:00
|
|
|
|
2017-04-29 03:53:28 +02:00
|
|
|
if (netdev_preauthenticate(device->netdev, bss,
|
|
|
|
device_preauthenticate_cb,
|
|
|
|
device) >= 0)
|
|
|
|
return;
|
2017-03-31 14:43:02 +02:00
|
|
|
}
|
|
|
|
|
2018-09-01 00:44:10 +02:00
|
|
|
new_hs = station_handshake_setup(station, connected, bss);
|
2017-04-29 03:53:28 +02:00
|
|
|
if (!new_hs) {
|
|
|
|
l_error("device_handshake_setup failed in reassociation");
|
2018-09-04 20:48:18 +02:00
|
|
|
station_roam_failed(station);
|
2017-03-31 14:43:02 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-29 03:53:28 +02:00
|
|
|
device_transition_reassociate(device, bss, new_hs);
|
2017-01-23 12:38:38 +01:00
|
|
|
}
|
|
|
|
|
2018-01-18 22:36:38 +01:00
|
|
|
static void device_ap_roam_frame_event(struct netdev *netdev,
|
|
|
|
const struct mmpdu_header *hdr,
|
|
|
|
const void *body, size_t body_len,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
struct station *station = device->station;
|
2018-01-18 22:36:38 +01:00
|
|
|
|
2018-09-04 20:48:18 +02:00
|
|
|
station_ap_directed_roam(station, hdr, body, body_len);
|
2017-08-14 14:31:18 +02:00
|
|
|
}
|
|
|
|
|
2016-06-14 18:19:05 +02:00
|
|
|
static void device_connect_cb(struct netdev *netdev, enum netdev_result result,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 21:07:44 +02:00
|
|
|
struct station *station = device->station;
|
2016-06-14 18:19:05 +02:00
|
|
|
|
2016-08-04 17:39:41 +02:00
|
|
|
l_debug("%d, result: %d", device->index, result);
|
|
|
|
|
2016-08-02 23:58:57 +02:00
|
|
|
if (device->connect_pending) {
|
2016-07-26 14:42:21 +02:00
|
|
|
struct l_dbus_message *reply;
|
|
|
|
|
2016-08-02 23:58:57 +02:00
|
|
|
switch (result) {
|
|
|
|
case NETDEV_RESULT_ABORTED:
|
|
|
|
reply = dbus_error_aborted(device->connect_pending);
|
|
|
|
break;
|
|
|
|
case NETDEV_RESULT_OK:
|
|
|
|
reply = l_dbus_message_new_method_return(
|
|
|
|
device->connect_pending);
|
|
|
|
l_dbus_message_set_arguments(reply, "");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
reply = dbus_error_failed(device->connect_pending);
|
|
|
|
break;
|
2016-07-26 14:42:21 +02:00
|
|
|
}
|
2016-06-14 18:19:05 +02:00
|
|
|
|
2016-08-02 23:58:57 +02:00
|
|
|
dbus_pending_reply(&device->connect_pending, reply);
|
2016-06-14 18:19:05 +02:00
|
|
|
}
|
2016-06-16 17:53:26 +02:00
|
|
|
|
2016-08-02 23:58:57 +02:00
|
|
|
if (result != NETDEV_RESULT_OK) {
|
2016-10-10 21:53:01 +02:00
|
|
|
if (result != NETDEV_RESULT_ABORTED) {
|
2018-09-04 21:07:44 +02:00
|
|
|
network_connect_failed(station->connected_network);
|
2016-08-04 18:33:13 +02:00
|
|
|
device_disassociated(device);
|
2016-10-10 21:53:01 +02:00
|
|
|
}
|
2016-08-04 18:33:13 +02:00
|
|
|
|
2016-08-02 23:58:57 +02:00
|
|
|
return;
|
2016-06-16 17:53:26 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 21:07:44 +02:00
|
|
|
network_connected(station->connected_network);
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_CONNECTED);
|
2016-06-14 18:19:05 +02:00
|
|
|
}
|
|
|
|
|
2017-05-20 01:39:38 +02:00
|
|
|
static void device_signal_agent_notify(struct signal_agent *agent,
|
|
|
|
const char *device_path, int level)
|
|
|
|
{
|
|
|
|
struct l_dbus_message *msg;
|
|
|
|
uint8_t value = level;
|
|
|
|
|
|
|
|
msg = l_dbus_message_new_method_call(dbus_get_bus(),
|
|
|
|
agent->owner, agent->path,
|
|
|
|
IWD_SIGNAL_AGENT_INTERFACE,
|
2018-08-14 03:32:44 +02:00
|
|
|
"Changed");
|
2017-05-20 01:39:38 +02:00
|
|
|
l_dbus_message_set_arguments(msg, "oy", device_path, value);
|
|
|
|
l_dbus_message_set_no_reply(msg, true);
|
|
|
|
|
|
|
|
l_dbus_send(dbus_get_bus(), msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void device_signal_agent_release(struct signal_agent *agent,
|
|
|
|
const char *device_path)
|
|
|
|
{
|
|
|
|
struct l_dbus_message *msg;
|
|
|
|
|
|
|
|
msg = l_dbus_message_new_method_call(dbus_get_bus(),
|
|
|
|
agent->owner, agent->path,
|
|
|
|
IWD_SIGNAL_AGENT_INTERFACE,
|
|
|
|
"Release");
|
|
|
|
l_dbus_message_set_arguments(msg, "o", device_path);
|
|
|
|
l_dbus_message_set_no_reply(msg, true);
|
|
|
|
|
|
|
|
l_dbus_send(dbus_get_bus(), msg);
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:19:05 +02:00
|
|
|
static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
|
|
|
|
void *user_data)
|
|
|
|
{
|
2016-06-16 18:06:17 +02:00
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
struct station *station = device->station;
|
2016-06-16 18:06:17 +02:00
|
|
|
|
2016-06-14 18:19:05 +02:00
|
|
|
switch (event) {
|
|
|
|
case NETDEV_EVENT_AUTHENTICATING:
|
|
|
|
l_debug("Authenticating");
|
|
|
|
break;
|
|
|
|
case NETDEV_EVENT_ASSOCIATING:
|
|
|
|
l_debug("Associating");
|
|
|
|
break;
|
|
|
|
case NETDEV_EVENT_LOST_BEACON:
|
2018-09-04 20:48:18 +02:00
|
|
|
station_lost_beacon(station);
|
2016-06-14 18:19:05 +02:00
|
|
|
break;
|
2016-06-16 18:21:12 +02:00
|
|
|
case NETDEV_EVENT_DISCONNECT_BY_AP:
|
2016-12-12 18:34:28 +01:00
|
|
|
case NETDEV_EVENT_DISCONNECT_BY_SME:
|
2018-04-18 07:03:21 +02:00
|
|
|
device_disconnect_event(device);
|
2016-12-12 18:34:28 +01:00
|
|
|
break;
|
2016-12-23 11:38:03 +01:00
|
|
|
case NETDEV_EVENT_RSSI_THRESHOLD_LOW:
|
2018-09-04 20:48:18 +02:00
|
|
|
station_low_rssi(station);
|
2017-01-18 12:36:32 +01:00
|
|
|
break;
|
2016-12-23 11:38:03 +01:00
|
|
|
case NETDEV_EVENT_RSSI_THRESHOLD_HIGH:
|
2018-09-04 20:48:18 +02:00
|
|
|
station_ok_rssi(station);
|
2017-05-20 16:33:13 +02:00
|
|
|
break;
|
|
|
|
case NETDEV_EVENT_RSSI_LEVEL_NOTIFY:
|
2017-05-20 01:39:38 +02:00
|
|
|
if (device->signal_agent)
|
|
|
|
device_signal_agent_notify(device->signal_agent,
|
2018-09-04 22:51:44 +02:00
|
|
|
netdev_get_path(netdev),
|
|
|
|
netdev_get_rssi_level(netdev));
|
2017-05-20 01:39:38 +02:00
|
|
|
|
2016-12-23 11:38:03 +01:00
|
|
|
break;
|
2016-06-14 18:19:05 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-07-02 19:25:47 +02:00
|
|
|
int __device_connect_network(struct device *device, struct network *network,
|
|
|
|
struct scan_bss *bss)
|
2016-06-14 18:19:05 +02:00
|
|
|
{
|
|
|
|
struct l_dbus *dbus = dbus_get_bus();
|
2018-09-01 00:44:10 +02:00
|
|
|
struct station *station = device->station;
|
2018-09-04 22:51:44 +02:00
|
|
|
struct netdev *netdev = station->netdev;
|
2016-12-12 18:34:19 +01:00
|
|
|
struct handshake_state *hs;
|
2018-07-02 19:25:47 +02:00
|
|
|
int r;
|
2016-06-15 17:54:13 +02:00
|
|
|
|
2018-07-02 19:25:47 +02:00
|
|
|
if (device_is_busy(device))
|
|
|
|
return -EBUSY;
|
2016-11-02 23:46:17 +01:00
|
|
|
|
2018-09-01 00:44:10 +02:00
|
|
|
hs = station_handshake_setup(station, network, bss);
|
2018-07-02 19:25:47 +02:00
|
|
|
if (!hs)
|
|
|
|
return -ENOTSUP;
|
2016-11-02 23:46:17 +01:00
|
|
|
|
2018-07-02 19:25:47 +02:00
|
|
|
r = netdev_connect(device->netdev, bss, hs, device_netdev_event,
|
|
|
|
device_connect_cb, device);
|
|
|
|
if (r < 0) {
|
2016-12-12 18:34:19 +01:00
|
|
|
handshake_state_free(hs);
|
2018-07-02 19:25:47 +02:00
|
|
|
return r;
|
2016-06-14 18:19:05 +02:00
|
|
|
}
|
|
|
|
|
2018-09-01 23:21:28 +02:00
|
|
|
station->connected_bss = bss;
|
2018-09-01 00:44:10 +02:00
|
|
|
station->connected_network = network;
|
2016-06-14 18:19:05 +02:00
|
|
|
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_CONNECTING);
|
2016-06-14 18:19:05 +02:00
|
|
|
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(dbus, netdev_get_path(netdev),
|
2016-06-14 18:19:05 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "ConnectedNetwork");
|
|
|
|
l_dbus_property_changed(dbus, network_get_path(network),
|
|
|
|
IWD_NETWORK_INTERFACE, "Connected");
|
2018-07-02 19:25:47 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void device_connect_network(struct device *device, struct network *network,
|
|
|
|
struct scan_bss *bss,
|
|
|
|
struct l_dbus_message *message)
|
|
|
|
{
|
|
|
|
int err = __device_connect_network(device, network, bss);
|
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
struct l_dbus *dbus = dbus_get_bus();
|
|
|
|
|
|
|
|
l_dbus_send(dbus, dbus_error_from_errno(err, message));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
device->connect_pending = l_dbus_message_ref(message);
|
2018-09-05 01:00:48 +02:00
|
|
|
device->station->autoconnect = true;
|
2016-06-14 18:19:05 +02:00
|
|
|
}
|
|
|
|
|
2016-06-16 23:22:14 +02:00
|
|
|
static struct l_dbus_message *device_scan(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 21:09:22 +02:00
|
|
|
struct station *station = device->station;
|
2016-06-16 23:22:14 +02:00
|
|
|
|
2018-08-20 03:39:37 +02:00
|
|
|
/* TODO: Remove when Device/Station split is done */
|
|
|
|
if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION)
|
|
|
|
return dbus_error_not_available(message);
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (!device->powered)
|
2017-09-22 05:06:45 +02:00
|
|
|
return dbus_error_failed(message);
|
|
|
|
|
2018-09-05 00:32:18 +02:00
|
|
|
return station_dbus_scan(dbus, message, station);
|
2016-06-16 23:22:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void device_disconnect_cb(struct netdev *netdev, bool success,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-05 01:00:48 +02:00
|
|
|
struct station *station = device->station;
|
2016-06-16 23:22:14 +02:00
|
|
|
|
2016-08-04 17:39:41 +02:00
|
|
|
l_debug("%d, success: %d", device->index, success);
|
|
|
|
|
2016-08-04 18:37:23 +02:00
|
|
|
if (device->disconnect_pending) {
|
|
|
|
struct l_dbus_message *reply;
|
2016-07-02 16:42:32 +02:00
|
|
|
|
2016-08-04 18:37:23 +02:00
|
|
|
if (success) {
|
|
|
|
reply = l_dbus_message_new_method_return(
|
|
|
|
device->disconnect_pending);
|
|
|
|
l_dbus_message_set_arguments(reply, "");
|
|
|
|
} else
|
|
|
|
reply = dbus_error_failed(device->disconnect_pending);
|
2016-06-16 23:22:14 +02:00
|
|
|
|
|
|
|
|
2016-08-04 18:37:23 +02:00
|
|
|
dbus_pending_reply(&device->disconnect_pending, reply);
|
2016-08-04 18:44:24 +02:00
|
|
|
|
2016-08-04 18:37:23 +02:00
|
|
|
}
|
2016-07-02 16:42:32 +02:00
|
|
|
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_DISCONNECTED);
|
2016-08-04 18:44:24 +02:00
|
|
|
|
2018-09-05 01:00:48 +02:00
|
|
|
if (station->autoconnect)
|
|
|
|
station_enter_state(station, STATION_STATE_AUTOCONNECT);
|
2016-06-16 23:22:14 +02:00
|
|
|
}
|
|
|
|
|
2016-07-02 16:42:32 +02:00
|
|
|
int device_disconnect(struct device *device)
|
2016-06-16 23:22:14 +02:00
|
|
|
{
|
2018-09-04 17:40:45 +02:00
|
|
|
struct station *station = device->station;
|
|
|
|
|
|
|
|
if (station->state == STATION_STATE_DISCONNECTING)
|
2016-07-02 16:42:32 +02:00
|
|
|
return -EBUSY;
|
2016-06-16 23:22:14 +02:00
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (!station->connected_bss)
|
2016-07-02 16:42:32 +02:00
|
|
|
return -ENOTCONN;
|
2016-06-16 23:22:14 +02:00
|
|
|
|
|
|
|
if (netdev_disconnect(device->netdev, device_disconnect_cb, device) < 0)
|
2016-07-02 16:42:32 +02:00
|
|
|
return -EIO;
|
2016-06-16 23:22:14 +02:00
|
|
|
|
2016-06-24 05:09:04 +02:00
|
|
|
/*
|
|
|
|
* If the disconnect somehow fails we won't know if we're still
|
|
|
|
* connected so we may as well indicate now that we're no longer
|
|
|
|
* connected.
|
|
|
|
*/
|
2018-09-05 01:25:31 +02:00
|
|
|
station_reset_connection_state(station);
|
2016-06-24 05:09:04 +02:00
|
|
|
|
2018-09-05 01:00:48 +02:00
|
|
|
station_enter_state(station, STATION_STATE_DISCONNECTING);
|
2016-06-16 23:22:14 +02:00
|
|
|
|
2016-07-02 16:42:32 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_dbus_disconnect(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
struct station *station = device->station;
|
2016-07-02 16:42:32 +02:00
|
|
|
int result;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
2016-09-22 18:57:15 +02:00
|
|
|
/*
|
|
|
|
* Disconnect was triggered by the user, don't autoconnect. Wait for
|
|
|
|
* the user's explicit instructions to scan and connect to the network
|
|
|
|
*/
|
2018-09-05 01:00:48 +02:00
|
|
|
station_set_autoconnect(station, false);
|
2016-07-02 16:42:32 +02:00
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (station->state == STATION_STATE_AUTOCONNECT ||
|
|
|
|
station->state == STATION_STATE_DISCONNECTED)
|
2018-07-03 23:13:39 +02:00
|
|
|
return l_dbus_message_new_method_return(message);
|
|
|
|
|
2016-09-22 18:57:15 +02:00
|
|
|
result = device_disconnect(device);
|
2016-07-02 16:42:32 +02:00
|
|
|
if (result < 0)
|
2018-07-03 23:12:04 +02:00
|
|
|
return dbus_error_from_errno(result, message);
|
2016-07-02 16:42:32 +02:00
|
|
|
|
2016-06-16 23:22:14 +02:00
|
|
|
device->disconnect_pending = l_dbus_message_ref(message);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_get_networks(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
struct l_dbus_message *reply;
|
|
|
|
struct l_dbus_message_builder *builder;
|
2018-09-01 23:21:28 +02:00
|
|
|
struct l_queue *sorted = device->station->networks_sorted;
|
2016-06-16 23:22:14 +02:00
|
|
|
const struct l_queue_entry *entry;
|
|
|
|
|
|
|
|
reply = l_dbus_message_new_method_return(message);
|
|
|
|
builder = l_dbus_message_builder_new(reply);
|
|
|
|
|
|
|
|
l_dbus_message_builder_enter_array(builder, "(osns)");
|
|
|
|
|
2018-09-01 23:21:28 +02:00
|
|
|
for (entry = l_queue_get_entries(sorted); entry; entry = entry->next) {
|
2016-06-16 23:22:14 +02:00
|
|
|
const struct network *network = entry->data;
|
|
|
|
enum security security = network_get_security(network);
|
2017-02-15 02:28:06 +01:00
|
|
|
int16_t signal_strength = network_get_signal_strength(network);
|
2016-06-16 23:22:14 +02:00
|
|
|
|
|
|
|
l_dbus_message_builder_enter_struct(builder, "osns");
|
|
|
|
l_dbus_message_builder_append_basic(builder, 'o',
|
|
|
|
network_get_path(network));
|
|
|
|
l_dbus_message_builder_append_basic(builder, 's',
|
|
|
|
network_get_ssid(network));
|
|
|
|
l_dbus_message_builder_append_basic(builder, 'n',
|
|
|
|
&signal_strength);
|
|
|
|
l_dbus_message_builder_append_basic(builder, 's',
|
|
|
|
security_to_str(security));
|
|
|
|
l_dbus_message_builder_leave_struct(builder);
|
|
|
|
}
|
|
|
|
|
|
|
|
l_dbus_message_builder_leave_array(builder);
|
|
|
|
|
|
|
|
l_dbus_message_builder_finalize(builder);
|
|
|
|
l_dbus_message_builder_destroy(builder);
|
|
|
|
|
|
|
|
return reply;
|
|
|
|
}
|
|
|
|
|
2017-05-20 01:39:38 +02:00
|
|
|
static void signal_agent_free(void *data)
|
|
|
|
{
|
|
|
|
struct signal_agent *agent = data;
|
|
|
|
|
|
|
|
l_free(agent->owner);
|
|
|
|
l_free(agent->path);
|
|
|
|
l_dbus_remove_watch(dbus_get_bus(), agent->disconnect_watch);
|
|
|
|
l_free(agent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void signal_agent_disconnect(struct l_dbus *dbus, void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
|
|
|
|
l_debug("signal_agent %s disconnected", device->signal_agent->owner);
|
|
|
|
|
|
|
|
l_idle_oneshot(signal_agent_free, device->signal_agent, NULL);
|
|
|
|
device->signal_agent = NULL;
|
|
|
|
|
|
|
|
netdev_set_rssi_report_levels(device->netdev, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_signal_agent_register(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
const char *path, *sender;
|
|
|
|
struct l_dbus_message_iter level_iter;
|
|
|
|
int8_t levels[16];
|
|
|
|
int err;
|
|
|
|
int16_t val;
|
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
if (device->signal_agent)
|
|
|
|
return dbus_error_already_exists(message);
|
|
|
|
|
|
|
|
l_debug("signal agent register called");
|
|
|
|
|
|
|
|
if (!l_dbus_message_get_arguments(message, "oan", &path, &level_iter))
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
|
|
|
while (l_dbus_message_iter_next_entry(&level_iter, &val)) {
|
|
|
|
if (count >= L_ARRAY_SIZE(levels) || val > 127 || val < -127)
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
|
|
|
levels[count++] = val;
|
|
|
|
}
|
|
|
|
|
2017-05-30 18:39:26 +02:00
|
|
|
if (count < 1)
|
2017-05-20 01:39:38 +02:00
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
|
|
|
err = netdev_set_rssi_report_levels(device->netdev, levels, count);
|
|
|
|
if (err == -ENOTSUP)
|
|
|
|
return dbus_error_not_supported(message);
|
|
|
|
else if (err < 0)
|
|
|
|
return dbus_error_failed(message);
|
|
|
|
|
|
|
|
sender = l_dbus_message_get_sender(message);
|
|
|
|
|
|
|
|
device->signal_agent = l_new(struct signal_agent, 1);
|
|
|
|
device->signal_agent->owner = l_strdup(sender);
|
|
|
|
device->signal_agent->path = l_strdup(path);
|
|
|
|
device->signal_agent->disconnect_watch =
|
|
|
|
l_dbus_add_disconnect_watch(dbus, sender,
|
|
|
|
signal_agent_disconnect,
|
|
|
|
device, NULL);
|
|
|
|
|
|
|
|
l_debug("agent %s path %s", sender, path);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: send an initial notification in a oneshot idle callback,
|
|
|
|
* if state is connected.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return l_dbus_message_new_method_return(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_signal_agent_unregister(
|
|
|
|
struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
const char *path, *sender;
|
|
|
|
|
|
|
|
if (!device->signal_agent)
|
|
|
|
return dbus_error_failed(message);
|
|
|
|
|
|
|
|
l_debug("signal agent unregister");
|
|
|
|
|
|
|
|
if (!l_dbus_message_get_arguments(message, "o", &path))
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
2017-05-30 18:07:38 +02:00
|
|
|
if (strcmp(device->signal_agent->path, path))
|
|
|
|
return dbus_error_not_found(message);
|
|
|
|
|
2017-05-20 01:39:38 +02:00
|
|
|
sender = l_dbus_message_get_sender(message);
|
|
|
|
|
|
|
|
if (strcmp(device->signal_agent->owner, sender))
|
|
|
|
return dbus_error_not_found(message);
|
|
|
|
|
|
|
|
signal_agent_free(device->signal_agent);
|
|
|
|
device->signal_agent = NULL;
|
|
|
|
|
|
|
|
netdev_set_rssi_report_levels(device->netdev, NULL, 0);
|
|
|
|
|
|
|
|
return l_dbus_message_new_method_return(message);
|
|
|
|
}
|
|
|
|
|
2018-07-11 00:46:57 +02:00
|
|
|
static void device_hidden_network_scan_triggered(int err, void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
|
|
|
if (!err)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dbus_pending_reply(&device->connect_pending,
|
|
|
|
dbus_error_failed(device->connect_pending));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool device_hidden_network_scan_results(uint32_t wiphy_id,
|
|
|
|
uint32_t ifindex, int err,
|
|
|
|
struct l_queue *bss_list,
|
|
|
|
void *userdata)
|
|
|
|
{
|
|
|
|
struct device *device = userdata;
|
2018-09-04 23:09:08 +02:00
|
|
|
struct station *station = device->station;
|
2018-07-11 00:46:57 +02:00
|
|
|
struct network *network_psk;
|
|
|
|
struct network *network_open;
|
|
|
|
struct network *network;
|
|
|
|
const char *ssid;
|
|
|
|
uint8_t ssid_len;
|
2018-07-11 22:59:26 +02:00
|
|
|
struct l_dbus_message *msg;
|
2018-07-11 00:46:57 +02:00
|
|
|
struct scan_bss *bss;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
2018-07-11 22:59:26 +02:00
|
|
|
msg = device->connect_pending;
|
|
|
|
device->connect_pending = NULL;
|
|
|
|
|
2018-07-11 00:46:57 +02:00
|
|
|
if (err) {
|
2018-07-11 22:59:26 +02:00
|
|
|
dbus_pending_reply(&msg, dbus_error_failed(msg));
|
|
|
|
return false;
|
2018-07-11 00:46:57 +02:00
|
|
|
}
|
|
|
|
|
2018-07-13 18:35:41 +02:00
|
|
|
if (!l_dbus_message_get_arguments(msg, "s", &ssid)) {
|
2018-07-11 22:59:26 +02:00
|
|
|
dbus_pending_reply(&msg, dbus_error_invalid_args(msg));
|
|
|
|
return false;
|
2018-07-11 00:46:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ssid_len = strlen(ssid);
|
|
|
|
|
|
|
|
while ((bss = l_queue_pop_head(bss_list))) {
|
|
|
|
if (bss->ssid_len != ssid_len ||
|
|
|
|
memcmp(bss->ssid, ssid, ssid_len))
|
|
|
|
goto next;
|
|
|
|
|
2018-09-01 23:21:28 +02:00
|
|
|
if (station_add_seen_bss(device->station, bss)) {
|
|
|
|
l_queue_push_tail(device->station->bss_list, bss);
|
2018-07-11 00:46:57 +02:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
scan_bss_free(bss);
|
|
|
|
}
|
|
|
|
|
|
|
|
l_queue_destroy(bss_list, NULL);
|
|
|
|
|
2018-09-04 23:09:08 +02:00
|
|
|
network_psk = station_network_find(station, ssid, SECURITY_PSK);
|
|
|
|
network_open = station_network_find(station, ssid, SECURITY_NONE);
|
2018-07-11 00:46:57 +02:00
|
|
|
|
|
|
|
if (!network_psk && !network_open) {
|
2018-07-11 22:59:26 +02:00
|
|
|
dbus_pending_reply(&msg, dbus_error_not_found(msg));
|
|
|
|
return true;
|
2018-07-11 00:46:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (network_psk && network_open) {
|
2018-07-11 22:59:26 +02:00
|
|
|
dbus_pending_reply(&msg, dbus_error_service_set_overlap(msg));
|
|
|
|
return true;
|
2018-07-11 00:46:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
network = network_psk ? : network_open;
|
|
|
|
|
2018-07-13 18:35:41 +02:00
|
|
|
network_connect_new_hidden_network(network, msg);
|
2018-07-11 22:59:26 +02:00
|
|
|
l_dbus_message_unref(msg);
|
2018-07-11 00:46:57 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_connect_hidden_network(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 23:09:08 +02:00
|
|
|
struct station *station = device->station;
|
2018-07-11 00:46:57 +02:00
|
|
|
const char *ssid;
|
|
|
|
struct scan_parameters params = {
|
|
|
|
.flush = true,
|
|
|
|
.randomize_mac_addr_hint = true,
|
|
|
|
};
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (!device->powered)
|
2018-07-11 00:46:57 +02:00
|
|
|
return dbus_error_failed(message);
|
|
|
|
|
|
|
|
if (device->connect_pending || device_is_busy(device))
|
|
|
|
return dbus_error_busy(message);
|
|
|
|
|
|
|
|
if (!l_dbus_message_get_arguments(message, "s", &ssid))
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
|
|
|
if (strlen(ssid) > 32)
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
2018-07-22 14:15:18 +02:00
|
|
|
if (known_networks_find(ssid, SECURITY_PSK) ||
|
|
|
|
known_networks_find(ssid, SECURITY_NONE))
|
2018-07-11 00:46:57 +02:00
|
|
|
return dbus_error_already_provisioned(message);
|
|
|
|
|
2018-09-04 23:09:08 +02:00
|
|
|
if (station_network_find(station, ssid, SECURITY_PSK) ||
|
|
|
|
station_network_find(station, ssid, SECURITY_NONE))
|
2018-07-11 00:46:57 +02:00
|
|
|
return dbus_error_not_hidden(message);
|
|
|
|
|
|
|
|
params.ssid = ssid;
|
|
|
|
|
|
|
|
if (!scan_active_full(device->index, ¶ms,
|
|
|
|
device_hidden_network_scan_triggered,
|
|
|
|
device_hidden_network_scan_results,
|
|
|
|
device, NULL))
|
|
|
|
return dbus_error_failed(message);
|
|
|
|
|
|
|
|
device->connect_pending = l_dbus_message_ref(message);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-16 23:22:14 +02:00
|
|
|
static bool device_property_get_name(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 's',
|
|
|
|
netdev_get_name(device->netdev));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool device_property_get_address(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
str = util_address_to_string(netdev_get_address(device->netdev));
|
|
|
|
l_dbus_message_builder_append_basic(builder, 's', str);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool device_property_get_connected_network(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 21:07:44 +02:00
|
|
|
struct station *station = device->station;
|
|
|
|
|
|
|
|
if (!station->connected_network)
|
2016-06-16 23:22:14 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 'o',
|
2018-09-04 21:07:44 +02:00
|
|
|
network_get_path(station->connected_network));
|
2016-06-16 23:22:14 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-20 12:42:06 +02:00
|
|
|
static bool device_property_get_powered(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
bool powered = device->powered;
|
2016-06-20 12:42:06 +02:00
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 'b', &powered);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:57:37 +02:00
|
|
|
struct set_generic_cb_data {
|
2016-07-12 04:13:52 +02:00
|
|
|
struct device *device;
|
|
|
|
struct l_dbus *dbus;
|
|
|
|
struct l_dbus_message *message;
|
|
|
|
l_dbus_property_complete_cb_t complete;
|
|
|
|
};
|
|
|
|
|
2018-08-17 19:02:15 +02:00
|
|
|
static void set_generic_destroy(void *user_data)
|
|
|
|
{
|
|
|
|
struct set_generic_cb_data *cb_data = user_data;
|
|
|
|
|
|
|
|
/* Message hasn't been replied to, generate an Aborted error */
|
|
|
|
if (cb_data->message)
|
|
|
|
cb_data->complete(cb_data->dbus, cb_data->message,
|
|
|
|
dbus_error_aborted(cb_data->message));
|
|
|
|
|
|
|
|
l_free(cb_data);
|
|
|
|
}
|
|
|
|
|
2016-07-12 04:13:52 +02:00
|
|
|
static void set_powered_cb(struct netdev *netdev, int result, void *user_data)
|
|
|
|
{
|
2018-06-13 17:57:37 +02:00
|
|
|
struct set_generic_cb_data *cb_data = user_data;
|
2016-07-12 04:13:52 +02:00
|
|
|
struct l_dbus_message *reply = NULL;
|
|
|
|
|
|
|
|
if (result < 0)
|
|
|
|
reply = dbus_error_failed(cb_data->message);
|
|
|
|
|
|
|
|
cb_data->complete(cb_data->dbus, cb_data->message, reply);
|
2018-08-17 19:02:15 +02:00
|
|
|
cb_data->message = NULL;
|
2016-07-12 04:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_property_set_powered(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_iter *new_value,
|
|
|
|
l_dbus_property_complete_cb_t complete,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
bool powered;
|
2018-06-13 17:57:37 +02:00
|
|
|
struct set_generic_cb_data *cb_data;
|
2018-08-17 18:52:47 +02:00
|
|
|
int r;
|
2016-07-12 04:13:52 +02:00
|
|
|
|
|
|
|
if (!l_dbus_message_iter_get_variant(new_value, "b", &powered))
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (powered == device->powered) {
|
2016-07-12 04:13:52 +02:00
|
|
|
complete(dbus, message, NULL);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:57:37 +02:00
|
|
|
cb_data = l_new(struct set_generic_cb_data, 1);
|
2016-07-12 04:13:52 +02:00
|
|
|
cb_data->device = device;
|
|
|
|
cb_data->dbus = dbus;
|
|
|
|
cb_data->message = message;
|
|
|
|
cb_data->complete = complete;
|
|
|
|
|
2018-08-17 18:52:47 +02:00
|
|
|
r = netdev_set_powered(device->netdev, powered, set_powered_cb,
|
2018-08-17 19:02:15 +02:00
|
|
|
cb_data, set_generic_destroy);
|
2018-08-17 18:52:47 +02:00
|
|
|
if (r < 0) {
|
|
|
|
l_free(cb_data);
|
|
|
|
return dbus_error_from_errno(r, message);
|
|
|
|
}
|
2016-07-12 04:13:52 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:57:37 +02:00
|
|
|
static bool device_property_get_4addr(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
bool use_4addr = netdev_get_4addr(device->netdev);
|
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 'b', &use_4addr);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_4addr_cb(struct netdev *netdev, int result, void *user_data)
|
|
|
|
{
|
|
|
|
struct set_generic_cb_data *cb_data = user_data;
|
|
|
|
struct l_dbus_message *reply = NULL;
|
|
|
|
|
|
|
|
if (result < 0)
|
|
|
|
reply = dbus_error_failed(cb_data->message);
|
|
|
|
|
|
|
|
cb_data->complete(cb_data->dbus, cb_data->message, reply);
|
2018-08-17 19:02:15 +02:00
|
|
|
cb_data->message = NULL;
|
2018-06-13 17:57:37 +02:00
|
|
|
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(cb_data->dbus,
|
|
|
|
netdev_get_path(cb_data->device->netdev),
|
2018-06-13 17:57:37 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "WDS");
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct l_dbus_message *device_property_set_4addr(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_iter *new_value,
|
|
|
|
l_dbus_property_complete_cb_t complete,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct set_generic_cb_data *cb_data;
|
|
|
|
struct device *device = user_data;
|
|
|
|
bool use_4addr;
|
|
|
|
|
|
|
|
if (!l_dbus_message_iter_get_variant(new_value, "b", &use_4addr))
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
|
|
|
if (use_4addr == netdev_get_4addr(device->netdev)) {
|
|
|
|
complete(dbus, message, NULL);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cb_data = l_new(struct set_generic_cb_data, 1);
|
|
|
|
cb_data->device = device;
|
|
|
|
cb_data->dbus = dbus;
|
|
|
|
cb_data->message = message;
|
|
|
|
cb_data->complete = complete;
|
|
|
|
|
2018-08-17 19:02:15 +02:00
|
|
|
if (netdev_set_4addr(device->netdev, use_4addr, set_4addr_cb,
|
|
|
|
cb_data, set_generic_destroy) < 0)
|
2018-06-13 17:57:37 +02:00
|
|
|
return dbus_error_failed(message);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-12 04:13:53 +02:00
|
|
|
static bool device_property_get_scanning(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-05 00:32:18 +02:00
|
|
|
struct station *station = device->station;
|
|
|
|
bool scanning = station->scanning;
|
2016-07-12 04:13:53 +02:00
|
|
|
|
2016-09-22 19:57:10 +02:00
|
|
|
l_dbus_message_builder_append_basic(builder, 'b', &scanning);
|
2016-07-12 04:13:53 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-20 00:48:39 +02:00
|
|
|
static bool device_property_get_state(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-09-04 17:40:45 +02:00
|
|
|
const char *statestr;
|
2016-07-20 00:48:39 +02:00
|
|
|
|
2018-08-20 03:39:37 +02:00
|
|
|
/* TODO: Remove when Device/Station split is done */
|
|
|
|
if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION) {
|
|
|
|
uint32_t iftype = netdev_get_iftype(device->netdev);
|
2018-06-30 01:29:17 +02:00
|
|
|
l_dbus_message_builder_append_basic(builder, 's',
|
2018-08-20 03:39:37 +02:00
|
|
|
dbus_iftype_to_string(iftype));
|
2018-06-30 01:29:17 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
if (device->powered == false) {
|
|
|
|
l_dbus_message_builder_append_basic(builder,
|
|
|
|
's', "disconnected");
|
|
|
|
return true;
|
2016-07-20 00:48:39 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
statestr = station_state_to_string(device->station->state);
|
2016-07-20 00:48:39 +02:00
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
/* Special case. For now we treat AUTOCONNECT as disconnected */
|
|
|
|
if (device->station->state == STATION_STATE_AUTOCONNECT)
|
|
|
|
statestr = "disconnected";
|
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 's', statestr);
|
2016-07-20 00:48:39 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:24:31 +01:00
|
|
|
static bool device_property_get_adapter(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 'o',
|
|
|
|
wiphy_get_path(device->wiphy));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-30 01:29:17 +02:00
|
|
|
static bool device_property_get_mode(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_builder *builder,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-08-20 03:39:37 +02:00
|
|
|
uint32_t iftype = netdev_get_iftype(device->netdev);
|
|
|
|
const char *modestr = dbus_iftype_to_string(iftype);
|
2018-06-30 01:29:17 +02:00
|
|
|
|
2018-08-20 03:39:37 +02:00
|
|
|
if (modestr == NULL)
|
|
|
|
modestr = "unknown";
|
2018-06-30 01:29:17 +02:00
|
|
|
|
|
|
|
l_dbus_message_builder_append_basic(builder, 's', modestr);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-20 05:07:15 +02:00
|
|
|
static void set_mode_cb(struct netdev *netdev, int result, void *user_data)
|
2018-07-18 01:39:54 +02:00
|
|
|
{
|
2018-08-20 05:07:15 +02:00
|
|
|
struct set_generic_cb_data *cb_data = user_data;
|
|
|
|
struct l_dbus_message *reply = NULL;
|
2018-07-18 01:39:54 +02:00
|
|
|
|
2018-08-20 05:07:15 +02:00
|
|
|
if (result < 0)
|
|
|
|
reply = dbus_error_from_errno(result, cb_data->message);
|
2018-07-18 01:39:54 +02:00
|
|
|
|
2018-08-20 05:07:15 +02:00
|
|
|
cb_data->complete(cb_data->dbus, cb_data->message, reply);
|
|
|
|
cb_data->message = NULL;
|
2018-07-18 01:39:54 +02:00
|
|
|
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(cb_data->dbus,
|
|
|
|
netdev_get_path(cb_data->device->netdev),
|
2018-08-20 05:07:15 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "Mode");
|
2018-08-20 05:41:07 +02:00
|
|
|
|
|
|
|
/* TODO: Special case, remove when Device/Station split is made */
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(cb_data->dbus,
|
|
|
|
netdev_get_path(cb_data->device->netdev),
|
2018-08-20 05:41:07 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "State");
|
2018-07-18 01:39:54 +02:00
|
|
|
}
|
|
|
|
|
2018-06-30 01:29:17 +02:00
|
|
|
static struct l_dbus_message *device_property_set_mode(struct l_dbus *dbus,
|
|
|
|
struct l_dbus_message *message,
|
|
|
|
struct l_dbus_message_iter *new_value,
|
|
|
|
l_dbus_property_complete_cb_t complete,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct device *device = user_data;
|
2018-08-20 05:07:15 +02:00
|
|
|
struct netdev *netdev = device->netdev;
|
|
|
|
const char *mode;
|
|
|
|
enum netdev_iftype iftype;
|
|
|
|
int r;
|
|
|
|
struct set_generic_cb_data *cb_data;
|
2018-06-30 01:29:17 +02:00
|
|
|
|
|
|
|
if (!l_dbus_message_iter_get_variant(new_value, "s", &mode))
|
|
|
|
return dbus_error_invalid_args(message);
|
|
|
|
|
2018-07-18 01:39:54 +02:00
|
|
|
if (!strcmp(mode, "station"))
|
2018-08-20 05:07:15 +02:00
|
|
|
iftype = NETDEV_IFTYPE_STATION;
|
2018-07-18 01:39:54 +02:00
|
|
|
else if (!strcmp(mode, "ap"))
|
2018-08-20 05:07:15 +02:00
|
|
|
iftype = NETDEV_IFTYPE_AP;
|
2018-07-18 01:39:54 +02:00
|
|
|
else if (!strcmp(mode, "ad-hoc"))
|
2018-08-20 05:07:15 +02:00
|
|
|
iftype = NETDEV_IFTYPE_ADHOC;
|
2018-07-18 01:39:54 +02:00
|
|
|
else
|
2018-06-30 01:29:17 +02:00
|
|
|
return dbus_error_invalid_args(message);
|
2018-07-18 01:39:54 +02:00
|
|
|
|
2018-08-20 05:07:15 +02:00
|
|
|
if (iftype == netdev_get_iftype(netdev)) {
|
|
|
|
complete(dbus, message, NULL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Special case, remove when Device/Station split is made */
|
|
|
|
if (iftype != NETDEV_IFTYPE_STATION && device_is_busy(device))
|
|
|
|
return dbus_error_busy(message);
|
|
|
|
|
|
|
|
cb_data = l_new(struct set_generic_cb_data, 1);
|
|
|
|
cb_data->device = device;
|
|
|
|
cb_data->dbus = dbus;
|
|
|
|
cb_data->message = message;
|
|
|
|
cb_data->complete = complete;
|
2018-06-30 01:29:17 +02:00
|
|
|
|
2018-08-20 05:07:15 +02:00
|
|
|
r = netdev_set_iftype(device->netdev, iftype, set_mode_cb,
|
|
|
|
cb_data, set_generic_destroy);
|
|
|
|
if (r < 0) {
|
|
|
|
l_free(cb_data);
|
|
|
|
return dbus_error_from_errno(r, message);
|
|
|
|
}
|
2018-06-30 01:29:17 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-16 23:22:14 +02:00
|
|
|
static void setup_device_interface(struct l_dbus_interface *interface)
|
|
|
|
{
|
|
|
|
l_dbus_interface_method(interface, "Scan", 0,
|
|
|
|
device_scan, "", "");
|
|
|
|
l_dbus_interface_method(interface, "Disconnect", 0,
|
2016-07-02 16:42:32 +02:00
|
|
|
device_dbus_disconnect, "", "");
|
2016-06-16 23:22:14 +02:00
|
|
|
l_dbus_interface_method(interface, "GetOrderedNetworks", 0,
|
|
|
|
device_get_networks, "a(osns)", "",
|
|
|
|
"networks");
|
2017-05-20 01:39:38 +02:00
|
|
|
l_dbus_interface_method(interface, "RegisterSignalLevelAgent", 0,
|
|
|
|
device_signal_agent_register,
|
|
|
|
"", "oan", "path", "levels");
|
|
|
|
l_dbus_interface_method(interface, "UnregisterSignalLevelAgent", 0,
|
|
|
|
device_signal_agent_unregister,
|
|
|
|
"", "o", "path");
|
2018-07-11 00:46:57 +02:00
|
|
|
l_dbus_interface_method(interface, "ConnectHiddenNetwork", 0,
|
|
|
|
device_connect_hidden_network, "", "s", "name");
|
2016-06-16 23:22:14 +02:00
|
|
|
l_dbus_interface_property(interface, "Name", 0, "s",
|
|
|
|
device_property_get_name, NULL);
|
|
|
|
l_dbus_interface_property(interface, "Address", 0, "s",
|
|
|
|
device_property_get_address, NULL);
|
|
|
|
l_dbus_interface_property(interface, "ConnectedNetwork", 0, "o",
|
|
|
|
device_property_get_connected_network,
|
|
|
|
NULL);
|
2018-06-13 17:57:37 +02:00
|
|
|
l_dbus_interface_property(interface, "WDS", 0, "b",
|
|
|
|
device_property_get_4addr,
|
|
|
|
device_property_set_4addr);
|
2016-06-20 12:42:06 +02:00
|
|
|
l_dbus_interface_property(interface, "Powered", 0, "b",
|
2016-07-12 04:13:52 +02:00
|
|
|
device_property_get_powered,
|
|
|
|
device_property_set_powered);
|
2016-07-12 04:13:53 +02:00
|
|
|
l_dbus_interface_property(interface, "Scanning", 0, "b",
|
|
|
|
device_property_get_scanning, NULL);
|
2016-07-20 00:48:39 +02:00
|
|
|
l_dbus_interface_property(interface, "State", 0, "s",
|
|
|
|
device_property_get_state, NULL);
|
2016-11-02 15:24:31 +01:00
|
|
|
l_dbus_interface_property(interface, "Adapter", 0, "o",
|
|
|
|
device_property_get_adapter, NULL);
|
2018-06-30 01:29:17 +02:00
|
|
|
l_dbus_interface_property(interface, "Mode", 0, "s",
|
|
|
|
device_property_get_mode,
|
|
|
|
device_property_set_mode);
|
2016-06-16 23:22:14 +02:00
|
|
|
}
|
|
|
|
|
2016-07-14 02:38:05 +02:00
|
|
|
static void device_netdev_notify(struct netdev *netdev,
|
|
|
|
enum netdev_watch_event event,
|
2016-06-20 12:42:05 +02:00
|
|
|
void *user_data)
|
|
|
|
{
|
2018-08-18 06:40:49 +02:00
|
|
|
struct device *device = netdev_get_device(netdev);
|
2016-06-20 12:42:05 +02:00
|
|
|
struct l_dbus *dbus = dbus_get_bus();
|
|
|
|
|
2018-08-18 06:40:49 +02:00
|
|
|
if (!device)
|
|
|
|
return;
|
|
|
|
|
2016-07-20 01:03:21 +02:00
|
|
|
switch (event) {
|
|
|
|
case NETDEV_WATCH_EVENT_UP:
|
2018-09-04 17:40:45 +02:00
|
|
|
device->powered = true;
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(dbus, netdev_get_path(device->netdev),
|
2016-07-14 02:38:05 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "Powered");
|
2018-08-18 07:40:45 +02:00
|
|
|
|
2018-08-20 05:07:15 +02:00
|
|
|
/* TODO: Remove when Device/Station split is done */
|
|
|
|
if (netdev_get_iftype(device->netdev) != NETDEV_IFTYPE_STATION)
|
|
|
|
return;
|
|
|
|
|
2018-09-01 00:44:10 +02:00
|
|
|
device->station = station_create(device->wiphy, device->netdev);
|
2016-07-20 01:03:21 +02:00
|
|
|
break;
|
|
|
|
case NETDEV_WATCH_EVENT_DOWN:
|
2018-09-01 00:44:10 +02:00
|
|
|
if (device->station) {
|
|
|
|
station_free(device->station);
|
|
|
|
device->station = NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
device->powered = false;
|
2016-06-20 12:42:05 +02:00
|
|
|
|
|
|
|
if (device->connect_pending)
|
|
|
|
dbus_pending_reply(&device->connect_pending,
|
|
|
|
dbus_error_aborted(device->connect_pending));
|
|
|
|
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(dbus, netdev_get_path(device->netdev),
|
2016-07-14 02:38:05 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "Powered");
|
2016-07-20 01:03:21 +02:00
|
|
|
break;
|
|
|
|
case NETDEV_WATCH_EVENT_NAME_CHANGE:
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(dbus, netdev_get_path(device->netdev),
|
2016-07-14 02:38:06 +02:00
|
|
|
IWD_DEVICE_INTERFACE, "Name");
|
2016-07-20 01:03:21 +02:00
|
|
|
break;
|
2017-03-08 15:07:14 +01:00
|
|
|
case NETDEV_WATCH_EVENT_ADDRESS_CHANGE:
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_property_changed(dbus, netdev_get_path(device->netdev),
|
2017-03-08 15:07:14 +01:00
|
|
|
IWD_DEVICE_INTERFACE, "Address");
|
|
|
|
break;
|
2018-08-18 06:40:49 +02:00
|
|
|
default:
|
|
|
|
break;
|
2016-07-20 01:03:21 +02:00
|
|
|
}
|
2016-06-20 12:42:05 +02:00
|
|
|
}
|
|
|
|
|
2016-06-16 22:37:50 +02:00
|
|
|
struct device *device_create(struct wiphy *wiphy, struct netdev *netdev)
|
|
|
|
{
|
|
|
|
struct device *device;
|
|
|
|
struct l_dbus *dbus = dbus_get_bus();
|
|
|
|
uint32_t ifindex = netdev_get_ifindex(netdev);
|
2018-01-18 22:36:38 +01:00
|
|
|
const uint8_t action_ap_roam_prefix[2] = { 0x0a, 0x07 };
|
2016-06-16 22:37:50 +02:00
|
|
|
|
|
|
|
device = l_new(struct device, 1);
|
|
|
|
device->index = ifindex;
|
|
|
|
device->wiphy = wiphy;
|
|
|
|
device->netdev = netdev;
|
|
|
|
|
2018-09-04 22:51:44 +02:00
|
|
|
if (!l_dbus_object_add_interface(dbus, netdev_get_path(device->netdev),
|
2016-06-16 22:37:50 +02:00
|
|
|
IWD_DEVICE_INTERFACE, device))
|
|
|
|
l_info("Unable to register %s interface", IWD_DEVICE_INTERFACE);
|
|
|
|
|
2018-09-04 22:51:44 +02:00
|
|
|
if (!l_dbus_object_add_interface(dbus, netdev_get_path(device->netdev),
|
2016-09-21 18:51:55 +02:00
|
|
|
L_DBUS_INTERFACE_PROPERTIES, device))
|
|
|
|
l_info("Unable to register %s interface",
|
|
|
|
L_DBUS_INTERFACE_PROPERTIES);
|
|
|
|
|
2016-06-16 22:37:50 +02:00
|
|
|
scan_ifindex_add(device->index);
|
2016-06-20 12:42:05 +02:00
|
|
|
|
2018-01-18 22:36:38 +01:00
|
|
|
/*
|
|
|
|
* register for AP roam transition watch
|
|
|
|
*/
|
|
|
|
device->ap_roam_watch = netdev_frame_watch_add(netdev, 0x00d0,
|
|
|
|
action_ap_roam_prefix, sizeof(action_ap_roam_prefix),
|
|
|
|
device_ap_roam_frame_event, device);
|
|
|
|
|
2018-09-04 17:40:45 +02:00
|
|
|
device->powered = netdev_get_is_up(netdev);
|
|
|
|
|
|
|
|
if (device->powered &&
|
2018-09-05 01:00:48 +02:00
|
|
|
netdev_get_iftype(netdev) == NETDEV_IFTYPE_STATION)
|
2018-09-01 00:44:10 +02:00
|
|
|
device->station = station_create(device->wiphy, device->netdev);
|
2018-08-18 06:40:49 +02:00
|
|
|
|
2016-06-16 22:37:50 +02:00
|
|
|
return device;
|
|
|
|
}
|
|
|
|
|
2018-09-04 23:41:37 +02:00
|
|
|
void device_remove(struct device *device)
|
2016-06-16 22:37:50 +02:00
|
|
|
{
|
|
|
|
struct l_dbus *dbus;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
|
|
|
if (device->connect_pending)
|
|
|
|
dbus_pending_reply(&device->connect_pending,
|
|
|
|
dbus_error_aborted(device->connect_pending));
|
|
|
|
|
2017-05-20 01:39:38 +02:00
|
|
|
if (device->signal_agent) {
|
|
|
|
device_signal_agent_release(device->signal_agent,
|
2018-09-04 22:51:44 +02:00
|
|
|
netdev_get_path(device->netdev));
|
2017-05-20 01:39:38 +02:00
|
|
|
signal_agent_free(device->signal_agent);
|
|
|
|
}
|
|
|
|
|
2016-06-16 22:37:50 +02:00
|
|
|
|
|
|
|
dbus = dbus_get_bus();
|
2018-09-04 22:51:44 +02:00
|
|
|
l_dbus_unregister_object(dbus, netdev_get_path(device->netdev));
|
2016-06-16 22:37:50 +02:00
|
|
|
|
|
|
|
scan_ifindex_remove(device->index);
|
2018-01-18 22:36:38 +01:00
|
|
|
|
|
|
|
netdev_frame_watch_remove(device->netdev, device->ap_roam_watch);
|
|
|
|
|
2016-06-16 22:37:50 +02:00
|
|
|
l_free(device);
|
|
|
|
}
|
|
|
|
|
2016-05-05 19:13:45 +02:00
|
|
|
bool device_init(void)
|
|
|
|
{
|
2016-06-16 23:22:14 +02:00
|
|
|
if (!l_dbus_register_interface(dbus_get_bus(),
|
|
|
|
IWD_DEVICE_INTERFACE,
|
|
|
|
setup_device_interface,
|
2016-09-21 18:51:55 +02:00
|
|
|
NULL, false))
|
2016-06-16 23:22:14 +02:00
|
|
|
return false;
|
|
|
|
|
2018-08-18 06:40:49 +02:00
|
|
|
netdev_watch = netdev_watch_add(device_netdev_notify, NULL, NULL);
|
2016-05-05 19:13:45 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-14 21:11:52 +02:00
|
|
|
void device_exit(void)
|
2016-05-05 19:13:45 +02:00
|
|
|
{
|
2018-08-18 06:40:49 +02:00
|
|
|
netdev_watch_remove(netdev_watch);
|
2016-05-05 19:13:45 +02:00
|
|
|
|
2016-06-16 23:22:14 +02:00
|
|
|
l_dbus_unregister_interface(dbus_get_bus(), IWD_DEVICE_INTERFACE);
|
2016-05-05 19:13:45 +02:00
|
|
|
}
|