Home | History | Annotate | Download | only in usr
      1 /*
      2  * Copyright (C) 2009 Joshua Oreman <oremanj (at) rwcr.net>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stdio.h>
     22 #include <console.h>
     23 #include <string.h>
     24 #include <errno.h>
     25 #include <gpxe/net80211.h>
     26 #include <gpxe/ethernet.h>
     27 #include <usr/ifmgmt.h>
     28 #include <usr/iwmgmt.h>
     29 #include <gpxe/errortab.h>
     30 
     31 /** @file
     32  *
     33  * Wireless network interface management
     34  *
     35  */
     36 
     37 /**
     38  * Print status of 802.11 device
     39  *
     40  * @v dev	802.11 device
     41  */
     42 void iwstat ( struct net80211_device *dev ) {
     43 
     44 	ifstat ( dev->netdev );
     45 
     46 	printf ( "  [802.11 ");
     47 	if ( dev->state & NET80211_ASSOCIATED ) {
     48 		printf ( "SSID '%s', ", dev->essid );
     49 	} else {
     50 		printf ( "not associated, " );
     51 	}
     52 	if ( dev->channel < dev->nr_channels && dev->rate < dev->nr_rates ) {
     53 		printf ( "Ch:%d Sig:%d", dev->channels[dev->channel].channel_nr,
     54 			 dev->last_signal );
     55 		switch ( dev->hw->signal_type ) {
     56 		case NET80211_SIGNAL_NONE:
     57 			printf ( "?" );
     58 			break;
     59 		case NET80211_SIGNAL_ARBITRARY:
     60 			printf ( "/%d", dev->hw->signal_max );
     61 			break;
     62 		case NET80211_SIGNAL_DB:
     63 			printf ( "/%d dB", dev->hw->signal_max );
     64 			break;
     65 		case NET80211_SIGNAL_DBM:
     66 			printf ( " dBm" );
     67 			break;
     68 		}
     69 		printf ( ", Qual:%d%% Rate:%d Mbps]\n",
     70 			 ( dev->rx_beacon_interval == 0 ? 0 :
     71 			   100 * dev->tx_beacon_interval /
     72 			   dev->rx_beacon_interval ),
     73 			 dev->rates[dev->rate] / 10 );
     74 	} else {
     75 		printf ( "antenna off]\n" );
     76 	}
     77 
     78 	if ( dev->state & NET80211_WORKING ) {
     79 		printf ( "  [associating" );
     80 		if ( dev->associating )
     81 			printf ( " to '%s'", dev->associating->essid );
     82 		printf ( "...]\n" );
     83 	}
     84 }
     85 
     86 /** Identifiers for 802.11 cryptography types, indexed by type number */
     87 static const char *crypto_types[] = {
     88 	[NET80211_CRYPT_NONE] = "Open",
     89 	[NET80211_CRYPT_WEP] = "WEP ",
     90 	[NET80211_CRYPT_TKIP] = "WPA ",
     91 	[NET80211_CRYPT_CCMP] = "WPA2",
     92 	[NET80211_CRYPT_UNKNOWN] = "UNK ",
     93 };
     94 
     95 /** Number of 802.11 cryptography types defined */
     96 #define NR_CRYPTO_TYPES ( sizeof ( crypto_types ) / sizeof ( crypto_types[0] ) )
     97 
     98 /** Identifiers for 802.11 authentication types, indexed by type number */
     99 static const char *auth_types[] = {
    100 	[NET80211_SECPROT_NONE] = "",
    101 	[NET80211_SECPROT_PSK] = "PSK",
    102 	[NET80211_SECPROT_EAP] = "802.1X",
    103 	[NET80211_SECPROT_UNKNOWN] = "UNK",
    104 };
    105 
    106 /** Number of 802.11 authentication types defined */
    107 #define NR_AUTH_TYPES ( sizeof ( auth_types ) / sizeof ( auth_types[0] ) )
    108 
    109 /**
    110  * Scan for wireless networks using 802.11 device
    111  *
    112  * @v dev	802.11 device
    113  * @v active	Whether to use active scanning
    114  *
    115  * The list of networks found will be printed in tabular format.
    116  *
    117  * This function is safe to call at all times, whether the 802.11
    118  * device is open or not, but if called while the auto-association
    119  * task is running it will return an error indication.
    120  */
    121 int iwlist ( struct net80211_device *dev ) {
    122 	struct net80211_probe_ctx *ctx;
    123 	struct list_head *networks;
    124 	struct net80211_wlan *wlan;
    125 	char ssid_buf[22];
    126 	int rc;
    127 	unsigned i;
    128 	int was_opened = dev->netdev->state & NETDEV_OPEN;
    129 	int was_channel = dev->channels[dev->channel].channel_nr;
    130 
    131 	if ( ! was_opened ) {
    132 		dev->state |= NET80211_NO_ASSOC;
    133 		rc = netdev_open ( dev->netdev );
    134 		if ( rc < 0 )
    135 			goto err;
    136 	}
    137 
    138 	if ( dev->state & NET80211_WORKING ) {
    139 		rc = -EINVAL;
    140 		goto err_close_netdev;
    141 	}
    142 
    143 	if ( ! was_opened ) {
    144 		rc = net80211_prepare_probe ( dev, dev->hw->bands, 0 );
    145 		if ( rc < 0 )
    146 			goto err_close_netdev;
    147 	}
    148 
    149 	ctx = net80211_probe_start ( dev, "", 0 );
    150 	if ( ! ctx ) {
    151 		rc = -ENOMEM;
    152 		goto err_close_netdev;
    153 	}
    154 
    155 	while ( ! ( rc = net80211_probe_step ( ctx ) ) ) {
    156 		step();
    157 	}
    158 
    159 	networks = net80211_probe_finish_all ( ctx );
    160 
    161 	if ( list_empty ( networks ) ) {
    162 		goto err_free_networks;
    163 	}
    164 
    165 	rc = 0;
    166 
    167 	printf ( "Networks on %s:\n\n", dev->netdev->name );
    168 
    169 	/* Output format:
    170 	 * 0         1         2         3         4         5         6
    171 	 * 0123456789012345678901234567890123456789012345678901234567890
    172 	 * [Sig] SSID                  BSSID              Ch  Crypt/Auth
    173 	 * -------------------------------------------------------------
    174 	 * [ 15] abcdefghijklmnopqrst> 00:00:00:00:00:00  11  Open
    175 	 *                                             ... or WPA   PSK etc.
    176 	 */
    177 
    178 	/* Quoting the dashes and spaces verbatim uses less code space
    179 	   than generating them programmatically. */
    180 	printf ( "[Sig] SSID                  BSSID              Ch  Crypt/Auth\n"
    181 		 "-------------------------------------------------------------\n" );
    182 
    183 	list_for_each_entry ( wlan, networks, list ) {
    184 
    185 		/* Format SSID into 22-character string, space-padded,
    186 		   with '>' indicating truncation */
    187 
    188 		snprintf ( ssid_buf, sizeof ( ssid_buf ), "%s", wlan->essid );
    189 		for ( i = strlen ( ssid_buf ); i < sizeof ( ssid_buf ) - 1;
    190 		      i++ )
    191 			ssid_buf[i] = ' ';
    192 		if ( ssid_buf[sizeof ( ssid_buf ) - 2] != ' ' )
    193 			ssid_buf[sizeof ( ssid_buf ) - 2] = '>';
    194 		ssid_buf[sizeof ( ssid_buf ) - 1] = 0;
    195 
    196 		/* Sanity check */
    197 		if ( wlan->crypto >= NR_CRYPTO_TYPES ||
    198 		     wlan->handshaking >= NR_AUTH_TYPES )
    199 			continue;
    200 
    201 		printf ( "[%3d] %s %s  %2d  %s  %s\n",
    202 			 wlan->signal < 0 ? 100 + wlan->signal : wlan->signal,
    203 			 ssid_buf, eth_ntoa ( wlan->bssid ), wlan->channel,
    204 			 crypto_types[wlan->crypto],
    205 			 auth_types[wlan->handshaking] );
    206 	}
    207 	printf ( "\n" );
    208 
    209  err_free_networks:
    210 	net80211_free_wlanlist ( networks );
    211 
    212  err_close_netdev:
    213 	if ( ! was_opened ) {
    214 		dev->state &= ~NET80211_NO_ASSOC;
    215 		netdev_close ( dev->netdev );
    216 	} else {
    217 		net80211_change_channel ( dev, was_channel );
    218 	}
    219 
    220 	if ( ! rc )
    221 		return 0;
    222 
    223  err:
    224 	printf ( "Scanning for networks on %s: %s\n",
    225 		 dev->netdev->name, strerror ( rc ) );
    226 	return rc;
    227 }
    228 
    229 
    230 /* Record error codes as though they come from the 802.11 stack */
    231 #undef ERRFILE
    232 #define ERRFILE ERRFILE_net80211
    233 
    234 /** Common 802.11 errors */
    235 struct errortab common_wireless_errors[] __errortab = {
    236 	{ EINVAL | EUNIQ_06, "Packet decryption error" },
    237 	{ ECONNRESET | EUNIQ_01, "Unspecified reason" },
    238 	{ ECONNRESET | EUNIQ_04, "Disassociated due to inactivity" },
    239 	{ ECONNRESET | EUNIQ_0F, "4-Way Handshake timeout" },
    240 	{ ECONNRESET | EUNIQ_17, "IEEE 802.1X authentication failed" },
    241 	{ ECONNREFUSED | EUNIQ_01, "Unspecified failure" },
    242 	{ ECONNREFUSED | EUNIQ_0C, "Association denied" },
    243 	{ ECONNREFUSED | EUNIQ_0D, "Authentication method not supported" },
    244 };
    245