wifi: add nl80211 Critical Protocol indication support

At critical times during the connection process, especially during
DHCP and EAPOL, the driver can increase the reliability of communication
in an attempt to increase the possibility of success.  This could be
done by suppressing bluetooth for a short period, or locking in a low
(and thus more reliable) bitrate, or enforcing some other interference
protection.  The 3.10 kernel added nl80211 support for this, so lets
use it if we can.
This commit is contained in:
Dan Williams 2013-05-23 11:08:27 -05:00
parent 07edeabbc3
commit d18f524984
5 changed files with 66 additions and 0 deletions

View file

@ -175,6 +175,26 @@ if test "$ac_have_nl80211" = no; then
AC_MSG_ERROR(Linux kernel development header linux/nl80211.h not installed or not functional)
fi
AC_MSG_CHECKING([Linux kernel nl80211 Critical Protocol Start/Stop])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#ifndef __user
#define __user
#endif
#include <sys/types.h>
#include <linux/types.h>
#include <sys/socket.h>
#include <linux/nl80211.h>]],
[[unsigned int a = NL80211_CMD_CRIT_PROTOCOL_START; a++;]])],
[ac_have_nl80211_critproto=yes],
[ac_have_nl80211_critproto=no])
AC_MSG_RESULT($ac_have_nl80211_critproto)
if test "$ac_have_nl80211_critproto" = yes; then
AC_DEFINE(HAVE_NL80211_CRITICAL_PROTOCOL_CMDS, 1, [Define if nl80211 has critical protocol support])
else
AC_DEFINE(HAVE_NL80211_CRITICAL_PROTOCOL_CMDS, 0, [Define if nl80211 has critical protocol support])
fi
dnl
dnl Default to using WEXT but allow it to be disabled
dnl

View file

@ -555,6 +555,36 @@ wifi_nl80211_get_qual (WifiData *data)
return sta_info.signal;
}
#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS
static gboolean
wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running)
{
WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
struct nl_msg *msg;
int err;
msg = nl80211_alloc_msg (nl80211,
running ? NL80211_CMD_CRIT_PROTOCOL_START :
NL80211_CMD_CRIT_PROTOCOL_STOP,
0);
/* Despite the DHCP name, we're using this for any type of IP addressing,
* DHCPv4, DHCPv6, and IPv6 SLAAC.
*/
NLA_PUT_U16 (msg, NL80211_ATTR_CRIT_PROT_ID, NL80211_CRIT_PROTO_DHCP);
if (running) {
/* Give DHCP 5 seconds to complete */
NLA_PUT_U16 (msg, NL80211_ATTR_MAX_CRIT_PROT_DURATION, 5000);
}
err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
return err ? FALSE : TRUE;
nla_put_failure:
nlmsg_free (msg);
return FALSE;
}
#endif
struct nl80211_device_info {
guint32 *freqs;
int num_freqs;
@ -742,6 +772,9 @@ wifi_nl80211_init (const char *iface, int ifindex)
nl80211->parent.get_bssid = wifi_nl80211_get_bssid;
nl80211->parent.get_rate = wifi_nl80211_get_rate;
nl80211->parent.get_qual = wifi_nl80211_get_qual;
#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS
nl80211->parent.indicate_addressing_running = wifi_nl80211_indicate_addressing_running;
#endif
nl80211->parent.deinit = wifi_nl80211_deinit;
nl80211->nl_sock = nl_socket_alloc ();

View file

@ -65,6 +65,8 @@ struct WifiData {
/* ssid == NULL means "auto SSID" */
gboolean (*set_mesh_ssid) (WifiData *data, const GByteArray *ssid);
gboolean (*indicate_addressing_running) (WifiData *data, gboolean running);
};
gpointer wifi_data_new (const char *iface, int ifindex, gsize len);

View file

@ -205,3 +205,12 @@ wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid)
return data->set_mesh_ssid (data, ssid);
}
gboolean
wifi_utils_indicate_addressing_running (WifiData *data, gboolean running)
{
g_return_val_if_fail (data != NULL, FALSE);
if (data->indicate_addressing_running)
return data->indicate_addressing_running (data, running);
return FALSE;
}

View file

@ -67,4 +67,6 @@ gboolean wifi_utils_set_mesh_channel (WifiData *data, guint32 channel);
gboolean wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid);
gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running);
#endif /* WIFI_UTILS_H */