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>
32 * Wireless network interface management
37 * Print status of 802.11 device
39 * @v dev 802.11 device
41 void iwstat ( struct net80211_device
*dev
) {
43 ifstat ( dev
->netdev
);
45 printf ( " [802.11 ");
46 if ( dev
->state
& NET80211_ASSOCIATED
) {
47 printf ( "SSID '%s', ", dev
->essid
);
49 printf ( "not associated, " );
51 if ( dev
->channel
< dev
->nr_channels
&& dev
->rate
< dev
->nr_rates
) {
52 printf ( "Ch:%d Sig:%d", dev
->channels
[dev
->channel
].channel_nr
,
54 switch ( dev
->hw
->signal_type
) {
55 case NET80211_SIGNAL_NONE
:
58 case NET80211_SIGNAL_ARBITRARY
:
59 printf ( "/%d", dev
->hw
->signal_max
);
61 case NET80211_SIGNAL_DB
:
62 printf ( "/%d dB", dev
->hw
->signal_max
);
64 case NET80211_SIGNAL_DBM
:
68 printf ( ", Qual:%d%% Rate:%d Mbps]\n",
69 ( dev
->rx_beacon_interval
== 0 ? 0 :
70 100 * dev
->tx_beacon_interval
/
71 dev
->rx_beacon_interval
),
72 dev
->rates
[dev
->rate
] / 10 );
74 printf ( "antenna off]\n" );
77 if ( dev
->state
& NET80211_WORKING
) {
78 printf ( " [associating" );
79 if ( dev
->associating
)
80 printf ( " to '%s'", dev
->associating
->essid
);
85 /** Identifiers for 802.11 cryptography types, indexed by type number */
86 static const char *crypto_types
[] = {
87 [NET80211_CRYPT_NONE
] = "Open",
88 [NET80211_CRYPT_WEP
] = "WEP ",
89 [NET80211_CRYPT_TKIP
] = "WPA ",
90 [NET80211_CRYPT_CCMP
] = "WPA2",
91 [NET80211_CRYPT_UNKNOWN
] = "UNK ",
94 /** Number of 802.11 cryptography types defined */
95 #define NR_CRYPTO_TYPES ( sizeof ( crypto_types ) / sizeof ( crypto_types[0] ) )
97 /** Identifiers for 802.11 authentication types, indexed by type number */
98 static const char *auth_types
[] = {
99 [NET80211_SECPROT_NONE
] = "",
100 [NET80211_SECPROT_PSK
] = "PSK",
101 [NET80211_SECPROT_EAP
] = "802.1X",
102 [NET80211_SECPROT_UNKNOWN
] = "UNK",
105 /** Number of 802.11 authentication types defined */
106 #define NR_AUTH_TYPES ( sizeof ( auth_types ) / sizeof ( auth_types[0] ) )
109 * Scan for wireless networks using 802.11 device
111 * @v dev 802.11 device
112 * @v active Whether to use active scanning
114 * The list of networks found will be printed in tabular format.
116 * This function is safe to call at all times, whether the 802.11
117 * device is open or not, but if called while the auto-association
118 * task is running it will return an error indication.
120 int iwlist ( struct net80211_device
*dev
) {
121 struct net80211_probe_ctx
*ctx
;
122 struct list_head
*networks
;
123 struct net80211_wlan
*wlan
;
127 int was_opened
= netdev_is_open ( dev
->netdev
);
128 int was_channel
= dev
->channels
[dev
->channel
].channel_nr
;
130 if ( ! was_opened
) {
131 dev
->state
|= NET80211_NO_ASSOC
;
132 rc
= netdev_open ( dev
->netdev
);
137 if ( dev
->state
& NET80211_WORKING
) {
139 goto err_close_netdev
;
142 if ( ! was_opened
) {
143 rc
= net80211_prepare_probe ( dev
, dev
->hw
->bands
, 0 );
145 goto err_close_netdev
;
148 ctx
= net80211_probe_start ( dev
, "", 0 );
151 goto err_close_netdev
;
154 while ( ! ( rc
= net80211_probe_step ( ctx
) ) ) {
158 networks
= net80211_probe_finish_all ( ctx
);
160 if ( list_empty ( networks
) ) {
161 goto err_free_networks
;
166 printf ( "Networks on %s:\n\n", dev
->netdev
->name
);
170 * 0123456789012345678901234567890123456789012345678901234567890
171 * [Sig] SSID BSSID Ch Crypt/Auth
172 * -------------------------------------------------------------
173 * [ 15] abcdefghijklmnopqrst> 00:00:00:00:00:00 11 Open
174 * ... or WPA PSK etc.
177 /* Quoting the dashes and spaces verbatim uses less code space
178 than generating them programmatically. */
179 printf ( "[Sig] SSID BSSID Ch Crypt/Auth\n"
180 "-------------------------------------------------------------\n" );
182 list_for_each_entry ( wlan
, networks
, list
) {
184 /* Format SSID into 22-character string, space-padded,
185 with '>' indicating truncation */
187 snprintf ( ssid_buf
, sizeof ( ssid_buf
), "%s", wlan
->essid
);
188 for ( i
= strlen ( ssid_buf
); i
< sizeof ( ssid_buf
) - 1;
191 if ( ssid_buf
[sizeof ( ssid_buf
) - 2] != ' ' )
192 ssid_buf
[sizeof ( ssid_buf
) - 2] = '>';
193 ssid_buf
[sizeof ( ssid_buf
) - 1] = 0;
196 if ( wlan
->crypto
>= NR_CRYPTO_TYPES
||
197 wlan
->handshaking
>= NR_AUTH_TYPES
)
200 printf ( "[%3d] %s %s %2d %s %s\n",
201 wlan
->signal
< 0 ? 100 + wlan
->signal
: wlan
->signal
,
202 ssid_buf
, eth_ntoa ( wlan
->bssid
), wlan
->channel
,
203 crypto_types
[wlan
->crypto
],
204 auth_types
[wlan
->handshaking
] );
209 net80211_free_wlanlist ( networks
);
212 if ( ! was_opened
) {
213 dev
->state
&= ~NET80211_NO_ASSOC
;
214 netdev_close ( dev
->netdev
);
216 net80211_change_channel ( dev
, was_channel
);
223 printf ( "Scanning for networks on %s: %s\n",
224 dev
->netdev
->name
, strerror ( rc
) );