netdev: add join_adhoc/leave_adhoc API's

These will issue a JOIN/LEAVE_IBSS to the kernel. There is
a TODO regarding network configuration. For now, only the
SSID is configurable. This configuration is also required
for AP, but needs to be thought out. Since the current
AP Dbus API has nothing related to configuration items
such as freq/channel or RSN elements they are hard coded,
and will be for Ad-Hoc as well (for now).
This commit is contained in:
James Prestwood 2018-07-17 14:15:59 -07:00 committed by Denis Kenzior
parent e10d79b53f
commit 88bd69269e
2 changed files with 129 additions and 0 deletions

View File

@ -82,11 +82,14 @@ struct netdev {
netdev_connect_cb_t connect_cb;
netdev_disconnect_cb_t disconnect_cb;
netdev_neighbor_report_cb_t neighbor_report_cb;
netdev_adhoc_cb_t adhoc_cb;
void *user_data;
struct eapol_sm *sm;
struct handshake_state *handshake;
uint32_t connect_cmd_id;
uint32_t disconnect_cmd_id;
uint32_t join_adhoc_cmd_id;
uint32_t leave_adhoc_cmd_id;
enum netdev_result result;
struct l_timeout *neighbor_report_timeout;
struct l_timeout *sa_query_timeout;
@ -588,6 +591,16 @@ static void netdev_free(void *data)
netdev->user_data = NULL;
}
if (netdev->join_adhoc_cmd_id) {
l_genl_family_cancel(nl80211, netdev->join_adhoc_cmd_id);
netdev->join_adhoc_cmd_id = 0;
}
if (netdev->leave_adhoc_cmd_id) {
l_genl_family_cancel(nl80211, netdev->leave_adhoc_cmd_id);
netdev->leave_adhoc_cmd_id = 0;
}
device_remove(netdev->device);
watchlist_destroy(&netdev->event_watches);
watchlist_destroy(&netdev->frame_watches);
@ -2482,6 +2495,113 @@ int netdev_reassociate(struct netdev *netdev, struct scan_bss *target_bss,
return err;
}
static void netdev_join_adhoc_cb(struct l_genl_msg *msg, void *user_data)
{
struct netdev *netdev = user_data;
netdev->join_adhoc_cmd_id = 0;
if (netdev->adhoc_cb)
netdev->adhoc_cb(netdev, l_genl_msg_get_error(msg),
netdev->user_data);
}
int netdev_join_adhoc(struct netdev *netdev, const char *ssid,
struct iovec *extra_ie, size_t extra_ie_elems,
bool control_port, netdev_adhoc_cb_t cb,
void *user_data)
{
struct l_genl_msg *cmd;
uint32_t ifindex = device_get_ifindex(netdev->device);
uint32_t ch_freq = scan_channel_to_freq(6, SCAN_BAND_2_4_GHZ);
uint32_t ch_type = NL80211_CHAN_HT20;
if (netdev->type != NL80211_IFTYPE_ADHOC) {
l_error("iftype is invalid for adhoc: %u",
netdev_get_iftype(netdev));
return -ENOTSUP;
}
if (netdev->join_adhoc_cmd_id || netdev->leave_adhoc_cmd_id)
return -EBUSY;
netdev->adhoc_cb = cb;
netdev->user_data = user_data;
cmd = l_genl_msg_new_sized(NL80211_CMD_JOIN_IBSS, 128);
l_genl_msg_append_attr(cmd, NL80211_ATTR_IFINDEX, 4, &ifindex);
l_genl_msg_append_attr(cmd, NL80211_ATTR_SSID, strlen(ssid), ssid);
l_genl_msg_append_attr(cmd, NL80211_ATTR_WIPHY_FREQ, 4, &ch_freq);
l_genl_msg_append_attr(cmd, NL80211_ATTR_WIPHY_CHANNEL_TYPE, 4,
&ch_type);
l_genl_msg_append_attrv(cmd, NL80211_ATTR_IE, extra_ie, extra_ie_elems);
l_genl_msg_append_attr(cmd, NL80211_ATTR_SOCKET_OWNER, 0, NULL);
if (control_port)
l_genl_msg_append_attr(cmd, NL80211_ATTR_CONTROL_PORT, 0, NULL);
if (netdev->pae_over_nl80211)
l_genl_msg_append_attr(cmd,
NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
0, NULL);
netdev->join_adhoc_cmd_id = l_genl_family_send(nl80211, cmd,
netdev_join_adhoc_cb, netdev, NULL);
if (!netdev->join_adhoc_cmd_id) {
netdev->adhoc_cb = NULL;
netdev->user_data = NULL;
return -EIO;
}
return 0;
}
static void netdev_leave_adhoc_cb(struct l_genl_msg *msg, void *user_data)
{
struct netdev *netdev = user_data;
netdev->leave_adhoc_cmd_id = 0;
if (netdev->adhoc_cb)
netdev->adhoc_cb(netdev, l_genl_msg_get_error(msg),
netdev->user_data);
netdev->adhoc_cb = NULL;
}
int netdev_leave_adhoc(struct netdev *netdev, netdev_adhoc_cb_t cb,
void *user_data)
{
struct l_genl_msg *cmd;
if (netdev->type != NL80211_IFTYPE_ADHOC) {
l_error("iftype is invalid for adhoc: %u",
netdev_get_iftype(netdev));
return -ENOTSUP;
}
if (netdev->join_adhoc_cmd_id || netdev->leave_adhoc_cmd_id)
return -EBUSY;
netdev->adhoc_cb = cb;
netdev->user_data = user_data;
cmd = l_genl_msg_new_sized(NL80211_CMD_LEAVE_IBSS, 64);
l_genl_msg_append_attr(cmd, NL80211_ATTR_IFINDEX, 4, &netdev->index);
netdev->leave_adhoc_cmd_id = l_genl_family_send(nl80211, cmd,
netdev_leave_adhoc_cb, netdev,
NULL);
if (!netdev->leave_adhoc_cmd_id)
return -EIO;
return 0;
}
/*
* Build an FT Authentication Request frame according to 12.5.2 / 12.5.4:
* RSN or non-RSN Over-the-air FT Protocol, with the IE contents

View File

@ -70,6 +70,8 @@ typedef void (*netdev_event_func_t)(struct netdev *netdev,
void *user_data);
typedef void (*netdev_disconnect_cb_t)(struct netdev *netdev, bool result,
void *user_data);
typedef void (*netdev_adhoc_cb_t)(struct netdev *netdev, int result,
void *user_data);
typedef void (*netdev_watch_func_t)(struct netdev *netdev,
enum netdev_watch_event event,
void *user_data);
@ -135,6 +137,13 @@ int netdev_preauthenticate(struct netdev *netdev, struct scan_bss *target_bss,
int netdev_del_station(struct netdev *netdev, const uint8_t *sta,
uint16_t reason_code, bool disassociate);
int netdev_join_adhoc(struct netdev *netdev, const char *ssid,
struct iovec *extra_ie, size_t extra_ie_elems,
bool control_port, netdev_adhoc_cb_t cb,
void *user_data);
int netdev_leave_adhoc(struct netdev *netdev, netdev_adhoc_cb_t cb,
void *user_data);
int netdev_set_powered(struct netdev *netdev, bool powered,
netdev_set_powered_cb_t cb, void *user_data,
netdev_destroy_func_t destroy);