2 * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>.
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.
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.
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.
19 FILE_LICENCE ( GPL2_OR_LATER
);
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>
33 * Wireless network interface management
38 * Print status of 802.11 device
40 * @v dev 802.11 device
42 void iwstat ( struct net80211_device
*dev
) {
44 ifstat ( dev
->netdev
);
46 printf ( " [802.11 ");
47 if ( dev
->state
& NET80211_ASSOCIATED
) {
48 printf ( "SSID '%s', ", dev
->essid
);
50 printf ( "not associated, " );
52 if ( dev
->channel
< dev
->nr_channels
&& dev
->rate
< dev
->nr_rates
) {
53 printf ( "Ch:%d Sig:%d", dev
->channels
[dev
->channel
].channel_nr
,
55 switch ( dev
->hw
->signal_type
) {
56 case NET80211_SIGNAL_NONE
:
59 case NET80211_SIGNAL_ARBITRARY
:
60 printf ( "/%d", dev
->hw
->signal_max
);
62 case NET80211_SIGNAL_DB
:
63 printf ( "/%d dB", dev
->hw
->signal_max
);
65 case NET80211_SIGNAL_DBM
:
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 );
75 printf ( "antenna off]\n" );
78 if ( dev
->state
& NET80211_WORKING
) {
79 printf ( " [associating" );
80 if ( dev
->associating
)
81 printf ( " to '%s'", dev
->associating
->essid
);
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 ",
95 /** Number of 802.11 cryptography types defined */
96 #define NR_CRYPTO_TYPES ( sizeof ( crypto_types ) / sizeof ( crypto_types[0] ) )
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",
106 /** Number of 802.11 authentication types defined */
107 #define NR_AUTH_TYPES ( sizeof ( auth_types ) / sizeof ( auth_types[0] ) )
110 * Scan for wireless networks using 802.11 device
112 * @v dev 802.11 device
113 * @v active Whether to use active scanning
115 * The list of networks found will be printed in tabular format.
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.
121 int iwlist ( struct net80211_device
*dev
) {
122 struct net80211_probe_ctx
*ctx
;
123 struct list_head
*networks
;
124 struct net80211_wlan
*wlan
;
128 int was_opened
= dev
->netdev
->state
& NETDEV_OPEN
;
129 int was_channel
= dev
->channels
[dev
->channel
].channel_nr
;
131 if ( ! was_opened
) {
132 dev
->state
|= NET80211_NO_ASSOC
;
133 rc
= netdev_open ( dev
->netdev
);
138 if ( dev
->state
& NET80211_WORKING
) {
140 goto err_close_netdev
;
143 if ( ! was_opened
) {
144 rc
= net80211_prepare_probe ( dev
, dev
->hw
->bands
, 0 );
146 goto err_close_netdev
;
149 ctx
= net80211_probe_start ( dev
, "", 0 );
152 goto err_close_netdev
;
155 while ( ! ( rc
= net80211_probe_step ( ctx
) ) ) {
159 networks
= net80211_probe_finish_all ( ctx
);
161 if ( list_empty ( networks
) ) {
162 goto err_free_networks
;
167 printf ( "Networks on %s:\n\n", dev
->netdev
->name
);
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.
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" );
183 list_for_each_entry ( wlan
, networks
, list
) {
185 /* Format SSID into 22-character string, space-padded,
186 with '>' indicating truncation */
188 snprintf ( ssid_buf
, sizeof ( ssid_buf
), "%s", wlan
->essid
);
189 for ( i
= strlen ( ssid_buf
); i
< sizeof ( ssid_buf
) - 1;
192 if ( ssid_buf
[sizeof ( ssid_buf
) - 2] != ' ' )
193 ssid_buf
[sizeof ( ssid_buf
) - 2] = '>';
194 ssid_buf
[sizeof ( ssid_buf
) - 1] = 0;
197 if ( wlan
->crypto
>= NR_CRYPTO_TYPES
||
198 wlan
->handshaking
>= NR_AUTH_TYPES
)
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
] );
210 net80211_free_wlanlist ( networks
);
213 if ( ! was_opened
) {
214 dev
->state
&= ~NET80211_NO_ASSOC
;
215 netdev_close ( dev
->netdev
);
217 net80211_change_channel ( dev
, was_channel
);
224 printf ( "Scanning for networks on %s: %s\n",
225 dev
->netdev
->name
, strerror ( rc
) );
230 /* Record error codes as though they come from the 802.11 stack */
232 #define ERRFILE ERRFILE_net80211
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" },