From 88bd69269e219b112149b8ae87826329f9f2fec1 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Tue, 17 Jul 2018 14:15:59 -0700 Subject: [PATCH] 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). --- src/netdev.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/netdev.h | 9 ++++ 2 files changed, 129 insertions(+) diff --git a/src/netdev.c b/src/netdev.c index de30e728..9f008e4e 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -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 diff --git a/src/netdev.h b/src/netdev.h index 3017307b..97e842df 100644 --- a/src/netdev.h +++ b/src/netdev.h @@ -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);