mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-03 10:32:33 +01:00
ap: Drop struct ap_config in favor of l_settings
Change ap_start to load all of the AP configuration from a struct l_settings, moving the 6 or so parameters from struct ap_config members to the l_settings groups and keys. This extends the ap profile concept used for the DHCP settings. ap_start callers create the l_settings object and fill the values in it or read the settings in from a file. Since ap_setup_dhcp and ap_load_profile_and_dhcp no longer do the settings file loading, they needed to be refactored and some issues were fixed in their logic, e.g. l_dhcp_server_set_ip_address() was never called when the "IP pool" was used. Also the IP pool was previously only used if the ap->config->profile was NULL and this didn't match what the docs said: "If [IPv4].Address is not provided and no IP address is set on the interface prior to calling StartProfile the IP pool will be used."
This commit is contained in:
parent
11914431bc
commit
ab6cd7e465
545
src/ap.c
545
src/ap.c
@ -61,7 +61,15 @@ struct ap_state {
|
|||||||
const struct ap_ops *ops;
|
const struct ap_ops *ops;
|
||||||
ap_stopped_func_t stopped_func;
|
ap_stopped_func_t stopped_func;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
struct ap_config *config;
|
|
||||||
|
char ssid[33];
|
||||||
|
char passphrase[64];
|
||||||
|
uint8_t psk[32];
|
||||||
|
uint8_t channel;
|
||||||
|
uint8_t *authorized_macs;
|
||||||
|
unsigned int authorized_macs_num;
|
||||||
|
char wsc_name[33];
|
||||||
|
struct wsc_primary_device_type wsc_primary_device_type;
|
||||||
|
|
||||||
unsigned int ciphers;
|
unsigned int ciphers;
|
||||||
enum ie_rsn_cipher_suite group_cipher;
|
enum ie_rsn_cipher_suite group_cipher;
|
||||||
@ -228,24 +236,6 @@ static const char *broadcast_from_ip(const char *ip)
|
|||||||
return inet_ntoa(ia);
|
return inet_ntoa(ia);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ap_config_free(struct ap_config *config)
|
|
||||||
{
|
|
||||||
if (unlikely(!config))
|
|
||||||
return;
|
|
||||||
|
|
||||||
l_free(config->ssid);
|
|
||||||
|
|
||||||
explicit_bzero(config->passphrase, sizeof(config->passphrase));
|
|
||||||
explicit_bzero(config->psk, sizeof(config->psk));
|
|
||||||
l_free(config->authorized_macs);
|
|
||||||
l_free(config->wsc_name);
|
|
||||||
|
|
||||||
if (config->profile)
|
|
||||||
l_free(config->profile);
|
|
||||||
|
|
||||||
l_free(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ap_stop_handshake(struct sta_state *sta)
|
static void ap_stop_handshake(struct sta_state *sta)
|
||||||
{
|
{
|
||||||
if (sta->sm) {
|
if (sta->sm) {
|
||||||
@ -301,6 +291,14 @@ static void ap_reset(struct ap_state *ap)
|
|||||||
{
|
{
|
||||||
struct netdev *netdev = ap->netdev;
|
struct netdev *netdev = ap->netdev;
|
||||||
|
|
||||||
|
explicit_bzero(ap->passphrase, sizeof(ap->passphrase));
|
||||||
|
explicit_bzero(ap->psk, sizeof(ap->psk));
|
||||||
|
|
||||||
|
if (ap->authorized_macs_num) {
|
||||||
|
l_free(ap->authorized_macs);
|
||||||
|
ap->authorized_macs_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (ap->mlme_watch)
|
if (ap->mlme_watch)
|
||||||
l_genl_family_unregister(ap->nl80211, ap->mlme_watch);
|
l_genl_family_unregister(ap->nl80211, ap->mlme_watch);
|
||||||
|
|
||||||
@ -317,9 +315,6 @@ static void ap_reset(struct ap_state *ap)
|
|||||||
if (ap->rates)
|
if (ap->rates)
|
||||||
l_uintset_free(ap->rates);
|
l_uintset_free(ap->rates);
|
||||||
|
|
||||||
ap_config_free(ap->config);
|
|
||||||
ap->config = NULL;
|
|
||||||
|
|
||||||
l_queue_destroy(ap->wsc_pbc_probes, l_free);
|
l_queue_destroy(ap->wsc_pbc_probes, l_free);
|
||||||
|
|
||||||
ap->started = false;
|
ap->started = false;
|
||||||
@ -666,25 +661,23 @@ static size_t ap_write_wsc_ie(struct ap_state *ap,
|
|||||||
|
|
||||||
wsc_pr.response_type = WSC_RESPONSE_TYPE_AP;
|
wsc_pr.response_type = WSC_RESPONSE_TYPE_AP;
|
||||||
memcpy(wsc_pr.uuid_e, ap->wsc_uuid_r, sizeof(wsc_pr.uuid_e));
|
memcpy(wsc_pr.uuid_e, ap->wsc_uuid_r, sizeof(wsc_pr.uuid_e));
|
||||||
wsc_pr.primary_device_type =
|
wsc_pr.primary_device_type = ap->wsc_primary_device_type;
|
||||||
ap->config->wsc_primary_device_type;
|
|
||||||
|
|
||||||
if (ap->config->wsc_name)
|
if (ap->wsc_name[0] != '\0')
|
||||||
l_strlcpy(wsc_pr.device_name, ap->config->wsc_name,
|
l_strlcpy(wsc_pr.device_name, ap->wsc_name,
|
||||||
sizeof(wsc_pr.device_name));
|
sizeof(wsc_pr.device_name));
|
||||||
|
|
||||||
wsc_pr.config_methods =
|
wsc_pr.config_methods =
|
||||||
WSC_CONFIGURATION_METHOD_PUSH_BUTTON;
|
WSC_CONFIGURATION_METHOD_PUSH_BUTTON;
|
||||||
|
|
||||||
if (ap->config->authorized_macs_num) {
|
if (ap->authorized_macs_num) {
|
||||||
size_t len;
|
size_t len = ap->authorized_macs_num * 6;
|
||||||
|
|
||||||
len = ap->config->authorized_macs_num * 6;
|
|
||||||
if (len > sizeof(wsc_pr.authorized_macs))
|
if (len > sizeof(wsc_pr.authorized_macs))
|
||||||
len = sizeof(wsc_pr.authorized_macs);
|
len = sizeof(wsc_pr.authorized_macs);
|
||||||
|
|
||||||
memcpy(wsc_pr.authorized_macs,
|
memcpy(wsc_pr.authorized_macs,
|
||||||
ap->config->authorized_macs, len);
|
ap->authorized_macs, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
wsc_data = wsc_build_probe_response(&wsc_pr, &wsc_data_size);
|
wsc_data = wsc_build_probe_response(&wsc_pr, &wsc_data_size);
|
||||||
@ -701,15 +694,14 @@ static size_t ap_write_wsc_ie(struct ap_state *ap,
|
|||||||
WSC_CONFIGURATION_METHOD_PUSH_BUTTON;
|
WSC_CONFIGURATION_METHOD_PUSH_BUTTON;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ap->config->authorized_macs_num) {
|
if (ap->authorized_macs_num) {
|
||||||
size_t len;
|
size_t len = ap->authorized_macs_num * 6;
|
||||||
|
|
||||||
len = ap->config->authorized_macs_num * 6;
|
|
||||||
if (len > sizeof(wsc_beacon.authorized_macs))
|
if (len > sizeof(wsc_beacon.authorized_macs))
|
||||||
len = sizeof(wsc_beacon.authorized_macs);
|
len = sizeof(wsc_beacon.authorized_macs);
|
||||||
|
|
||||||
memcpy(wsc_beacon.authorized_macs,
|
memcpy(wsc_beacon.authorized_macs,
|
||||||
ap->config->authorized_macs, len);
|
ap->authorized_macs, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
wsc_data = wsc_build_beacon(&wsc_beacon, &wsc_data_size);
|
wsc_data = wsc_build_beacon(&wsc_beacon, &wsc_data_size);
|
||||||
@ -831,8 +823,7 @@ static size_t ap_build_beacon_pr_head(struct ap_state *ap,
|
|||||||
|
|
||||||
/* SSID IE */
|
/* SSID IE */
|
||||||
ie_tlv_builder_next(&builder, IE_TYPE_SSID);
|
ie_tlv_builder_next(&builder, IE_TYPE_SSID);
|
||||||
ie_tlv_builder_set_data(&builder, ap->config->ssid,
|
ie_tlv_builder_set_data(&builder, ap->ssid, strlen(ap->ssid));
|
||||||
strlen(ap->config->ssid));
|
|
||||||
|
|
||||||
/* Supported Rates IE */
|
/* Supported Rates IE */
|
||||||
ie_tlv_builder_next(&builder, IE_TYPE_SUPPORTED_RATES);
|
ie_tlv_builder_next(&builder, IE_TYPE_SUPPORTED_RATES);
|
||||||
@ -857,7 +848,7 @@ static size_t ap_build_beacon_pr_head(struct ap_state *ap,
|
|||||||
|
|
||||||
/* DSSS Parameter Set IE for DSSS, HR, ERP and HT PHY rates */
|
/* DSSS Parameter Set IE for DSSS, HR, ERP and HT PHY rates */
|
||||||
ie_tlv_builder_next(&builder, IE_TYPE_DSSS_PARAMETER_SET);
|
ie_tlv_builder_next(&builder, IE_TYPE_DSSS_PARAMETER_SET);
|
||||||
ie_tlv_builder_set_data(&builder, &ap->config->channel, 1);
|
ie_tlv_builder_set_data(&builder, &ap->channel, 1);
|
||||||
|
|
||||||
ie_tlv_builder_finalize(&builder, &len);
|
ie_tlv_builder_finalize(&builder, &len);
|
||||||
return 36 + len;
|
return 36 + len;
|
||||||
@ -938,8 +929,7 @@ static uint32_t ap_send_mgmt_frame(struct ap_state *ap,
|
|||||||
frame_xchg_cb_t callback,
|
frame_xchg_cb_t callback,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
uint32_t ch_freq = scan_channel_to_freq(ap->config->channel,
|
uint32_t ch_freq = scan_channel_to_freq(ap->channel, SCAN_BAND_2_4_GHZ);
|
||||||
SCAN_BAND_2_4_GHZ);
|
|
||||||
uint64_t wdev_id = netdev_get_wdev_id(ap->netdev);
|
uint64_t wdev_id = netdev_get_wdev_id(ap->netdev);
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
|
|
||||||
@ -958,8 +948,7 @@ static void ap_start_handshake(struct sta_state *sta, bool use_eapol_start,
|
|||||||
struct ie_rsn_info rsn;
|
struct ie_rsn_info rsn;
|
||||||
uint8_t bss_rsne[64];
|
uint8_t bss_rsne[64];
|
||||||
|
|
||||||
handshake_state_set_ssid(sta->hs, (void *) ap->config->ssid,
|
handshake_state_set_ssid(sta->hs, (void *) ap->ssid, strlen(ap->ssid));
|
||||||
strlen(ap->config->ssid));
|
|
||||||
handshake_state_set_authenticator_address(sta->hs, own_addr);
|
handshake_state_set_authenticator_address(sta->hs, own_addr);
|
||||||
handshake_state_set_supplicant_address(sta->hs, sta->addr);
|
handshake_state_set_supplicant_address(sta->hs, sta->addr);
|
||||||
|
|
||||||
@ -1026,7 +1015,7 @@ static void ap_start_rsna(struct sta_state *sta, const uint8_t *gtk_rsc)
|
|||||||
handshake_state_set_authenticator(sta->hs, true);
|
handshake_state_set_authenticator(sta->hs, true);
|
||||||
handshake_state_set_event_func(sta->hs, ap_handshake_event, sta);
|
handshake_state_set_event_func(sta->hs, ap_handshake_event, sta);
|
||||||
handshake_state_set_supplicant_ie(sta->hs, sta->assoc_rsne);
|
handshake_state_set_supplicant_ie(sta->hs, sta->assoc_rsne);
|
||||||
handshake_state_set_pmk(sta->hs, sta->ap->config->psk, 32);
|
handshake_state_set_pmk(sta->hs, sta->ap->psk, 32);
|
||||||
ap_start_handshake(sta, false, gtk_rsc);
|
ap_start_handshake(sta, false, gtk_rsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1144,16 +1133,15 @@ static void ap_start_eap_wsc(struct sta_state *sta)
|
|||||||
WSC_RF_BAND_2_4_GHZ);
|
WSC_RF_BAND_2_4_GHZ);
|
||||||
l_settings_set_uint(sta->wsc_settings, "WSC", "ConfigurationMethods",
|
l_settings_set_uint(sta->wsc_settings, "WSC", "ConfigurationMethods",
|
||||||
WSC_CONFIGURATION_METHOD_PUSH_BUTTON);
|
WSC_CONFIGURATION_METHOD_PUSH_BUTTON);
|
||||||
l_settings_set_string(sta->wsc_settings, "WSC", "WPA2-SSID",
|
l_settings_set_string(sta->wsc_settings, "WSC", "WPA2-SSID", ap->ssid);
|
||||||
ap->config->ssid);
|
|
||||||
|
|
||||||
if (ap->config->passphrase[0])
|
if (ap->passphrase[0])
|
||||||
l_settings_set_string(sta->wsc_settings,
|
l_settings_set_string(sta->wsc_settings,
|
||||||
"WSC", "WPA2-Passphrase",
|
"WSC", "WPA2-Passphrase",
|
||||||
ap->config->passphrase);
|
ap->passphrase);
|
||||||
else
|
else
|
||||||
l_settings_set_bytes(sta->wsc_settings,
|
l_settings_set_bytes(sta->wsc_settings,
|
||||||
"WSC", "WPA2-PSK", ap->config->psk, 32);
|
"WSC", "WPA2-PSK", ap->psk, 32);
|
||||||
|
|
||||||
sta->hs = netdev_handshake_state_new(ap->netdev);
|
sta->hs = netdev_handshake_state_new(ap->netdev);
|
||||||
handshake_state_set_authenticator(sta->hs, true);
|
handshake_state_set_authenticator(sta->hs, true);
|
||||||
@ -1611,8 +1599,8 @@ static void ap_assoc_reassoc(struct sta_state *sta, bool reassoc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rates || !ssid || (!wsc_data && !rsn) ||
|
if (!rates || !ssid || (!wsc_data && !rsn) ||
|
||||||
ssid_len != strlen(ap->config->ssid) ||
|
ssid_len != strlen(ap->ssid) ||
|
||||||
memcmp(ssid, ap->config->ssid, ssid_len)) {
|
memcmp(ssid, ap->ssid, ssid_len)) {
|
||||||
err = MMPDU_REASON_CODE_INVALID_IE;
|
err = MMPDU_REASON_CODE_INVALID_IE;
|
||||||
goto bad_frame;
|
goto bad_frame;
|
||||||
}
|
}
|
||||||
@ -1922,11 +1910,11 @@ static void ap_probe_req_cb(const struct mmpdu_header *hdr, const void *body,
|
|||||||
|
|
||||||
if (!ssid || ssid_len == 0) /* Wildcard SSID */
|
if (!ssid || ssid_len == 0) /* Wildcard SSID */
|
||||||
match = true;
|
match = true;
|
||||||
else if (ssid && ssid_len == strlen(ap->config->ssid) && /* One SSID */
|
else if (ssid && ssid_len == strlen(ap->ssid) && /* One SSID */
|
||||||
!memcmp(ssid, ap->config->ssid, ssid_len))
|
!memcmp(ssid, ap->ssid, ssid_len))
|
||||||
match = true;
|
match = true;
|
||||||
else if (ssid && ssid_len == 7 && !memcmp(ssid, "DIRECT-", 7) &&
|
else if (ssid && ssid_len == 7 && !memcmp(ssid, "DIRECT-", 7) &&
|
||||||
!memcmp(ssid, ap->config->ssid, 7)) /* P2P wildcard */
|
!memcmp(ssid, ap->ssid, 7)) /* P2P wildcard */
|
||||||
match = true;
|
match = true;
|
||||||
else if (ssid_list) { /* SSID List */
|
else if (ssid_list) { /* SSID List */
|
||||||
ie_tlv_iter_init(&iter, ssid_list, ssid_list_len);
|
ie_tlv_iter_init(&iter, ssid_list, ssid_list_len);
|
||||||
@ -1938,16 +1926,15 @@ static void ap_probe_req_cb(const struct mmpdu_header *hdr, const void *body,
|
|||||||
ssid = (const char *) ie_tlv_iter_get_data(&iter);
|
ssid = (const char *) ie_tlv_iter_get_data(&iter);
|
||||||
ssid_len = ie_tlv_iter_get_length(&iter);
|
ssid_len = ie_tlv_iter_get_length(&iter);
|
||||||
|
|
||||||
if (ssid_len == strlen(ap->config->ssid) &&
|
if (ssid_len == strlen(ap->ssid) &&
|
||||||
!memcmp(ssid, ap->config->ssid,
|
!memcmp(ssid, ap->ssid, ssid_len)) {
|
||||||
ssid_len)) {
|
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsss_channel != 0 && dsss_channel != ap->config->channel)
|
if (dsss_channel != 0 && dsss_channel != ap->channel)
|
||||||
match = false;
|
match = false;
|
||||||
|
|
||||||
if (!match)
|
if (!match)
|
||||||
@ -2053,15 +2040,15 @@ static void ap_auth_cb(const struct mmpdu_header *hdr, const void *body,
|
|||||||
memcmp(hdr->address_3, bssid, 6))
|
memcmp(hdr->address_3, bssid, 6))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ap->config->authorized_macs_num) {
|
if (ap->authorized_macs_num) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < ap->config->authorized_macs_num; i++)
|
for (i = 0; i < ap->authorized_macs_num; i++)
|
||||||
if (!memcmp(from, ap->config->authorized_macs + i * 6,
|
if (!memcmp(from, ap->authorized_macs + i * 6,
|
||||||
6))
|
6))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == ap->config->authorized_macs_num) {
|
if (i == ap->authorized_macs_num) {
|
||||||
ap_auth_reply(ap, from, MMPDU_REASON_CODE_UNSPECIFIED);
|
ap_auth_reply(ap, from, MMPDU_REASON_CODE_UNSPECIFIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2210,8 +2197,7 @@ static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
|
|||||||
uint32_t nl_akm = CRYPTO_AKM_PSK;
|
uint32_t nl_akm = CRYPTO_AKM_PSK;
|
||||||
uint32_t wpa_version = NL80211_WPA_VERSION_2;
|
uint32_t wpa_version = NL80211_WPA_VERSION_2;
|
||||||
uint32_t auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
|
uint32_t auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
|
||||||
uint32_t ch_freq = scan_channel_to_freq(ap->config->channel,
|
uint32_t ch_freq = scan_channel_to_freq(ap->channel, SCAN_BAND_2_4_GHZ);
|
||||||
SCAN_BAND_2_4_GHZ);
|
|
||||||
uint32_t ch_width = NL80211_CHAN_WIDTH_20;
|
uint32_t ch_width = NL80211_CHAN_WIDTH_20;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
@ -2233,7 +2219,7 @@ static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cmd = l_genl_msg_new_sized(NL80211_CMD_START_AP, 256 + head_len +
|
cmd = l_genl_msg_new_sized(NL80211_CMD_START_AP, 256 + head_len +
|
||||||
tail_len + strlen(ap->config->ssid));
|
tail_len + strlen(ap->ssid));
|
||||||
|
|
||||||
/* SET_BEACON attrs */
|
/* SET_BEACON attrs */
|
||||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_BEACON_HEAD, head_len, head);
|
l_genl_msg_append_attr(cmd, NL80211_ATTR_BEACON_HEAD, head_len, head);
|
||||||
@ -2247,8 +2233,8 @@ static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
|
|||||||
&ap->beacon_interval);
|
&ap->beacon_interval);
|
||||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_DTIM_PERIOD, 4, &dtim_period);
|
l_genl_msg_append_attr(cmd, NL80211_ATTR_DTIM_PERIOD, 4, &dtim_period);
|
||||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
l_genl_msg_append_attr(cmd, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_SSID, strlen(ap->config->ssid),
|
l_genl_msg_append_attr(cmd, NL80211_ATTR_SSID, strlen(ap->ssid),
|
||||||
ap->config->ssid);
|
ap->ssid);
|
||||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_HIDDEN_SSID, 4,
|
l_genl_msg_append_attr(cmd, NL80211_ATTR_HIDDEN_SSID, 4,
|
||||||
&hidden_ssid);
|
&hidden_ssid);
|
||||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
|
l_genl_msg_append_attr(cmd, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
|
||||||
@ -2493,7 +2479,8 @@ static void ap_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dhcp_load_settings(struct ap_state *ap, struct l_settings *settings)
|
static bool dhcp_load_settings(struct ap_state *ap,
|
||||||
|
const struct l_settings *settings)
|
||||||
{
|
{
|
||||||
struct l_dhcp_server *server = ap->server;
|
struct l_dhcp_server *server = ap->server;
|
||||||
struct in_addr ia;
|
struct in_addr ia;
|
||||||
@ -2568,77 +2555,41 @@ error:
|
|||||||
* 3. Address in IP pool.
|
* 3. Address in IP pool.
|
||||||
*
|
*
|
||||||
* Returns: 0 if an IP was successfully selected and needs to be set
|
* Returns: 0 if an IP was successfully selected and needs to be set
|
||||||
* -EALREADY if an IP was already set on the interface
|
* -EALREADY if an IP was already set on the interface or
|
||||||
|
* IP configuration was not enabled,
|
||||||
* -EEXIST if the IP pool ran out of IP's
|
* -EEXIST if the IP pool ran out of IP's
|
||||||
* -EINVAL if there was an error.
|
* -EINVAL if there was an error.
|
||||||
*/
|
*/
|
||||||
static int ap_setup_dhcp(struct ap_state *ap, struct l_settings *settings)
|
static int ap_setup_dhcp(struct ap_state *ap, const struct l_settings *settings)
|
||||||
{
|
{
|
||||||
uint32_t ifindex = netdev_get_ifindex(ap->netdev);
|
uint32_t ifindex = netdev_get_ifindex(ap->netdev);
|
||||||
struct in_addr ia;
|
struct in_addr ia;
|
||||||
uint32_t address = 0;
|
uint32_t address = 0;
|
||||||
|
L_AUTO_FREE_VAR(char *, addr) = NULL;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
ap->server = l_dhcp_server_new(ifindex);
|
|
||||||
if (!ap->server) {
|
|
||||||
l_error("Failed to create DHCP server on %u", ifindex);
|
|
||||||
return -EINVAL;;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getenv("IWD_DHCP_DEBUG"))
|
|
||||||
l_dhcp_server_set_debug(ap->server, do_debug,
|
|
||||||
"[DHCPv4 SERV] ", NULL);
|
|
||||||
|
|
||||||
/* get the current address if there is one */
|
/* get the current address if there is one */
|
||||||
if (l_net_get_address(ifindex, &ia) && ia.s_addr != 0)
|
if (l_net_get_address(ifindex, &ia) && ia.s_addr != 0)
|
||||||
address = ia.s_addr;
|
address = ia.s_addr;
|
||||||
|
|
||||||
if (ap->config->profile) {
|
addr = l_settings_get_string(settings, "IPv4", "Address");
|
||||||
char *addr;
|
if (addr) {
|
||||||
|
if (inet_pton(AF_INET, addr, &ia) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
addr = l_settings_get_string(settings, "IPv4", "Address");
|
/* Is a matching address already set on interface? */
|
||||||
if (addr) {
|
if (ia.s_addr == address)
|
||||||
if (inet_pton(AF_INET, addr, &ia) < 0)
|
|
||||||
goto free_addr;
|
|
||||||
|
|
||||||
/* Is a matching address already set on interface? */
|
|
||||||
if (ia.s_addr == address)
|
|
||||||
ret = -EALREADY;
|
|
||||||
else
|
|
||||||
ret = 0;
|
|
||||||
} else if (address) {
|
|
||||||
/* No address in config, but interface has one set */
|
|
||||||
addr = l_strdup(inet_ntoa(ia));
|
|
||||||
ret = -EALREADY;
|
ret = -EALREADY;
|
||||||
} else
|
else
|
||||||
goto free_addr;
|
ret = 0;
|
||||||
|
|
||||||
/* Set the remaining DHCP options in config file */
|
|
||||||
if (!dhcp_load_settings(ap, settings)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto free_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!l_dhcp_server_set_ip_address(ap->server, addr)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto free_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ap->own_ip = l_strdup(addr);
|
|
||||||
|
|
||||||
free_addr:
|
|
||||||
l_free(addr);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
} else if (address) {
|
} else if (address) {
|
||||||
/* No config file and address is already set */
|
/* No address in config, but interface has one set */
|
||||||
ap->own_ip = l_strdup(inet_ntoa(ia));
|
addr = l_strdup(inet_ntoa(ia));
|
||||||
|
ret = -EALREADY;
|
||||||
return -EALREADY;
|
|
||||||
} else if (pool.used) {
|
} else if (pool.used) {
|
||||||
/* No config file, no address set. Use IP pool */
|
/* No config file, no address set. Use IP pool */
|
||||||
ap->own_ip = ip_pool_get();
|
addr = ip_pool_get();
|
||||||
if (!ap->own_ip) {
|
if (!addr) {
|
||||||
l_error("No more IP's in pool, cannot start AP on %u",
|
l_error("No more IP's in pool, cannot start AP on %u",
|
||||||
ifindex);
|
ifindex);
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
@ -2646,52 +2597,41 @@ free_addr:
|
|||||||
|
|
||||||
ap->use_ip_pool = true;
|
ap->use_ip_pool = true;
|
||||||
ap->ip_prefix = pool.prefix;
|
ap->ip_prefix = pool.prefix;
|
||||||
|
ret = 0;
|
||||||
|
} else
|
||||||
|
return -EALREADY;
|
||||||
|
|
||||||
return 0;
|
ap->server = l_dhcp_server_new(ifindex);
|
||||||
|
if (!ap->server) {
|
||||||
|
l_error("Failed to create DHCP server on %u", ifindex);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
if (getenv("IWD_DHCP_DEBUG"))
|
||||||
|
l_dhcp_server_set_debug(ap->server, do_debug,
|
||||||
|
"[DHCPv4 SERV] ", NULL);
|
||||||
|
|
||||||
|
/* Set the remaining DHCP options in config file */
|
||||||
|
if (!dhcp_load_settings(ap, settings))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!l_dhcp_server_set_ip_address(ap->server, addr))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ap->own_ip = l_steal_ptr(addr);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
|
static int ap_load_dhcp(struct ap_state *ap, const struct l_settings *config,
|
||||||
|
bool *wait_dhcp)
|
||||||
{
|
{
|
||||||
uint32_t ifindex = netdev_get_ifindex(ap->netdev);
|
uint32_t ifindex = netdev_get_ifindex(ap->netdev);
|
||||||
char *passphrase;
|
|
||||||
struct l_settings *settings = NULL;
|
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
/* No profile or DHCP settings */
|
if (!l_settings_has_group(config, "IPv4"))
|
||||||
if (!ap->config->profile && !pool.used)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (ap->config->profile) {
|
err = ap_setup_dhcp(ap, config);
|
||||||
settings = l_settings_new();
|
|
||||||
|
|
||||||
if (!l_settings_load_from_file(settings, ap->config->profile))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
passphrase = l_settings_get_string(settings, "Security",
|
|
||||||
"Passphrase");
|
|
||||||
if (passphrase) {
|
|
||||||
if (strlen(passphrase) > 63) {
|
|
||||||
l_error("[Security].Passphrase must not exceed "
|
|
||||||
"63 characters");
|
|
||||||
l_free(passphrase);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(ap->config->passphrase, passphrase);
|
|
||||||
l_free(passphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!l_settings_has_group(settings, "IPv4")) {
|
|
||||||
*wait_dhcp = false;
|
|
||||||
err = 0;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ap_setup_dhcp(ap, settings);
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
/* Address change required */
|
/* Address change required */
|
||||||
ap->rtnl_add_cmd = l_rtnl_ifaddr4_add(rtnl, ifindex,
|
ap->rtnl_add_cmd = l_rtnl_ifaddr4_add(rtnl, ifindex,
|
||||||
@ -2701,8 +2641,7 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
|
|||||||
|
|
||||||
if (!ap->rtnl_add_cmd) {
|
if (!ap->rtnl_add_cmd) {
|
||||||
l_error("Failed to add IPv4 address");
|
l_error("Failed to add IPv4 address");
|
||||||
err = -EIO;
|
return -EIO;
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ap->cleanup_ip = true;
|
ap->cleanup_ip = true;
|
||||||
@ -2715,24 +2654,201 @@ static int ap_load_profile_and_dhcp(struct ap_state *ap, bool *wait_dhcp)
|
|||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
|
||||||
l_settings_free(settings);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ap_load_psk(struct ap_state *ap, const struct l_settings *config)
|
||||||
|
{
|
||||||
|
L_AUTO_FREE_VAR(char *, passphrase) =
|
||||||
|
l_settings_get_string(config, "Security", "Passphrase");
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (passphrase) {
|
||||||
|
if (strlen(passphrase) > 63) {
|
||||||
|
l_error("AP [Security].Passphrase must not exceed "
|
||||||
|
"63 characters");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(ap->passphrase, passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_settings_has_key(config, "Security", "PreSharedKey")) {
|
||||||
|
size_t psk_len;
|
||||||
|
L_AUTO_FREE_VAR(uint8_t *, psk) = l_settings_get_bytes(config,
|
||||||
|
"Security",
|
||||||
|
"PreSharedKey",
|
||||||
|
&psk_len);
|
||||||
|
|
||||||
|
if (!psk || psk_len != 32) {
|
||||||
|
l_error("AP [Security].PreSharedKey must be a 32-byte "
|
||||||
|
"hexstring");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ap->psk, psk, 32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!passphrase) {
|
||||||
|
l_error("AP requires at least one of [Security].PreSharedKey, "
|
||||||
|
"[Security].Passphrase to be present");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = crypto_psk_from_passphrase(passphrase, (uint8_t *) ap->ssid,
|
||||||
|
strlen(ap->ssid), ap->psk);
|
||||||
|
if (err < 0) {
|
||||||
|
l_error("AP couldn't generate the PSK from given "
|
||||||
|
"[Security].Passphrase value: %s (%i)",
|
||||||
|
strerror(-err), -err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
|
||||||
|
bool *out_wait_dhcp, bool *out_cck_rates)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
L_AUTO_FREE_VAR(char *, strval) = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
strval = l_settings_get_string(config, "General", "SSID");
|
||||||
|
if (L_WARN_ON(!strval))
|
||||||
|
return -ENOMSG;
|
||||||
|
|
||||||
|
len = strlen(strval);
|
||||||
|
if (len < 1 || len > 32) {
|
||||||
|
l_error("AP SSID length outside the [1, 32] range");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (L_WARN_ON(!l_utf8_validate(strval, len, NULL)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
strcpy(ap->ssid, strval);
|
||||||
|
l_free(l_steal_ptr(strval));
|
||||||
|
|
||||||
|
if (!ap_load_psk(ap, config))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This loads DHCP settings either from the l_settings object or uses
|
||||||
|
* the defaults. wait_on_address will be set true if an address change
|
||||||
|
* is required.
|
||||||
|
*/
|
||||||
|
err = ap_load_dhcp(ap, config, out_wait_dhcp);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (l_settings_has_key(config, "General", "Channel")) {
|
||||||
|
unsigned int uintval;
|
||||||
|
|
||||||
|
if (!l_settings_get_uint(config, "General", "Channel",
|
||||||
|
&uintval) ||
|
||||||
|
!scan_channel_to_freq(uintval,
|
||||||
|
SCAN_BAND_2_4_GHZ)) {
|
||||||
|
l_error("AP Channel value unsupported");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->channel = uintval;
|
||||||
|
} else
|
||||||
|
/* TODO: Start a Get Survey to decide the channel */
|
||||||
|
ap->channel = 6;
|
||||||
|
|
||||||
|
strval = l_settings_get_string(config, "WSC", "DeviceName");
|
||||||
|
if (strval) {
|
||||||
|
len = strlen(strval);
|
||||||
|
|
||||||
|
if (len > 32) {
|
||||||
|
l_error("AP WSC name length outside the [1, 32] range");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!l_utf8_validate(strval, len, NULL)) {
|
||||||
|
l_error("AP WSC name doesn't validate as UTF-8");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(ap->wsc_name, strval);
|
||||||
|
l_free(l_steal_ptr(strval));
|
||||||
|
} else
|
||||||
|
memcpy(ap->wsc_name, ap->ssid, 33);
|
||||||
|
|
||||||
|
strval = l_settings_get_string(config, "WSC", "PrimaryDeviceType");
|
||||||
|
if (strval) {
|
||||||
|
bool ok = wsc_device_type_from_setting_str(strval,
|
||||||
|
&ap->wsc_primary_device_type);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
l_error("AP [WSC].PrimaryDeviceType format unknown");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Make ourselves a WFA standard PC by default */
|
||||||
|
ap->wsc_primary_device_type.category = 1;
|
||||||
|
memcpy(ap->wsc_primary_device_type.oui, wsc_wfa_oui, 3);
|
||||||
|
ap->wsc_primary_device_type.oui_type = 0x04;
|
||||||
|
ap->wsc_primary_device_type.subcategory = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_settings_get_value(config, "WSC", "AuthorizedMACs")) {
|
||||||
|
char **strvval;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
strvval = l_settings_get_string_list(config, "WSC",
|
||||||
|
"AuthorizedMACs", ',');
|
||||||
|
if (!strvval) {
|
||||||
|
l_error("AP Authorized MACs list format wrong");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->authorized_macs_num = l_strv_length(strvval);
|
||||||
|
ap->authorized_macs = l_malloc(ap->authorized_macs_num * 6);
|
||||||
|
|
||||||
|
for (i = 0; strvval[i]; i++)
|
||||||
|
if (!util_string_to_address(strvval[i],
|
||||||
|
ap->authorized_macs + i * 6)) {
|
||||||
|
l_error("Bad authorized MAC format: %s",
|
||||||
|
strvval[i]);
|
||||||
|
l_strfreev(strvval);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
l_strfreev(strvval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_settings_get_value(config, "General", "NoCCKRates")) {
|
||||||
|
bool boolval;
|
||||||
|
|
||||||
|
if (!l_settings_get_bool(config, "General", "NoCCKRates",
|
||||||
|
&boolval)) {
|
||||||
|
l_error("AP [General].NoCCKRates not a valid "
|
||||||
|
"boolean");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_cck_rates = !boolval;
|
||||||
|
} else
|
||||||
|
*out_cck_rates = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start a simple independent WPA2 AP on given netdev.
|
* Start a simple independent WPA2 AP on given netdev.
|
||||||
*
|
*
|
||||||
* @ops.handle_event is required and must react to AP_EVENT_START_FAILED
|
* @ops.handle_event is required and must react to AP_EVENT_START_FAILED
|
||||||
* and AP_EVENT_STOPPING by forgetting the ap_state struct, which is
|
* and AP_EVENT_STOPPING by forgetting the ap_state struct, which is
|
||||||
* going to be freed automatically.
|
* going to be freed automatically.
|
||||||
* In the @config struct the .ssid field is required and one of
|
* In the @config struct the [General].SSID key is required and one of
|
||||||
* .passphrase and .psk must be filled in. All other fields are optional.
|
* [Security].Passphrase and [Security].PreSharedKey must be filled in.
|
||||||
* If @ap_start succeeds, the returned ap_state takes ownership of
|
* All other fields are optional.
|
||||||
* @config and the caller shouldn't free it or any of the memory pointed
|
|
||||||
* to by its members (which also can't be static).
|
|
||||||
*/
|
*/
|
||||||
struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
|
struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
|
||||||
const struct ap_ops *ops, int *err_out,
|
const struct ap_ops *ops, int *err_out,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
@ -2742,57 +2858,37 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
|
|||||||
uint64_t wdev_id = netdev_get_wdev_id(netdev);
|
uint64_t wdev_id = netdev_get_wdev_id(netdev);
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
bool wait_on_address = false;
|
bool wait_on_address = false;
|
||||||
|
bool cck_rates = true;
|
||||||
|
|
||||||
if (err_out)
|
if (err_out)
|
||||||
*err_out = err;
|
*err_out = err;
|
||||||
|
|
||||||
if (L_WARN_ON(!config->ssid))
|
if (L_WARN_ON(!config))
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (L_WARN_ON(!config->profile && !config->passphrase[0] &&
|
|
||||||
l_memeqzero(config->psk, sizeof(config->psk))))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ap = l_new(struct ap_state, 1);
|
ap = l_new(struct ap_state, 1);
|
||||||
ap->nl80211 = l_genl_family_new(iwd_get_genl(), NL80211_GENL_NAME);
|
ap->nl80211 = l_genl_family_new(iwd_get_genl(), NL80211_GENL_NAME);
|
||||||
ap->config = config;
|
|
||||||
ap->netdev = netdev;
|
ap->netdev = netdev;
|
||||||
ap->ops = ops;
|
ap->ops = ops;
|
||||||
ap->user_data = user_data;
|
ap->user_data = user_data;
|
||||||
|
|
||||||
/*
|
err = ap_load_config(ap, config, &wait_on_address, &cck_rates);
|
||||||
* This both loads a profile if required and loads DHCP settings either
|
if (err)
|
||||||
* by the profile itself or the IP pool (or does nothing in the case
|
|
||||||
* of a profile-less configuration). wait_on_address will be set true
|
|
||||||
* if an address change is required.
|
|
||||||
*/
|
|
||||||
err = ap_load_profile_and_dhcp(ap, &wait_on_address);
|
|
||||||
if (err < 0)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!config->channel)
|
err = -EINVAL;
|
||||||
/* TODO: Start a Get Survey to decide the channel */
|
|
||||||
config->channel = 6;
|
|
||||||
|
|
||||||
if (!config->wsc_name)
|
|
||||||
config->wsc_name = l_strdup(config->ssid);
|
|
||||||
|
|
||||||
if (!config->wsc_primary_device_type.category) {
|
|
||||||
/* Make ourselves a WFA standard PC by default */
|
|
||||||
config->wsc_primary_device_type.category = 1;
|
|
||||||
memcpy(config->wsc_primary_device_type.oui, wsc_wfa_oui, 3);
|
|
||||||
config->wsc_primary_device_type.oui_type = 0x04;
|
|
||||||
config->wsc_primary_device_type.subcategory = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
||||||
ap->beacon_interval = 100;
|
ap->beacon_interval = 100;
|
||||||
|
|
||||||
|
wsc_uuid_from_addr(netdev_get_address(netdev), ap->wsc_uuid_r);
|
||||||
|
|
||||||
ap->rates = l_uintset_new(200);
|
ap->rates = l_uintset_new(200);
|
||||||
|
|
||||||
/* TODO: Pick from actual supported rates */
|
/* TODO: Pick from actual supported rates */
|
||||||
if (config->no_cck_rates) {
|
if (!cck_rates) {
|
||||||
l_uintset_put(ap->rates, 12); /* 6 Mbps*/
|
l_uintset_put(ap->rates, 12); /* 6 Mbps*/
|
||||||
l_uintset_put(ap->rates, 18); /* 9 Mbps*/
|
l_uintset_put(ap->rates, 18); /* 9 Mbps*/
|
||||||
l_uintset_put(ap->rates, 24); /* 12 Mbps*/
|
l_uintset_put(ap->rates, 24); /* 12 Mbps*/
|
||||||
@ -2807,15 +2903,6 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
|
|||||||
l_uintset_put(ap->rates, 22); /* 11 Mbps*/
|
l_uintset_put(ap->rates, 22); /* 11 Mbps*/
|
||||||
}
|
}
|
||||||
|
|
||||||
wsc_uuid_from_addr(netdev_get_address(netdev), ap->wsc_uuid_r);
|
|
||||||
|
|
||||||
if (config->passphrase[0] &&
|
|
||||||
crypto_psk_from_passphrase(config->passphrase,
|
|
||||||
(uint8_t *) config->ssid,
|
|
||||||
strlen(config->ssid),
|
|
||||||
config->psk) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_REQUEST << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_REQUEST << 4),
|
||||||
NULL, 0, ap_assoc_req_cb, ap, NULL))
|
NULL, 0, ap_assoc_req_cb, ap, NULL))
|
||||||
@ -2878,7 +2965,6 @@ error:
|
|||||||
if (err_out)
|
if (err_out)
|
||||||
*err_out = err;
|
*err_out = err;
|
||||||
|
|
||||||
ap->config = NULL;
|
|
||||||
ap_reset(ap);
|
ap_reset(ap);
|
||||||
l_genl_family_free(ap->nl80211);
|
l_genl_family_free(ap->nl80211);
|
||||||
l_free(ap);
|
l_free(ap);
|
||||||
@ -3128,7 +3214,7 @@ static struct l_dbus_message *ap_dbus_start(struct l_dbus *dbus,
|
|||||||
{
|
{
|
||||||
struct ap_if_data *ap_if = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
const char *ssid, *wpa2_passphrase;
|
const char *ssid, *wpa2_passphrase;
|
||||||
struct ap_config *config;
|
struct l_settings *config;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (ap_if->ap && ap_if->ap->started)
|
if (ap_if->ap && ap_if->ap->started)
|
||||||
@ -3141,16 +3227,17 @@ static struct l_dbus_message *ap_dbus_start(struct l_dbus *dbus,
|
|||||||
&ssid, &wpa2_passphrase))
|
&ssid, &wpa2_passphrase))
|
||||||
return dbus_error_invalid_args(message);
|
return dbus_error_invalid_args(message);
|
||||||
|
|
||||||
config = l_new(struct ap_config, 1);
|
config = l_settings_new();
|
||||||
config->ssid = l_strdup(ssid);
|
l_settings_set_string(config, "General", "SSID", ssid);
|
||||||
l_strlcpy(config->passphrase, wpa2_passphrase,
|
l_settings_set_string(config, "Security", "Passphrase",
|
||||||
sizeof(config->passphrase));
|
wpa2_passphrase);
|
||||||
|
l_settings_add_group(config, "IPv4");
|
||||||
|
|
||||||
ap_if->ap = ap_start(ap_if->netdev, config, &ap_dbus_ops, &err, ap_if);
|
ap_if->ap = ap_start(ap_if->netdev, config, &ap_dbus_ops, &err, ap_if);
|
||||||
if (!ap_if->ap) {
|
l_settings_free(config);
|
||||||
ap_config_free(config);
|
|
||||||
|
if (!ap_if->ap)
|
||||||
return dbus_error_from_errno(err, message);
|
return dbus_error_from_errno(err, message);
|
||||||
}
|
|
||||||
|
|
||||||
ap_if->pending = l_dbus_message_ref(message);
|
ap_if->pending = l_dbus_message_ref(message);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -3200,7 +3287,8 @@ static struct l_dbus_message *ap_dbus_start_profile(struct l_dbus *dbus,
|
|||||||
{
|
{
|
||||||
struct ap_if_data *ap_if = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
const char *ssid;
|
const char *ssid;
|
||||||
struct ap_config *config;
|
struct l_settings *config;
|
||||||
|
char *config_path;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (ap_if->ap && ap_if->ap->started)
|
if (ap_if->ap && ap_if->ap->started)
|
||||||
@ -3212,19 +3300,32 @@ static struct l_dbus_message *ap_dbus_start_profile(struct l_dbus *dbus,
|
|||||||
if (!l_dbus_message_get_arguments(message, "s", &ssid))
|
if (!l_dbus_message_get_arguments(message, "s", &ssid))
|
||||||
return dbus_error_invalid_args(message);
|
return dbus_error_invalid_args(message);
|
||||||
|
|
||||||
config = l_new(struct ap_config, 1);
|
config = l_settings_new();
|
||||||
config->ssid = l_strdup(ssid);
|
config_path = storage_get_path("ap/%s.ap", ssid);
|
||||||
/* This tells ap_start to pull settings from a profile on disk */
|
err = l_settings_load_from_file(config, config_path) ? 0 : -EIO;
|
||||||
config->profile = storage_get_path("ap/%s.ap", ssid);
|
l_free(config_path);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since [General].SSID is not an allowed setting for a profile on
|
||||||
|
* disk, we're free to potentially overwrite it with the SSID that
|
||||||
|
* the DBus user asked for.
|
||||||
|
*/
|
||||||
|
l_settings_set_string(config, "General", "SSID", ssid);
|
||||||
|
|
||||||
ap_if->ap = ap_start(ap_if->netdev, config, &ap_dbus_ops, &err, ap_if);
|
ap_if->ap = ap_start(ap_if->netdev, config, &ap_dbus_ops, &err, ap_if);
|
||||||
if (!ap_if->ap) {
|
l_settings_free(config);
|
||||||
ap_config_free(config);
|
|
||||||
return dbus_error_from_errno(err, message);
|
if (!ap_if->ap)
|
||||||
}
|
goto error;
|
||||||
|
|
||||||
ap_if->pending = l_dbus_message_ref(message);
|
ap_if->pending = l_dbus_message_ref(message);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return dbus_error_from_errno(err, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ap_dbus_property_get_started(struct l_dbus *dbus,
|
static bool ap_dbus_property_get_started(struct l_dbus *dbus,
|
||||||
@ -3247,11 +3348,11 @@ static bool ap_dbus_property_get_name(struct l_dbus *dbus,
|
|||||||
{
|
{
|
||||||
struct ap_if_data *ap_if = user_data;
|
struct ap_if_data *ap_if = user_data;
|
||||||
|
|
||||||
if (!ap_if->ap || !ap_if->ap->config || !ap_if->ap->started)
|
if (!ap_if->ap || !ap_if->ap->started)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
l_dbus_message_builder_append_basic(builder, 's',
|
l_dbus_message_builder_append_basic(builder, 's',
|
||||||
ap_if->ap->config->ssid);
|
ap_if->ap->ssid);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
19
src/ap.h
19
src/ap.h
@ -58,21 +58,6 @@ struct ap_event_registration_success_data {
|
|||||||
|
|
||||||
typedef void (*ap_stopped_func_t)(void *user_data);
|
typedef void (*ap_stopped_func_t)(void *user_data);
|
||||||
|
|
||||||
struct ap_config {
|
|
||||||
char *ssid;
|
|
||||||
char passphrase[64];
|
|
||||||
uint8_t psk[32];
|
|
||||||
uint8_t channel;
|
|
||||||
uint8_t *authorized_macs;
|
|
||||||
unsigned int authorized_macs_num;
|
|
||||||
char *wsc_name;
|
|
||||||
struct wsc_primary_device_type wsc_primary_device_type;
|
|
||||||
|
|
||||||
char *profile;
|
|
||||||
|
|
||||||
bool no_cck_rates : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ap_ops {
|
struct ap_ops {
|
||||||
void (*handle_event)(enum ap_event_type type, const void *event_data,
|
void (*handle_event)(enum ap_event_type type, const void *event_data,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
@ -100,9 +85,7 @@ struct ap_ops {
|
|||||||
uint8_t *out_buf, void *user_data);
|
uint8_t *out_buf, void *user_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
void ap_config_free(struct ap_config *config);
|
struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
|
||||||
|
|
||||||
struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
|
|
||||||
const struct ap_ops *ops, int *err,
|
const struct ap_ops *ops, int *err,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
void ap_shutdown(struct ap_state *ap, ap_stopped_func_t stopped_func,
|
void ap_shutdown(struct ap_state *ap, ap_stopped_func_t stopped_func,
|
||||||
|
51
src/p2p.c
51
src/p2p.c
@ -1187,13 +1187,32 @@ static const struct ap_ops p2p_go_ops = {
|
|||||||
|
|
||||||
static void p2p_group_start(struct p2p_device *dev)
|
static void p2p_group_start(struct p2p_device *dev)
|
||||||
{
|
{
|
||||||
struct ap_config *config = l_new(struct ap_config, 1);
|
struct l_settings *config = l_settings_new();
|
||||||
|
uint8_t psk[32];
|
||||||
|
char *macs[2] = {};
|
||||||
|
const struct wsc_primary_device_type *pdt =
|
||||||
|
&dev->device_info.primary_device_type;
|
||||||
|
uint64_t pdt_uint =
|
||||||
|
((uint64_t) pdt->category << 48) |
|
||||||
|
((uint64_t) pdt->oui[0] << 40) |
|
||||||
|
((uint64_t) pdt->oui[1] << 32) |
|
||||||
|
((uint64_t) pdt->oui[2] << 24) |
|
||||||
|
((uint64_t) pdt->oui_type << 16) |
|
||||||
|
pdt->subcategory;
|
||||||
|
|
||||||
config->ssid = l_strdup(dev->go_group_id.ssid);
|
l_settings_set_string(config, "General", "SSID", dev->go_group_id.ssid);
|
||||||
config->channel = dev->listen_channel;
|
l_settings_set_uint(config, "General", "Channel", dev->listen_channel);
|
||||||
config->wsc_name = l_strdup(dev->device_info.device_name);
|
l_settings_set_bool(config, "General", "NoCCKRates", true);
|
||||||
config->wsc_primary_device_type = dev->device_info.primary_device_type;
|
l_settings_set_string(config, "WSC", "DeviceName",
|
||||||
config->no_cck_rates = true;
|
dev->device_info.device_name);
|
||||||
|
l_settings_set_uint64(config, "WSC", "PrimaryDeviceType", pdt_uint);
|
||||||
|
/*
|
||||||
|
* Section 3.1.4.4: "It shall only allow association by the
|
||||||
|
* P2P Device that it is currently in Group Formation with."
|
||||||
|
*/
|
||||||
|
macs[0] = (char *) util_address_to_string(
|
||||||
|
dev->conn_peer_interface_addr);
|
||||||
|
l_settings_set_string_list(config, "WSC", "AuthorizedMACs", macs, ',');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Section 3.2.1: "The Credentials for a P2P Group issued to a
|
* Section 3.2.1: "The Credentials for a P2P Group issued to a
|
||||||
@ -1207,29 +1226,25 @@ static void p2p_group_start(struct p2p_device *dev)
|
|||||||
* it's a little costlier to generate for the same cryptographic
|
* it's a little costlier to generate for the same cryptographic
|
||||||
* strength as the PSK.
|
* strength as the PSK.
|
||||||
*/
|
*/
|
||||||
if (!l_getrandom(config->psk, 32)) {
|
if (!l_getrandom(psk, 32)) {
|
||||||
l_error("l_getrandom() failed");
|
l_error("l_getrandom() failed");
|
||||||
ap_config_free(config);
|
l_settings_free(config);
|
||||||
p2p_connect_failed(dev);
|
p2p_connect_failed(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
l_settings_set_bytes(config, "Security", "PreSharedKey", psk, 32);
|
||||||
* Section 3.1.4.4: "It shall only allow association by the
|
|
||||||
* P2P Device that it is currently in Group Formation with."
|
l_settings_add_group(config, "IPv4");
|
||||||
*/
|
|
||||||
config->authorized_macs = l_memdup(dev->conn_peer_interface_addr, 6);
|
|
||||||
config->authorized_macs_num = 1;
|
|
||||||
|
|
||||||
dev->capability.group_caps |= P2P_GROUP_CAP_GO;
|
dev->capability.group_caps |= P2P_GROUP_CAP_GO;
|
||||||
dev->capability.group_caps |= P2P_GROUP_CAP_GROUP_FORMATION;
|
dev->capability.group_caps |= P2P_GROUP_CAP_GROUP_FORMATION;
|
||||||
|
|
||||||
dev->group = ap_start(dev->conn_netdev, config, &p2p_go_ops, NULL, dev);
|
dev->group = ap_start(dev->conn_netdev, config, &p2p_go_ops, NULL, dev);
|
||||||
if (!dev->group) {
|
l_settings_free(config);
|
||||||
ap_config_free(config);
|
|
||||||
|
if (!dev->group)
|
||||||
p2p_connect_failed(dev);
|
p2p_connect_failed(dev);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void p2p_netconfig_event_handler(enum netconfig_event event,
|
static void p2p_netconfig_event_handler(enum netconfig_event event,
|
||||||
|
Loading…
Reference in New Issue
Block a user