mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-20 19:12:33 +01:00
ap: Put a public api between AP logic and DBus code
Separate AP logic from DBus code, add a public API to make the AP logic reusable from other files.
This commit is contained in:
parent
1d852e10ad
commit
30933423fd
@ -207,7 +207,7 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
|
|||||||
src/knownnetworks.c \
|
src/knownnetworks.c \
|
||||||
src/rfkill.h src/rfkill.c \
|
src/rfkill.h src/rfkill.c \
|
||||||
src/ft.h src/ft.c \
|
src/ft.h src/ft.c \
|
||||||
src/ap.c src/adhoc.c \
|
src/ap.h src/ap.c src/adhoc.c \
|
||||||
src/sae.h src/sae.c \
|
src/sae.h src/sae.c \
|
||||||
src/nl80211util.h src/nl80211util.c \
|
src/nl80211util.h src/nl80211util.c \
|
||||||
src/nl80211cmd.h src/nl80211cmd.c \
|
src/nl80211cmd.h src/nl80211cmd.c \
|
||||||
|
383
src/ap.c
383
src/ap.c
@ -45,12 +45,17 @@
|
|||||||
#include "src/dbus.h"
|
#include "src/dbus.h"
|
||||||
#include "src/nl80211util.h"
|
#include "src/nl80211util.h"
|
||||||
#include "src/frame-xchg.h"
|
#include "src/frame-xchg.h"
|
||||||
|
#include "src/ap.h"
|
||||||
|
|
||||||
struct ap_state {
|
struct ap_state {
|
||||||
struct netdev *netdev;
|
struct netdev *netdev;
|
||||||
struct l_genl_family *nl80211;
|
struct l_genl_family *nl80211;
|
||||||
|
ap_event_func_t event_func;
|
||||||
|
ap_stopped_func_t stopped_func;
|
||||||
|
void *user_data;
|
||||||
char *ssid;
|
char *ssid;
|
||||||
uint8_t channel;
|
uint8_t channel;
|
||||||
|
|
||||||
unsigned int ciphers;
|
unsigned int ciphers;
|
||||||
enum ie_rsn_cipher_suite group_cipher;
|
enum ie_rsn_cipher_suite group_cipher;
|
||||||
uint32_t beacon_interval;
|
uint32_t beacon_interval;
|
||||||
@ -64,7 +69,6 @@ struct ap_state {
|
|||||||
uint16_t last_aid;
|
uint16_t last_aid;
|
||||||
struct l_queue *sta_states;
|
struct l_queue *sta_states;
|
||||||
|
|
||||||
struct l_dbus_message *pending;
|
|
||||||
bool started : 1;
|
bool started : 1;
|
||||||
bool gtk_set : 1;
|
bool gtk_set : 1;
|
||||||
};
|
};
|
||||||
@ -114,16 +118,12 @@ static void ap_reset(struct ap_state *ap)
|
|||||||
{
|
{
|
||||||
struct netdev *netdev = ap->netdev;
|
struct netdev *netdev = ap->netdev;
|
||||||
|
|
||||||
if (!ap->started)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ap->pending)
|
|
||||||
dbus_pending_reply(&ap->pending,
|
|
||||||
dbus_error_aborted(ap->pending));
|
|
||||||
|
|
||||||
l_free(ap->ssid);
|
l_free(ap->ssid);
|
||||||
|
|
||||||
memset(ap->pmk, 0, sizeof(ap->pmk));
|
explicit_bzero(ap->pmk, sizeof(ap->pmk));
|
||||||
|
|
||||||
|
if (ap->mlme_watch)
|
||||||
|
l_genl_family_unregister(ap->nl80211, ap->mlme_watch);
|
||||||
|
|
||||||
frame_watch_wdev_remove(netdev_get_wdev_id(netdev));
|
frame_watch_wdev_remove(netdev_get_wdev_id(netdev));
|
||||||
|
|
||||||
@ -136,28 +136,28 @@ static void ap_reset(struct ap_state *ap)
|
|||||||
l_uintset_free(ap->rates);
|
l_uintset_free(ap->rates);
|
||||||
|
|
||||||
ap->started = false;
|
ap->started = false;
|
||||||
|
|
||||||
l_dbus_property_changed(dbus_get_bus(), netdev_get_path(ap->netdev),
|
|
||||||
IWD_AP_INTERFACE, "Started");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ap_free(void *data)
|
|
||||||
{
|
|
||||||
struct ap_state *ap = data;
|
|
||||||
|
|
||||||
ap_reset(ap);
|
|
||||||
l_genl_family_free(ap->nl80211);
|
|
||||||
l_free(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_del_station(struct sta_state *sta, uint16_t reason,
|
static void ap_del_station(struct sta_state *sta, uint16_t reason,
|
||||||
bool disassociate)
|
bool disassociate)
|
||||||
{
|
{
|
||||||
struct ap_state *ap = sta->ap;
|
struct ap_state *ap = sta->ap;
|
||||||
|
struct ap_event_station_removed_data event_data;
|
||||||
|
bool send_event = false;
|
||||||
|
|
||||||
netdev_del_station(ap->netdev, sta->addr, reason, disassociate);
|
netdev_del_station(ap->netdev, sta->addr, reason, disassociate);
|
||||||
sta->associated = false;
|
sta->associated = false;
|
||||||
sta->rsna = false;
|
|
||||||
|
if (sta->rsna) {
|
||||||
|
if (ap->event_func) {
|
||||||
|
memset(&event_data, 0, sizeof(event_data));
|
||||||
|
event_data.mac = sta->addr;
|
||||||
|
event_data.reason = reason;
|
||||||
|
send_event = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta->rsna = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sta->gtk_query_cmd_id) {
|
if (sta->gtk_query_cmd_id) {
|
||||||
l_genl_family_cancel(ap->nl80211, sta->gtk_query_cmd_id);
|
l_genl_family_cancel(ap->nl80211, sta->gtk_query_cmd_id);
|
||||||
@ -172,6 +172,10 @@ static void ap_del_station(struct sta_state *sta, uint16_t reason,
|
|||||||
|
|
||||||
sta->hs = NULL;
|
sta->hs = NULL;
|
||||||
sta->sm = NULL;
|
sta->sm = NULL;
|
||||||
|
|
||||||
|
if (send_event)
|
||||||
|
ap->event_func(AP_EVENT_STATION_REMOVED, &event_data,
|
||||||
|
ap->user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ap_sta_match_addr(const void *a, const void *b)
|
static bool ap_sta_match_addr(const void *a, const void *b)
|
||||||
@ -205,13 +209,19 @@ static void ap_del_key_cb(struct l_genl_msg *msg, void *user_data)
|
|||||||
|
|
||||||
static void ap_new_rsna(struct sta_state *sta)
|
static void ap_new_rsna(struct sta_state *sta)
|
||||||
{
|
{
|
||||||
|
struct ap_state *ap = sta->ap;
|
||||||
|
|
||||||
l_debug("STA "MAC" authenticated", MAC_STR(sta->addr));
|
l_debug("STA "MAC" authenticated", MAC_STR(sta->addr));
|
||||||
|
|
||||||
sta->rsna = true;
|
sta->rsna = true;
|
||||||
/*
|
|
||||||
* TODO: Once new AP interface is implemented this is where a
|
if (ap->event_func) {
|
||||||
* new "ConnectedPeer" property will be added.
|
struct ap_event_station_added_data event_data = {};
|
||||||
*/
|
event_data.mac = sta->addr;
|
||||||
|
event_data.rsn_ie = sta->assoc_rsne;
|
||||||
|
ap->event_func(AP_EVENT_STATION_ADDED, &event_data,
|
||||||
|
ap->user_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_drop_rsna(struct sta_state *sta)
|
static void ap_drop_rsna(struct sta_state *sta)
|
||||||
@ -250,6 +260,13 @@ static void ap_drop_rsna(struct sta_state *sta)
|
|||||||
|
|
||||||
sta->hs = NULL;
|
sta->hs = NULL;
|
||||||
sta->sm = NULL;
|
sta->sm = NULL;
|
||||||
|
|
||||||
|
if (ap->event_func) {
|
||||||
|
struct ap_event_station_removed_data event_data = {};
|
||||||
|
event_data.mac = sta->addr;
|
||||||
|
ap->event_func(AP_EVENT_STATION_REMOVED, &event_data,
|
||||||
|
ap->user_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
|
static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
|
||||||
@ -1305,26 +1322,18 @@ static void ap_start_cb(struct l_genl_msg *msg, void *user_data)
|
|||||||
|
|
||||||
ap->start_stop_cmd_id = 0;
|
ap->start_stop_cmd_id = 0;
|
||||||
|
|
||||||
if (!ap->pending)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (l_genl_msg_get_error(msg) < 0) {
|
if (l_genl_msg_get_error(msg) < 0) {
|
||||||
l_error("START_AP failed: %i", l_genl_msg_get_error(msg));
|
l_error("START_AP failed: %i", l_genl_msg_get_error(msg));
|
||||||
|
|
||||||
dbus_pending_reply(&ap->pending,
|
ap->event_func(AP_EVENT_START_FAILED, NULL, ap->user_data);
|
||||||
dbus_error_invalid_args(ap->pending));
|
|
||||||
ap_reset(ap);
|
ap_reset(ap);
|
||||||
|
l_genl_family_free(ap->nl80211);
|
||||||
|
l_free(ap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbus_pending_reply(&ap->pending,
|
|
||||||
l_dbus_message_new_method_return(ap->pending));
|
|
||||||
|
|
||||||
ap->started = true;
|
ap->started = true;
|
||||||
|
ap->event_func(AP_EVENT_STARTED, NULL, ap->user_data);
|
||||||
l_dbus_property_changed(dbus_get_bus(), netdev_get_path(ap->netdev),
|
|
||||||
IWD_AP_INTERFACE, "Started");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
|
static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
|
||||||
@ -1406,25 +1415,55 @@ static void ap_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
|||||||
|
|
||||||
switch (l_genl_msg_get_command(msg)) {
|
switch (l_genl_msg_get_command(msg)) {
|
||||||
case NL80211_CMD_STOP_AP:
|
case NL80211_CMD_STOP_AP:
|
||||||
if (ap->start_stop_cmd_id)
|
if (ap->start_stop_cmd_id) {
|
||||||
break;
|
l_genl_family_cancel(ap->nl80211,
|
||||||
|
ap->start_stop_cmd_id);
|
||||||
|
ap->start_stop_cmd_id = 0;
|
||||||
|
ap->event_func(AP_EVENT_START_FAILED, NULL,
|
||||||
|
ap->user_data);
|
||||||
|
} else if (ap->started) {
|
||||||
|
ap->started = false;
|
||||||
|
ap->event_func(AP_EVENT_STOPPING, NULL, ap->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
ap_reset(ap);
|
ap_reset(ap);
|
||||||
|
l_genl_family_free(ap->nl80211);
|
||||||
|
l_free(ap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ap_start(struct ap_state *ap, const char *ssid, const char *psk,
|
/*
|
||||||
struct l_dbus_message *message)
|
* Start a simple independent WPA2 AP on given netdev.
|
||||||
|
*
|
||||||
|
* @event_func is required and must react to AP_EVENT_START_FAILED
|
||||||
|
* and AP_EVENT_STOPPING by forgetting the ap_state struct, which
|
||||||
|
* is going to be freed automatically.
|
||||||
|
* @channel is optional.
|
||||||
|
*/
|
||||||
|
struct ap_state *ap_start(struct netdev *netdev, const char *ssid,
|
||||||
|
const char *psk, int channel,
|
||||||
|
ap_event_func_t event_func, void *user_data)
|
||||||
{
|
{
|
||||||
struct netdev *netdev = ap->netdev;
|
struct ap_state *ap;
|
||||||
struct wiphy *wiphy = netdev_get_wiphy(netdev);
|
struct wiphy *wiphy = netdev_get_wiphy(netdev);
|
||||||
struct l_genl_msg *cmd;
|
struct l_genl_msg *cmd;
|
||||||
uint64_t wdev_id = netdev_get_wdev_id(netdev);
|
uint64_t wdev_id = netdev_get_wdev_id(netdev);
|
||||||
|
|
||||||
|
ap = l_new(struct ap_state, 1);
|
||||||
|
ap->nl80211 = l_genl_family_new(iwd_get_genl(), NL80211_GENL_NAME);
|
||||||
ap->ssid = l_strdup(ssid);
|
ap->ssid = l_strdup(ssid);
|
||||||
/* TODO: Start a Get Survey to decide the channel */
|
ap->netdev = netdev;
|
||||||
ap->channel = 6;
|
ap->event_func = event_func;
|
||||||
|
ap->user_data = user_data;
|
||||||
|
|
||||||
|
if (channel)
|
||||||
|
ap->channel = channel;
|
||||||
|
else {
|
||||||
|
/* TODO: Start a Get Survey to decide the channel */
|
||||||
|
ap->channel = 6;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Add all ciphers supported by wiphy */
|
/* TODO: Add all ciphers supported by wiphy */
|
||||||
ap->ciphers = wiphy_select_cipher(wiphy, 0xffff);
|
ap->ciphers = wiphy_select_cipher(wiphy, 0xffff);
|
||||||
ap->group_cipher = wiphy_select_cipher(wiphy, 0xffff);
|
ap->group_cipher = wiphy_select_cipher(wiphy, 0xffff);
|
||||||
@ -1485,37 +1524,30 @@ static int ap_start(struct ap_state *ap, const char *ssid, const char *psk,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap->pending = l_dbus_message_ref(message);
|
return ap;
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
ap_reset(ap);
|
ap_reset(ap);
|
||||||
|
l_genl_family_free(ap->nl80211);
|
||||||
return -EIO;
|
l_free(ap);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_stop_cb(struct l_genl_msg *msg, void *user_data)
|
static void ap_stop_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
{
|
{
|
||||||
struct ap_state *ap = user_data;
|
struct ap_state *ap = user_data;
|
||||||
|
int error = l_genl_msg_get_error(msg);
|
||||||
|
|
||||||
ap->start_stop_cmd_id = 0;
|
ap->start_stop_cmd_id = 0;
|
||||||
|
|
||||||
if (!ap->pending)
|
if (error < 0)
|
||||||
goto end;
|
l_error("STOP_AP failed: %s (%i)", strerror(error), error);
|
||||||
|
|
||||||
if (l_genl_msg_get_error(msg) < 0) {
|
if (ap->stopped_func)
|
||||||
l_error("STOP_AP failed: %i", l_genl_msg_get_error(msg));
|
ap->stopped_func(ap->user_data);
|
||||||
dbus_pending_reply(&ap->pending,
|
|
||||||
dbus_error_failed(ap->pending));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbus_pending_reply(&ap->pending,
|
l_genl_family_free(ap->nl80211);
|
||||||
l_dbus_message_new_method_return(ap->pending));
|
l_free(ap);
|
||||||
|
|
||||||
end:
|
|
||||||
ap_reset(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct l_genl_msg *ap_build_cmd_stop_ap(struct ap_state *ap)
|
static struct l_genl_msg *ap_build_cmd_stop_ap(struct ap_state *ap)
|
||||||
@ -1529,81 +1561,207 @@ static struct l_genl_msg *ap_build_cmd_stop_ap(struct ap_state *ap)
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ap_stop(struct ap_state *ap, struct l_dbus_message *message)
|
/*
|
||||||
|
* Schedule the running @ap to be stopped and freed. The original
|
||||||
|
* event_func and user_data are forgotten and a new callback can be
|
||||||
|
* provided if the caller needs to know when the interface becomes
|
||||||
|
* free, for example for a new ap_start call.
|
||||||
|
*
|
||||||
|
* The user must forget @ap when @stopped_func is called. If the
|
||||||
|
* @user_data ends up being destroyed before that, ap_free(ap) should
|
||||||
|
* be used to prevent @stopped_func from being called.
|
||||||
|
* If @stopped_func is not provided, the caller must forget @ap
|
||||||
|
* immediately.
|
||||||
|
*/
|
||||||
|
void ap_shutdown(struct ap_state *ap, ap_stopped_func_t stopped_func,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct l_genl_msg *cmd;
|
struct l_genl_msg *cmd;
|
||||||
|
|
||||||
|
if (ap->started) {
|
||||||
|
ap->started = false;
|
||||||
|
ap->event_func(AP_EVENT_STOPPING, NULL, ap->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ap_reset(ap);
|
||||||
|
|
||||||
|
if (ap->gtk_set) {
|
||||||
|
ap->gtk_set = false;
|
||||||
|
|
||||||
|
cmd = ap_build_cmd_del_key(ap);
|
||||||
|
if (!cmd) {
|
||||||
|
l_error("ap_build_cmd_del_key failed");
|
||||||
|
goto free_ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!l_genl_family_send(ap->nl80211, cmd, ap_gtk_op_cb, NULL,
|
||||||
|
NULL)) {
|
||||||
|
l_genl_msg_unref(cmd);
|
||||||
|
l_error("Issuing DEL_KEY failed");
|
||||||
|
goto free_ap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd = ap_build_cmd_stop_ap(ap);
|
cmd = ap_build_cmd_stop_ap(ap);
|
||||||
if (!cmd)
|
if (!cmd) {
|
||||||
return -ENOMEM;
|
l_error("ap_build_cmd_stop_ap failed");
|
||||||
|
goto free_ap;
|
||||||
if (ap->start_stop_cmd_id)
|
}
|
||||||
l_genl_family_cancel(ap->nl80211, ap->start_stop_cmd_id);
|
|
||||||
|
|
||||||
if (ap->mlme_watch)
|
|
||||||
l_genl_family_unregister(ap->nl80211, ap->mlme_watch);
|
|
||||||
|
|
||||||
ap->start_stop_cmd_id = l_genl_family_send(ap->nl80211, cmd, ap_stop_cb,
|
ap->start_stop_cmd_id = l_genl_family_send(ap->nl80211, cmd, ap_stop_cb,
|
||||||
ap, NULL);
|
ap, NULL);
|
||||||
if (!ap->start_stop_cmd_id) {
|
if (!ap->start_stop_cmd_id) {
|
||||||
l_genl_msg_unref(cmd);
|
l_genl_msg_unref(cmd);
|
||||||
return -EIO;
|
l_error("Sending STOP_AP failed");
|
||||||
|
goto free_ap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ap->gtk_set) {
|
ap->stopped_func = stopped_func;
|
||||||
struct l_genl_msg *msg;
|
ap->user_data = user_data;
|
||||||
|
return;
|
||||||
|
|
||||||
ap->gtk_set = false;
|
free_ap:
|
||||||
|
if (stopped_func)
|
||||||
|
stopped_func(user_data);
|
||||||
|
|
||||||
msg = ap_build_cmd_del_key(ap);
|
l_genl_family_free(ap->nl80211);
|
||||||
if (!l_genl_family_send(ap->nl80211, msg, ap_gtk_op_cb, NULL,
|
l_free(ap);
|
||||||
NULL)) {
|
}
|
||||||
l_genl_msg_unref(msg);
|
|
||||||
l_error("Issuing DEL_KEY failed");
|
/* Free @ap without a graceful shutdown */
|
||||||
}
|
void ap_free(struct ap_state *ap)
|
||||||
|
{
|
||||||
|
ap_reset(ap);
|
||||||
|
l_genl_family_free(ap->nl80211);
|
||||||
|
l_free(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ap_station_disconnect(struct ap_state *ap, const uint8_t *mac,
|
||||||
|
enum mmpdu_reason_code reason)
|
||||||
|
{
|
||||||
|
struct sta_state *sta;
|
||||||
|
|
||||||
|
if (!ap->started)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sta = l_queue_remove_if(ap->sta_states, ap_sta_match_addr, mac);
|
||||||
|
if (!sta)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ap_del_station(sta, reason, false);
|
||||||
|
ap_sta_free(sta);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ap_if_data {
|
||||||
|
struct netdev *netdev;
|
||||||
|
struct ap_state *ap;
|
||||||
|
struct l_dbus_message *pending;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ap_if_event_func(enum ap_event_type type, const void *event_data,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ap_if_data *ap_if = user_data;
|
||||||
|
struct l_dbus_message *reply;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AP_EVENT_START_FAILED:
|
||||||
|
if (L_WARN_ON(!ap_if->pending))
|
||||||
|
break;
|
||||||
|
|
||||||
|
reply = dbus_error_failed(ap_if->pending);
|
||||||
|
dbus_pending_reply(&ap_if->pending, reply);
|
||||||
|
ap_if->ap = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_STARTED:
|
||||||
|
if (L_WARN_ON(!ap_if->pending))
|
||||||
|
break;
|
||||||
|
|
||||||
|
reply = l_dbus_message_new_method_return(ap_if->pending);
|
||||||
|
dbus_pending_reply(&ap_if->pending, reply);
|
||||||
|
l_dbus_property_changed(dbus_get_bus(),
|
||||||
|
netdev_get_path(ap_if->netdev),
|
||||||
|
IWD_AP_INTERFACE, "Started");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_STOPPING:
|
||||||
|
l_dbus_property_changed(dbus_get_bus(),
|
||||||
|
netdev_get_path(ap_if->netdev),
|
||||||
|
IWD_AP_INTERFACE, "Started");
|
||||||
|
|
||||||
|
if (!ap_if->pending)
|
||||||
|
ap_if->ap = NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AP_EVENT_STATION_ADDED:
|
||||||
|
case AP_EVENT_STATION_REMOVED:
|
||||||
|
/* Ignored */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap->pending = l_dbus_message_ref(message);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct l_dbus_message *ap_dbus_start(struct l_dbus *dbus,
|
static struct l_dbus_message *ap_dbus_start(struct l_dbus *dbus,
|
||||||
struct l_dbus_message *message, void *user_data)
|
struct l_dbus_message *message, void *user_data)
|
||||||
{
|
{
|
||||||
struct ap_state *ap = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
const char *ssid, *wpa2_psk;
|
const char *ssid, *wpa2_psk;
|
||||||
|
|
||||||
if (ap->pending)
|
if (ap_if->ap && ap_if->ap->started)
|
||||||
return dbus_error_busy(message);
|
|
||||||
|
|
||||||
if (ap->started)
|
|
||||||
return dbus_error_already_exists(message);
|
return dbus_error_already_exists(message);
|
||||||
|
|
||||||
|
if (ap_if->ap || ap_if->pending)
|
||||||
|
return dbus_error_busy(message);
|
||||||
|
|
||||||
if (!l_dbus_message_get_arguments(message, "ss", &ssid, &wpa2_psk))
|
if (!l_dbus_message_get_arguments(message, "ss", &ssid, &wpa2_psk))
|
||||||
return dbus_error_invalid_args(message);
|
return dbus_error_invalid_args(message);
|
||||||
|
|
||||||
if (ap_start(ap, ssid, wpa2_psk, message) < 0)
|
ap_if->ap = ap_start(ap_if->netdev, ssid, wpa2_psk, 0,
|
||||||
|
ap_if_event_func, ap_if);
|
||||||
|
if (!ap_if->ap)
|
||||||
return dbus_error_invalid_args(message);
|
return dbus_error_invalid_args(message);
|
||||||
|
|
||||||
|
ap_if->pending = l_dbus_message_ref(message);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ap_dbus_stop_cb(void *user_data)
|
||||||
|
{
|
||||||
|
struct ap_if_data *ap_if = user_data;
|
||||||
|
struct l_dbus_message *reply;
|
||||||
|
|
||||||
|
if (L_WARN_ON(!ap_if->pending))
|
||||||
|
return;
|
||||||
|
|
||||||
|
reply = l_dbus_message_new_method_return(ap_if->pending);
|
||||||
|
dbus_pending_reply(&ap_if->pending, reply);
|
||||||
|
ap_if->ap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct l_dbus_message *ap_dbus_stop(struct l_dbus *dbus,
|
static struct l_dbus_message *ap_dbus_stop(struct l_dbus *dbus,
|
||||||
struct l_dbus_message *message, void *user_data)
|
struct l_dbus_message *message, void *user_data)
|
||||||
{
|
{
|
||||||
struct ap_state *ap = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
|
|
||||||
if (ap->pending)
|
if (!ap_if->ap) {
|
||||||
return dbus_error_busy(message);
|
if (ap_if->pending)
|
||||||
|
return dbus_error_busy(message);
|
||||||
|
|
||||||
/* already stopped, no-op */
|
/* already stopped, no-op */
|
||||||
if (!ap->started)
|
|
||||||
return l_dbus_message_new_method_return(message);
|
return l_dbus_message_new_method_return(message);
|
||||||
|
}
|
||||||
|
|
||||||
if (ap_stop(ap, message) < 0)
|
if (ap_if->pending) {
|
||||||
return dbus_error_failed(message);
|
struct l_dbus_message *reply;
|
||||||
|
|
||||||
|
reply = dbus_error_aborted(ap_if->pending);
|
||||||
|
dbus_pending_reply(&ap_if->pending, reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
ap_if->pending = l_dbus_message_ref(message);
|
||||||
|
ap_shutdown(ap_if->ap, ap_dbus_stop_cb, ap_if);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1612,8 +1770,8 @@ static bool ap_dbus_property_get_started(struct l_dbus *dbus,
|
|||||||
struct l_dbus_message_builder *builder,
|
struct l_dbus_message_builder *builder,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct ap_state *ap = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
bool started = ap->started;
|
bool started = ap_if->ap && ap_if->ap->started;
|
||||||
|
|
||||||
l_dbus_message_builder_append_basic(builder, 'b', &started);
|
l_dbus_message_builder_append_basic(builder, 'b', &started);
|
||||||
|
|
||||||
@ -1632,27 +1790,36 @@ static void ap_setup_interface(struct l_dbus_interface *interface)
|
|||||||
|
|
||||||
static void ap_destroy_interface(void *user_data)
|
static void ap_destroy_interface(void *user_data)
|
||||||
{
|
{
|
||||||
struct ap_state *ap = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
|
|
||||||
ap_free(ap);
|
if (ap_if->pending) {
|
||||||
|
struct l_dbus_message *reply;
|
||||||
|
|
||||||
|
reply = dbus_error_aborted(ap_if->pending);
|
||||||
|
dbus_pending_reply(&ap_if->pending, reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ap_if->ap)
|
||||||
|
ap_free(ap_if->ap);
|
||||||
|
|
||||||
|
l_free(ap_if);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_add_interface(struct netdev *netdev)
|
static void ap_add_interface(struct netdev *netdev)
|
||||||
{
|
{
|
||||||
struct ap_state *ap;
|
struct ap_if_data *ap_if;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Check wiphy supported channels and NL80211_ATTR_TX_FRAME_TYPES
|
* TODO: Check wiphy supported channels and NL80211_ATTR_TX_FRAME_TYPES
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* just allocate/set device, Start method will complete setup */
|
/* just allocate/set device, Start method will complete setup */
|
||||||
ap = l_new(struct ap_state, 1);
|
ap_if = l_new(struct ap_if_data, 1);
|
||||||
ap->netdev = netdev;
|
ap_if->netdev = netdev;
|
||||||
ap->nl80211 = l_genl_family_new(iwd_get_genl(), NL80211_GENL_NAME);
|
|
||||||
|
|
||||||
/* setup ap dbus interface */
|
/* setup ap dbus interface */
|
||||||
l_dbus_object_add_interface(dbus_get_bus(),
|
l_dbus_object_add_interface(dbus_get_bus(),
|
||||||
netdev_get_path(netdev), IWD_AP_INTERFACE, ap);
|
netdev_get_path(netdev), IWD_AP_INTERFACE, ap_if);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_remove_interface(struct netdev *netdev)
|
static void ap_remove_interface(struct netdev *netdev)
|
||||||
|
56
src/ap.h
Normal file
56
src/ap.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Wireless daemon for Linux
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ap_state;
|
||||||
|
struct iovec;
|
||||||
|
|
||||||
|
enum ap_event_type {
|
||||||
|
AP_EVENT_START_FAILED,
|
||||||
|
AP_EVENT_STARTED,
|
||||||
|
AP_EVENT_STOPPING,
|
||||||
|
AP_EVENT_STATION_ADDED,
|
||||||
|
AP_EVENT_STATION_REMOVED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ap_event_station_added_data {
|
||||||
|
const uint8_t *mac;
|
||||||
|
const uint8_t *rsn_ie;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ap_event_station_removed_data {
|
||||||
|
const uint8_t *mac;
|
||||||
|
enum mmpdu_reason_code reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ap_event_func_t)(enum ap_event_type type, const void *event_data,
|
||||||
|
void *user_data);
|
||||||
|
typedef void (*ap_stopped_func_t)(void *user_data);
|
||||||
|
|
||||||
|
struct ap_state *ap_start(struct netdev *netdev, const char *ssid,
|
||||||
|
const char *psk, int channel,
|
||||||
|
ap_event_func_t event_func, void *user_data);
|
||||||
|
void ap_shutdown(struct ap_state *ap, ap_stopped_func_t stopped_func,
|
||||||
|
void *user_data);
|
||||||
|
void ap_free(struct ap_state *ap);
|
||||||
|
|
||||||
|
bool ap_station_disconnect(struct ap_state *ap, const uint8_t *mac,
|
||||||
|
enum mmpdu_reason_code reason);
|
Loading…
Reference in New Issue
Block a user