diff options
author | Joshua Oreman <oremanj@rwcr.net> | 2009-08-07 20:17:50 -0700 |
---|---|---|
committer | Marty Connor <mdc@etherboot.org> | 2010-01-05 09:11:21 -0500 |
commit | 1327a787eb5c7e3563b23bf689455fa887f3e3ed (patch) | |
tree | a8539c43281d02302731152d04251e7afd2ca8ee | |
parent | dd8a3e2e706fff6af6872db9e52d9c62a26838cf (diff) | |
download | ipxe-1327a787eb5c7e3563b23bf689455fa887f3e3ed.tar.gz |
[iwmgmt] Add wireless management commands and text for common errors
Add commands `iwstat' (to list 802.11-specific status information for
802.11 devices) and `iwlist' (to scan for available networks and print
a list along with security information).
Signed-off-by: Marty Connor <mdc@etherboot.org>
-rw-r--r-- | src/config/config.c | 1 | ||||
-rw-r--r-- | src/config/config_net80211.c | 33 | ||||
-rw-r--r-- | src/config/general.h | 7 | ||||
-rw-r--r-- | src/hci/commands/iwmgmt_cmd.c | 69 | ||||
-rw-r--r-- | src/hci/wireless_errors.c | 118 | ||||
-rw-r--r-- | src/include/gpxe/errfile.h | 1 | ||||
-rw-r--r-- | src/include/usr/iwmgmt.h | 17 | ||||
-rw-r--r-- | src/usr/iwmgmt.c | 244 |
8 files changed, 490 insertions, 0 deletions
diff --git a/src/config/config.c b/src/config/config.c index 3c43dfbc5..f487ae975 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -204,6 +204,7 @@ REQUIRE_OBJECT ( config_cmd ); #ifdef IFMGMT_CMD REQUIRE_OBJECT ( ifmgmt_cmd ); #endif +/* IWMGMT_CMD is brought in by net80211.c if requested */ #ifdef ROUTE_CMD REQUIRE_OBJECT ( route_cmd ); #endif diff --git a/src/config/config_net80211.c b/src/config/config_net80211.c new file mode 100644 index 000000000..bcb76a747 --- /dev/null +++ b/src/config/config_net80211.c @@ -0,0 +1,33 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <config/general.h> + +/** @file + * + * 802.11 configuration options + * + */ + +/* + * Drag in 802.11-specific commands + * + */ +#ifdef IWMGMT_CMD +REQUIRE_OBJECT ( iwmgmt_cmd ); +#endif + +/* + * Drag in 802.11 error message tables + * + */ +#ifdef ERRMSG_80211 +REQUIRE_OBJECT ( wireless_errors ); +#endif + diff --git a/src/config/general.h b/src/config/general.h index ee07dfc09..0acc00d3d 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -99,6 +99,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define NVO_CMD /* Non-volatile option storage commands */ #define CONFIG_CMD /* Option configuration console */ #define IFMGMT_CMD /* Interface management commands */ +#define IWMGMT_CMD /* Wireless interface management commands */ #define ROUTE_CMD /* Routing table management commands */ #define IMAGE_CMD /* Image management commands */ #define DHCP_CMD /* DHCP management commands */ @@ -109,6 +110,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#undef PXE_CMD /* PXE commands */ /* + * Error message tables to include + * + */ +#undef ERRMSG_80211 /* All 802.11 error descriptions (~3.3kb) */ + +/* * Obscure configuration options * * You probably don't need to touch these. diff --git a/src/hci/commands/iwmgmt_cmd.c b/src/hci/commands/iwmgmt_cmd.c new file mode 100644 index 000000000..006c9f1df --- /dev/null +++ b/src/hci/commands/iwmgmt_cmd.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/netdevice.h> +#include <gpxe/net80211.h> +#include <gpxe/command.h> +#include <usr/iwmgmt.h> +#include <hci/ifmgmt_cmd.h> + +/* "iwstat" command */ + +static int iwstat_payload ( struct net_device *netdev ) { + struct net80211_device *dev = net80211_get ( netdev ); + + if ( dev ) + iwstat ( dev ); + + return 0; +} + +static int iwstat_exec ( int argc, char **argv ) { + return ifcommon_exec ( argc, argv, + iwstat_payload, "Display wireless status of" ); +} + +/* "iwlist" command */ + +static int iwlist_payload ( struct net_device *netdev ) { + struct net80211_device *dev = net80211_get ( netdev ); + + if ( dev ) + return iwlist ( dev ); + + return 0; +} + +static int iwlist_exec ( int argc, char **argv ) { + return ifcommon_exec ( argc, argv, iwlist_payload, + "List wireless networks available via" ); +} + +/** Wireless interface management commands */ +struct command iwmgmt_commands[] __command = { + { + .name = "iwstat", + .exec = iwstat_exec, + }, + { + .name = "iwlist", + .exec = iwlist_exec, + }, +}; diff --git a/src/hci/wireless_errors.c b/src/hci/wireless_errors.c new file mode 100644 index 000000000..46006f9e1 --- /dev/null +++ b/src/hci/wireless_errors.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <errno.h> +#include <gpxe/errortab.h> + +/* Record errors as though they come from the 802.11 stack */ +#undef ERRFILE +#define ERRFILE ERRFILE_net80211 + +/** All 802.11 errors + * + * These follow the 802.11 standard as much as is feasible, but most + * have been abbreviated to fit the 50-character limit imposed by + * strerror. + */ +struct errortab wireless_errors[] __errortab = { + /* gPXE 802.11 stack errors */ + { EINVAL | EUNIQ_01, "Packet too short" }, + { EINVAL | EUNIQ_02, "Packet 802.11 version not supported" }, + { EINVAL | EUNIQ_03, "Packet not a data packet" }, + { EINVAL | EUNIQ_04, "Packet not from an Access Point" }, + { EINVAL | EUNIQ_05, "Packet has invalid LLC header" }, + { EINVAL | EUNIQ_06, "Packet decryption error", }, + { EINVAL | EUNIQ_07, "Invalid active scan requested" }, + + /* 802.11 status codes (IEEE Std 802.11-2007, Table 7-23) */ + /* Maximum error length: 50 chars | */ + { ECONNREFUSED | EUNIQ_01, "Unspecified failure" }, + { ECONNREFUSED | EUNIQ_0A, "Cannot support all requested capabilities" }, + { ECONNREFUSED | EUNIQ_0B, "Reassociation denied due to lack of association" }, + { ECONNREFUSED | EUNIQ_0C, "Association denied for another reason" }, + { ECONNREFUSED | EUNIQ_0D, "Authentication algorithm unsupported" }, + { ECONNREFUSED | EUNIQ_0E, "Authentication sequence number unexpected" }, + { ECONNREFUSED | EUNIQ_0F, "Authentication rejected due to challenge failure" }, + { ECONNREFUSED | EUNIQ_10, "Authentication rejected due to timeout" }, + { ECONNREFUSED | EUNIQ_11, "Association denied because AP is out of resources" }, + { ECONNREFUSED | EUNIQ_12, "Association denied; basic rate support required" }, + { ECONNREFUSED | EUNIQ_13, "Association denied; short preamble support req'd" }, + { ECONNREFUSED | EUNIQ_14, "Association denied; PBCC modulation support req'd" }, + { ECONNREFUSED | EUNIQ_15, "Association denied; Channel Agility support req'd" }, + { ECONNREFUSED | EUNIQ_16, "Association denied; Spectrum Management required" }, + { ECONNREFUSED | EUNIQ_17, "Association denied; Power Capability unacceptable" }, + { ECONNREFUSED | EUNIQ_18, "Association denied; Supported Channels unacceptable" }, + { ECONNREFUSED | EUNIQ_19, "Association denied; Short Slot Tume support req'd" }, + { ECONNREFUSED | EUNIQ_1A, "Association denied; DSSS-OFDM support required" }, + { EHOSTUNREACH, "Unspecified, QoS-related failure" }, + { EHOSTUNREACH | EUNIQ_01, "Association denied; QoS AP out of QoS resources" }, + { EHOSTUNREACH | EUNIQ_02, "Association denied due to excessively poor link" }, + { EHOSTUNREACH | EUNIQ_03, "Association denied; QoS support required" }, + { EHOSTUNREACH | EUNIQ_05, "The request has been declined" }, + { EHOSTUNREACH | EUNIQ_06, "Request unsuccessful due to invalid parameters" }, + { EHOSTUNREACH | EUNIQ_07, "TS not created due to bad specification" }, + { EHOSTUNREACH | EUNIQ_08, "Invalid information element" }, + { EHOSTUNREACH | EUNIQ_09, "Invalid group cipher" }, + { EHOSTUNREACH | EUNIQ_0A, "Invalid pairwise cipher" }, + { EHOSTUNREACH | EUNIQ_0B, "Invalid AKMP" }, + { EHOSTUNREACH | EUNIQ_0C, "Unsupported RSN information element version" }, + { EHOSTUNREACH | EUNIQ_0D, "Invalid RSN information element capabilities" }, + { EHOSTUNREACH | EUNIQ_0E, "Cipher suite rejected because of security policy" }, + { EHOSTUNREACH | EUNIQ_0F, "TS not created due to insufficient delay" }, + { EHOSTUNREACH | EUNIQ_10, "Direct link is not allowed in the BSS by policy" }, + { EHOSTUNREACH | EUNIQ_11, "The Destination STA is not present within the BSS" }, + { EHOSTUNREACH | EUNIQ_12, "The Destination STA is not a QoS STA" }, + { EHOSTUNREACH | EUNIQ_13, "Association denied; Listen Interval is too large" }, + + /* 802.11 reason codes (IEEE Std 802.11-2007, Table 7-22) */ + /* Maximum error length: 50 chars | */ + { ECONNRESET | EUNIQ_01, "Unspecified reason" }, + { ECONNRESET | EUNIQ_02, "Previous authentication no longer valid" }, + { ECONNRESET | EUNIQ_03, "Deauthenticated due to leaving network" }, + { ECONNRESET | EUNIQ_04, "Disassociated due to inactivity" }, + { ECONNRESET | EUNIQ_05, "Disassociated because AP is out of resources" }, + { ECONNRESET | EUNIQ_06, "Class 2 frame received from nonauthenticated STA" }, + { ECONNRESET | EUNIQ_07, "Class 3 frame received from nonassociated STA" }, + { ECONNRESET | EUNIQ_08, "Disassociated due to roaming" }, + { ECONNRESET | EUNIQ_09, "STA requesting (re)association not authenticated" }, + { ECONNRESET | EUNIQ_0A, "Disassociated; Power Capability unacceptable" }, + { ECONNRESET | EUNIQ_0B, "Disassociated; Supported Channels unacceptable" }, + { ECONNRESET | EUNIQ_0D, "Invalid information element" }, + { ECONNRESET | EUNIQ_0E, "Message integrity code (MIC) failure" }, + { ECONNRESET | EUNIQ_0F, "4-Way Handshake timeout" }, + { ECONNRESET | EUNIQ_10, "Group Key Handshake timeout" }, + { ECONNRESET | EUNIQ_11, "4-Way Handshake information element changed unduly" }, + { ECONNRESET | EUNIQ_12, "Invalid group cipher" }, + { ECONNRESET | EUNIQ_13, "Invalid pairwise cipher" }, + { ECONNRESET | EUNIQ_14, "Invalid AKMP" }, + { ECONNRESET | EUNIQ_15, "Unsupported RSN information element version" }, + { ECONNRESET | EUNIQ_16, "Invalid RSN information element capabilities" }, + { ECONNRESET | EUNIQ_17, "IEEE 802.1X authentication failed" }, + { ECONNRESET | EUNIQ_18, "Cipher suite rejected because of security policy" }, + { ENETRESET, "Disassociated for unspecified, QoS-related reason" }, + { ENETRESET | EUNIQ_01, "Disassociated; QoS AP is out of QoS resources" }, + { ENETRESET | EUNIQ_02, "Disassociated due to excessively poor link" }, + { ENETRESET | EUNIQ_03, "Disassociated due to TXOP limit violation" }, + { ENETRESET | EUNIQ_04, "Requested; STA is leaving the BSS (or resetting)" }, + { ENETRESET | EUNIQ_05, "Requested; does not want to use the mechanism" }, + { ENETRESET | EUNIQ_06, "Requested; setup is required" }, + { ENETRESET | EUNIQ_07, "Requested from peer STA due to timeout" }, + { ENETRESET | EUNIQ_0D, "Peer STA does not support requested cipher suite" }, +}; diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h index 8d4545eb4..55dbb6f64 100644 --- a/src/include/gpxe/errfile.h +++ b/src/include/gpxe/errfile.h @@ -192,6 +192,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_x509 ( ERRFILE_OTHER | 0x00160000 ) #define ERRFILE_login_ui ( ERRFILE_OTHER | 0x00170000 ) #define ERRFILE_ib_srpboot ( ERRFILE_OTHER | 0x00180000 ) +#define ERRFILE_iwmgmt ( ERRFILE_OTHER | 0x00190000 ) /** @} */ diff --git a/src/include/usr/iwmgmt.h b/src/include/usr/iwmgmt.h new file mode 100644 index 000000000..c1bdc37a8 --- /dev/null +++ b/src/include/usr/iwmgmt.h @@ -0,0 +1,17 @@ +#ifndef _USR_IWMGMT_H +#define _USR_IWMGMT_H + +/** @file + * + * Wireless network interface management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +struct net80211_device; + +extern void iwstat ( struct net80211_device *dev ); +extern int iwlist ( struct net80211_device *dev ); + +#endif /* _USR_IWMGMT_H */ diff --git a/src/usr/iwmgmt.c b/src/usr/iwmgmt.c new file mode 100644 index 000000000..59ba103a1 --- /dev/null +++ b/src/usr/iwmgmt.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <console.h> +#include <string.h> +#include <errno.h> +#include <gpxe/net80211.h> +#include <gpxe/ethernet.h> +#include <usr/ifmgmt.h> +#include <usr/iwmgmt.h> +#include <gpxe/errortab.h> + +/** @file + * + * Wireless network interface management + * + */ + +/** + * Print status of 802.11 device + * + * @v dev 802.11 device + */ +void iwstat ( struct net80211_device *dev ) { + + ifstat ( dev->netdev ); + + printf ( " [802.11 "); + if ( dev->state & NET80211_ASSOCIATED ) { + printf ( "SSID '%s', ", dev->essid ); + } else { + printf ( "not associated, " ); + } + if ( dev->channel < dev->nr_channels && dev->rate < dev->nr_rates ) { + printf ( "Ch:%d Sig:%d", dev->channels[dev->channel].channel_nr, + dev->last_signal ); + switch ( dev->hw->signal_type ) { + case NET80211_SIGNAL_NONE: + printf ( "?" ); + break; + case NET80211_SIGNAL_ARBITRARY: + printf ( "/%d", dev->hw->signal_max ); + break; + case NET80211_SIGNAL_DB: + printf ( "/%d dB", dev->hw->signal_max ); + break; + case NET80211_SIGNAL_DBM: + printf ( " dBm" ); + break; + } + printf ( ", Qual:%d%% Rate:%d Mbps]\n", + ( dev->rx_beacon_interval == 0 ? 0 : + 100 * dev->tx_beacon_interval / + dev->rx_beacon_interval ), + dev->rates[dev->rate] / 10 ); + } else { + printf ( "antenna off]\n" ); + } + + if ( dev->state & NET80211_WORKING ) { + printf ( " [associating" ); + if ( dev->associating ) + printf ( " to '%s'", dev->associating->essid ); + printf ( "...]\n" ); + } +} + +/** Identifiers for 802.11 cryptography types, indexed by type number */ +static const char *crypto_types[] = { + [NET80211_CRYPT_NONE] = "Open", + [NET80211_CRYPT_WEP] = "WEP ", + [NET80211_CRYPT_TKIP] = "WPA ", + [NET80211_CRYPT_CCMP] = "WPA2", + [NET80211_CRYPT_UNKNOWN] = "UNK ", +}; + +/** Number of 802.11 cryptography types defined */ +#define NR_CRYPTO_TYPES ( sizeof ( crypto_types ) / sizeof ( crypto_types[0] ) ) + +/** Identifiers for 802.11 authentication types, indexed by type number */ +static const char *auth_types[] = { + [NET80211_SECPROT_NONE] = "", + [NET80211_SECPROT_PSK] = "PSK", + [NET80211_SECPROT_EAP] = "802.1X", + [NET80211_SECPROT_UNKNOWN] = "UNK", +}; + +/** Number of 802.11 authentication types defined */ +#define NR_AUTH_TYPES ( sizeof ( auth_types ) / sizeof ( auth_types[0] ) ) + +/** + * Scan for wireless networks using 802.11 device + * + * @v dev 802.11 device + * @v active Whether to use active scanning + * + * The list of networks found will be printed in tabular format. + * + * This function is safe to call at all times, whether the 802.11 + * device is open or not, but if called while the auto-association + * task is running it will return an error indication. + */ +int iwlist ( struct net80211_device *dev ) { + struct net80211_probe_ctx *ctx; + struct list_head *networks; + struct net80211_wlan *wlan; + char ssid_buf[22]; + int rc; + unsigned i; + int was_opened = dev->netdev->state & NETDEV_OPEN; + int was_channel = dev->channels[dev->channel].channel_nr; + + if ( ! was_opened ) { + dev->state |= NET80211_NO_ASSOC; + rc = netdev_open ( dev->netdev ); + if ( rc < 0 ) + goto err; + } + + if ( dev->state & NET80211_WORKING ) { + rc = -EINVAL; + goto err_close_netdev; + } + + if ( ! was_opened ) { + rc = net80211_prepare_probe ( dev, dev->hw->bands, 0 ); + if ( rc < 0 ) + goto err_close_netdev; + } + + ctx = net80211_probe_start ( dev, "", 0 ); + if ( ! ctx ) { + rc = -ENOMEM; + goto err_close_netdev; + } + + while ( ! ( rc = net80211_probe_step ( ctx ) ) ) { + step(); + } + + networks = net80211_probe_finish_all ( ctx ); + + if ( list_empty ( networks ) ) { + goto err_free_networks; + } + + rc = 0; + + printf ( "Networks on %s:\n\n", dev->netdev->name ); + + /* Output format: + * 0 1 2 3 4 5 6 + * 0123456789012345678901234567890123456789012345678901234567890 + * [Sig] SSID BSSID Ch Crypt/Auth + * ------------------------------------------------------------- + * [ 15] abcdefghijklmnopqrst> 00:00:00:00:00:00 11 Open + * ... or WPA PSK etc. + */ + + /* Quoting the dashes and spaces verbatim uses less code space + than generating them programmatically. */ + printf ( "[Sig] SSID BSSID Ch Crypt/Auth\n" + "-------------------------------------------------------------\n" ); + + list_for_each_entry ( wlan, networks, list ) { + + /* Format SSID into 22-character string, space-padded, + with '>' indicating truncation */ + + snprintf ( ssid_buf, sizeof ( ssid_buf ), "%s", wlan->essid ); + for ( i = strlen ( ssid_buf ); i < sizeof ( ssid_buf ) - 1; + i++ ) + ssid_buf[i] = ' '; + if ( ssid_buf[sizeof ( ssid_buf ) - 2] != ' ' ) + ssid_buf[sizeof ( ssid_buf ) - 2] = '>'; + ssid_buf[sizeof ( ssid_buf ) - 1] = 0; + + /* Sanity check */ + if ( wlan->crypto >= NR_CRYPTO_TYPES || + wlan->handshaking >= NR_AUTH_TYPES ) + continue; + + printf ( "[%3d] %s %s %2d %s %s\n", + wlan->signal < 0 ? 100 + wlan->signal : wlan->signal, + ssid_buf, eth_ntoa ( wlan->bssid ), wlan->channel, + crypto_types[wlan->crypto], + auth_types[wlan->handshaking] ); + } + printf ( "\n" ); + + err_free_networks: + net80211_free_wlanlist ( networks ); + + err_close_netdev: + if ( ! was_opened ) { + dev->state &= ~NET80211_NO_ASSOC; + netdev_close ( dev->netdev ); + } else { + net80211_change_channel ( dev, was_channel ); + } + + if ( ! rc ) + return 0; + + err: + printf ( "Scanning for networks on %s: %s\n", + dev->netdev->name, strerror ( rc ) ); + return rc; +} + + +/* Record error codes as though they come from the 802.11 stack */ +#undef ERRFILE +#define ERRFILE ERRFILE_net80211 + +/** Common 802.11 errors */ +struct errortab common_wireless_errors[] __errortab = { + { EINVAL | EUNIQ_06, "Packet decryption error" }, + { ECONNRESET | EUNIQ_01, "Unspecified reason" }, + { ECONNRESET | EUNIQ_04, "Disassociated due to inactivity" }, + { ECONNRESET | EUNIQ_0F, "4-Way Handshake timeout" }, + { ECONNRESET | EUNIQ_17, "IEEE 802.1X authentication failed" }, + { ECONNREFUSED | EUNIQ_01, "Unspecified failure" }, + { ECONNREFUSED | EUNIQ_0C, "Association denied" }, + { ECONNREFUSED | EUNIQ_0D, "Authentication method not supported" }, +}; |