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 */