station: move signal level agent logic from device

This commit is contained in:
Denis Kenzior 2018-09-04 22:46:12 -05:00
parent ac83a35b97
commit cdfcb902e4
3 changed files with 177 additions and 168 deletions

View File

@ -50,7 +50,6 @@
struct device {
uint32_t index;
uint8_t preauth_bssid[ETH_ALEN];
struct signal_agent *signal_agent;
struct wiphy *wiphy;
struct netdev *netdev;
@ -61,12 +60,6 @@ struct device {
uint32_t ap_roam_watch;
};
struct signal_agent {
char *owner;
char *path;
unsigned int disconnect_watch;
};
static uint32_t netdev_watch;
static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
@ -350,37 +343,6 @@ static void device_connect_cb(struct netdev *netdev, enum netdev_result result,
station_enter_state(station, STATION_STATE_CONNECTED);
}
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,
"Changed");
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);
}
static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
void *user_data)
{
@ -408,11 +370,7 @@ static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
station_ok_rssi(station);
break;
case NETDEV_EVENT_RSSI_LEVEL_NOTIFY:
if (device->signal_agent)
device_signal_agent_notify(device->signal_agent,
netdev_get_path(netdev),
netdev_get_rssi_level(netdev));
station_rssi_level_changed(station);
break;
};
}
@ -514,116 +472,6 @@ static struct l_dbus_message *device_get_networks(struct l_dbus *dbus,
return station_dbus_get_networks(dbus, message, station);
}
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;
}
if (count < 1)
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);
if (strcmp(device->signal_agent->path, path))
return dbus_error_not_found(message);
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);
}
static struct l_dbus_message *device_connect_hidden_network(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
@ -977,12 +825,6 @@ static void setup_device_interface(struct l_dbus_interface *interface)
l_dbus_interface_method(interface, "GetOrderedNetworks", 0,
device_get_networks, "a(osns)", "",
"networks");
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");
l_dbus_interface_method(interface, "ConnectHiddenNetwork", 0,
device_connect_hidden_network, "", "s", "name");
l_dbus_interface_property(interface, "Name", 0, "s",
@ -1096,18 +938,10 @@ struct device *device_create(struct wiphy *wiphy, struct netdev *netdev)
void device_remove(struct device *device)
{
struct l_dbus *dbus;
struct l_dbus *dbus = dbus_get_bus();
l_debug("");
if (device->signal_agent) {
device_signal_agent_release(device->signal_agent,
netdev_get_path(device->netdev));
signal_agent_free(device->signal_agent);
}
dbus = dbus_get_bus();
l_dbus_unregister_object(dbus, netdev_get_path(device->netdev));
scan_ifindex_remove(device->index);

View File

@ -1599,6 +1599,166 @@ struct l_dbus_message *station_dbus_scan(struct l_dbus *dbus,
return NULL;
}
struct signal_agent {
char *owner;
char *path;
unsigned int disconnect_watch;
};
static void station_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,
"Changed");
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);
}
void station_rssi_level_changed(struct station *station)
{
struct netdev *netdev = station->netdev;
if (!station->signal_agent)
return;
station_signal_agent_notify(station->signal_agent,
netdev_get_path(netdev),
netdev_get_rssi_level(netdev));
}
static void station_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);
}
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 station *station = user_data;
l_debug("signal_agent %s disconnected", station->signal_agent->owner);
l_idle_oneshot(signal_agent_free, station->signal_agent, NULL);
station->signal_agent = NULL;
netdev_set_rssi_report_levels(station->netdev, NULL, 0);
}
static struct l_dbus_message *station_dbus_signal_agent_register(
struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
struct station *station = 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 (station->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;
}
if (count < 1)
return dbus_error_invalid_args(message);
err = netdev_set_rssi_report_levels(station->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);
station->signal_agent = l_new(struct signal_agent, 1);
station->signal_agent->owner = l_strdup(sender);
station->signal_agent->path = l_strdup(path);
station->signal_agent->disconnect_watch =
l_dbus_add_disconnect_watch(dbus, sender,
signal_agent_disconnect,
station, 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 *station_dbus_signal_agent_unregister(
struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
struct station *station = user_data;
const char *path, *sender;
if (!station->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);
if (strcmp(station->signal_agent->path, path))
return dbus_error_not_found(message);
sender = l_dbus_message_get_sender(message);
if (strcmp(station->signal_agent->owner, sender))
return dbus_error_not_found(message);
signal_agent_free(station->signal_agent);
station->signal_agent = NULL;
netdev_set_rssi_report_levels(station->netdev, NULL, 0);
return l_dbus_message_new_method_return(message);
}
void station_foreach(station_foreach_func_t func, void *user_data)
{
const struct l_queue_entry *entry;
@ -1663,6 +1823,12 @@ void station_free(struct station *station)
periodic_scan_stop(station);
if (station->signal_agent) {
station_signal_agent_release(station->signal_agent,
netdev_get_path(station->netdev));
signal_agent_free(station->signal_agent);
}
if (station->connect_pending)
dbus_pending_reply(&station->connect_pending,
dbus_error_aborted(station->connect_pending));
@ -1689,6 +1855,12 @@ void station_free(struct station *station)
static void station_setup_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_method(interface, "RegisterSignalLevelAgent", 0,
station_dbus_signal_agent_register,
"", "oan", "path", "levels");
l_dbus_interface_method(interface, "UnregisterSignalLevelAgent", 0,
station_dbus_signal_agent_unregister,
"", "o", "path");
}
static void station_destroy_interface(void *user_data)

View File

@ -54,6 +54,7 @@ struct station {
struct l_dbus_message *connect_pending;
struct l_dbus_message *disconnect_pending;
struct l_dbus_message *scan_pending;
struct signal_agent *signal_agent;
/* Roaming related members */
struct timespec roam_min_time;
@ -127,6 +128,8 @@ struct l_dbus_message *station_dbus_scan(struct l_dbus *dbus,
int station_disconnect(struct station *station);
void station_rssi_level_changed(struct station *station);
struct station *station_find(uint32_t ifindex);
void station_foreach(station_foreach_func_t func, void *user_data);
struct station *station_create(struct wiphy *wiphy, struct netdev *netdev);