From d18f52498493a51706e53ba12d27fe0790ddc8d0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 23 May 2013 11:08:27 -0500 Subject: [PATCH] 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. --- configure.ac | 20 ++++++++++++++++++++ src/wifi/wifi-utils-nl80211.c | 33 +++++++++++++++++++++++++++++++++ src/wifi/wifi-utils-private.h | 2 ++ src/wifi/wifi-utils.c | 9 +++++++++ src/wifi/wifi-utils.h | 2 ++ 5 files changed, 66 insertions(+) diff --git a/configure.ac b/configure.ac index 87126f20d1..aa075ba396 100644 --- a/configure.ac +++ b/configure.ac @@ -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 + #include + #include + #include ]], + [[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 diff --git a/src/wifi/wifi-utils-nl80211.c b/src/wifi/wifi-utils-nl80211.c index eb2534a22c..610ed93780 100644 --- a/src/wifi/wifi-utils-nl80211.c +++ b/src/wifi/wifi-utils-nl80211.c @@ -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 (); diff --git a/src/wifi/wifi-utils-private.h b/src/wifi/wifi-utils-private.h index 370f4fc0fd..769e25298e 100644 --- a/src/wifi/wifi-utils-private.h +++ b/src/wifi/wifi-utils-private.h @@ -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); diff --git a/src/wifi/wifi-utils.c b/src/wifi/wifi-utils.c index b93cd40ea2..ed7917e2b6 100644 --- a/src/wifi/wifi-utils.c +++ b/src/wifi/wifi-utils.c @@ -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; +} + diff --git a/src/wifi/wifi-utils.h b/src/wifi/wifi-utils.h index b917ef2f9d..a3d3e9aaeb 100644 --- a/src/wifi/wifi-utils.h +++ b/src/wifi/wifi-utils.h @@ -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 */