Commit 5e3c51fa authored by Dan Williams's avatar Dan Williams

wifi/mesh: require WEXT 21 or later

Seriously, get a kernel more recent than 2007.  Really.
parent 9549c70d
......@@ -104,7 +104,6 @@ struct _NMDeviceOlpcMeshPrivate
gint8 num_freqs;
guint32 freqs[IW_MAX_FREQUENCIES];
guint8 we_version;
gboolean up;
NMDevice * companion;
......@@ -147,44 +146,7 @@ nm_olpc_mesh_error_get_type (void)
static guint32
real_get_generic_capabilities (NMDevice *dev)
{
int fd;
guint32 caps = NM_DEVICE_CAP_NONE;
struct iw_range range;
struct iwreq wrq;
const char *iface = nm_device_get_iface (dev);
/* Check for Wireless Extensions support >= 16 for wireless devices */
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
nm_log_warn (LOGD_OLPC_MESH, "couldn't open control socket.");
goto out;
}
memset (&wrq, 0, sizeof (struct iwreq));
memset (&range, 0, sizeof (struct iw_range));
strncpy (wrq.ifr_name, iface, IFNAMSIZ);
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof (struct iw_range);
if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) {
nm_log_warn (LOGD_OLPC_MESH, "couldn't get driver range information.");
goto out;
}
if ((wrq.u.data.length < 300) || (range.we_version_compiled < 16)) {
nm_log_warn (LOGD_OLPC_MESH,
"(%s): driver's Wireless Extensions version (%d) is too old.",
iface, range.we_version_compiled);
goto out;
} else {
caps |= NM_DEVICE_CAP_NM_SUPPORTED;
}
out:
if (fd >= 0)
close (fd);
return caps;
return NM_DEVICE_CAP_NM_SUPPORTED;
}
static void
......@@ -193,7 +155,6 @@ nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
priv->dispose_has_run = FALSE;
priv->we_version = 0;
priv->companion = NULL;
priv->stage1_waiting = FALSE;
......@@ -276,15 +237,24 @@ constructor (GType type,
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof (struct iw_range);
if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0)
if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) {
nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
nm_device_get_iface (NM_DEVICE (self)));
goto error;
}
if ((wrq.u.data.length < 300) || (range.we_version_compiled < 21)) {
nm_log_info (LOGD_HW | LOGD_WIFI,
"(%s): driver WEXT version too old (got %d, expected >= 21)",
nm_device_get_iface (NM_DEVICE (self)),
range.we_version_compiled);
goto error;
}
priv->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
for (i = 0; i < priv->num_freqs; i++)
priv->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
priv->we_version = range.we_version_compiled;
close (fd);
/* shorter timeout for mesh connectivity */
......@@ -531,7 +501,6 @@ nm_device_olpc_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
static void
nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
int sk;
struct iwreq wrq;
const char * iface;
......@@ -554,24 +523,10 @@ nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid)
memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len));
}
wrq.u.essid.pointer = (caddr_t) buf;
if (priv->we_version < 21) {
/* For historic reasons, set SSID length to include one extra
* character, C string nul termination, even though SSID is
* really an octet string that should not be presented as a C
* string. Some Linux drivers decrement the length by one and
* can thus end up missing the last octet of the SSID if the
* length is not incremented here. WE-21 changes this to
* explicitly require the length _not_ to include nul
* termination. */
if (len)
len++;
}
wrq.u.essid.length = len;
wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */
strncpy (wrq.ifr_name, iface, IFNAMSIZ);
if (ioctl (sk, SIOCSIWESSID, &wrq) < 0) {
if (errno != ENODEV) {
nm_log_err (LOGD_OLPC_MESH, "(%s): error setting SSID to '%s': %s",
......
......@@ -154,7 +154,6 @@ struct _NMDeviceWifiPrivate {
guint link_timeout_id;
/* Static options from driver */
guint8 we_version;
guint32 capabilities;
gboolean has_scan_capa_ssid;
};
......@@ -504,29 +503,14 @@ static guint32
real_get_generic_capabilities (NMDevice *dev)
{
int fd, err;
guint32 caps = NM_DEVICE_CAP_NONE, response_len = 0;
guint32 caps = NM_DEVICE_CAP_NONE;
struct iwreq wrq;
struct iw_range range;
const char *iface = nm_device_get_iface (dev);
gboolean success;
memset (&range, 0, sizeof (struct iw_range));
success = wireless_get_range (NM_DEVICE_WIFI (dev), &range, &response_len);
if (!success)
return NM_DEVICE_CAP_NONE;
/* Check for Wireless Extensions support >= 16 for wireless devices */
if ((response_len < 300) || (range.we_version_compiled < 16)) {
nm_log_err (LOGD_HW | LOGD_WIFI,
"(%s): driver's Wireless Extensions version (%d) is too old.",
iface, range.we_version_compiled);
return NM_DEVICE_CAP_NONE;
}
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
nm_log_err (LOGD_HW, "(%s): couldn't open control socket.", iface);
goto out;
return NM_DEVICE_CAP_NONE;
}
/* Cards that don't scan aren't supported */
......@@ -539,7 +523,6 @@ real_get_generic_capabilities (NMDevice *dev)
else
caps |= NM_DEVICE_CAP_NM_SUPPORTED;
out:
return caps;
}
......@@ -549,11 +532,8 @@ out:
NM_WIFI_DEVICE_CAP_RSN)
static guint32
get_wireless_capabilities (NMDeviceWifi *self,
iwrange * range,
guint32 data_len)
get_wireless_capabilities (NMDeviceWifi *self, iwrange *range)
{
guint32 minlen;
guint32 caps = NM_WIFI_DEVICE_CAP_NONE;
const char * iface;
......@@ -562,39 +542,35 @@ get_wireless_capabilities (NMDeviceWifi *self,
iface = nm_device_get_iface (NM_DEVICE (self));
minlen = ((char *) &range->enc_capa) - (char *) range + sizeof (range->enc_capa);
/* All drivers should support WEP by default */
caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104;
if ((data_len >= minlen) && range->we_version_compiled >= 18) {
if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP;
if (range->enc_capa & IW_ENC_CAPA_WPA)
caps |= NM_WIFI_DEVICE_CAP_WPA;
if (range->enc_capa & IW_ENC_CAPA_WPA)
caps |= NM_WIFI_DEVICE_CAP_WPA;
if (range->enc_capa & IW_ENC_CAPA_WPA2)
caps |= NM_WIFI_DEVICE_CAP_RSN;
if (range->enc_capa & IW_ENC_CAPA_WPA2)
caps |= NM_WIFI_DEVICE_CAP_RSN;
/* Check for cipher support but not WPA support */
if ( (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
&& !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) {
nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; "
"WPA unavailable.", iface);
caps &= ~WPA_CAPS;
}
/* Check for cipher support but not WPA support */
if ( (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
&& !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) {
nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; "
"WPA unavailable.", iface);
caps &= ~WPA_CAPS;
}
/* Check for WPA support but not cipher support */
if ( (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))
&& !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) {
nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; "
"WPA unavailable.", iface);
caps &= ~WPA_CAPS;
}
/* Check for WPA support but not cipher support */
if ( (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))
&& !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) {
nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; "
"WPA unavailable.", iface);
caps &= ~WPA_CAPS;
}
return caps;
......@@ -666,8 +642,19 @@ constructor (GType type,
memset (&range, 0, sizeof (struct iw_range));
success = wireless_get_range (NM_DEVICE_WIFI (object), &range, &response_len);
if (!success)
if (!success) {
nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
nm_device_get_iface (NM_DEVICE (self)));
goto error;
}
if ((response_len < 300) || (range.we_version_compiled < 21)) {
nm_log_info (LOGD_HW | LOGD_WIFI,
"(%s): driver WEXT version too old (got %d, expected >= 21)",
nm_device_get_iface (NM_DEVICE (self)),
range.we_version_compiled);
goto error;
}
priv->max_qual.qual = range.max_qual.qual;
priv->max_qual.level = range.max_qual.level;
......@@ -678,8 +665,6 @@ constructor (GType type,
for (i = 0; i < priv->num_freqs; i++)
priv->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
priv->we_version = range.we_version_compiled;
/* Check for the ability to scan specific SSIDs. Until the scan_capa
* field gets added to wireless-tools, need to work around that by casting
* to the custom structure.
......@@ -699,7 +684,7 @@ constructor (GType type,
}
/* 802.11 wireless-specific capabilities */
priv->capabilities = get_wireless_capabilities (self, &range, response_len);
priv->capabilities = get_wireless_capabilities (self, &range);
/* Connect to the supplicant manager */
priv->supplicant.mgr = nm_supplicant_manager_get ();
......@@ -1870,13 +1855,6 @@ nm_device_wifi_get_ssid (NMDeviceWifi *self)
len = wrq.u.essid.length;
if (!nm_utils_is_empty_ssid ((guint8 *) ssid, len)) {
/* Some drivers include nul termination in the SSID, so let's
* remove it here before further processing. WE-21 changes this
* to explicitly require the length _not_ to include nul
* termination. */
if (len > 0 && ssid[len - 1] == '\0' && priv->we_version < 21)
len--;
priv->ssid = g_byte_array_sized_new (len);
g_byte_array_append (priv->ssid, (const guint8 *) ssid, len);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment