---
scan.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 150 insertions(+), 6 deletions(-)
diff --git a/scan.c b/scan.c
index 91e94ed..d383243 100644
--- a/scan.c
+++ b/scan.c
@@ -13,6 +13,9 @@
#include "nl80211.h"
#include "iw.h"
+static unsigned char vendor_oui[3] = { 0x00, 0x50, 0xf2 };
+static unsigned char cipher_oui[3] = { 0x00, 0x0f, 0xac };
+
struct scan_params {
bool unknown;
};
@@ -41,6 +44,14 @@ COMMAND(scan, trigger, NULL,
typedef void (*printfn)(unsigned char type, unsigned char len, unsigned char *data);
+static void tab_on_first(bool *first)
+{
+ if (!*first)
+ printf("\t");
+ else
+ *first = false;
+}
+
static void print_ssid(unsigned char type, unsigned char len, unsigned char *data)
{
int i;
@@ -80,20 +91,152 @@ static void print_ign(unsigned char type, unsigned char len, unsigned char *data
/* ignore for now, not too useful */
}
+static void print_cipher(const unsigned char *oui, unsigned char *data)
+{
+ if (memcmp(data, oui, 3) == 0) {
+ switch (data[3]) {
+ case 0x00:
+ printf("Use group cipher suite");
+ break;
+ case 0x01:
+ printf("WEP-40");
+ break;
+ case 0x02:
+ printf("TKIP");
+ break;
+ case 0x04:
+ printf("CCMP");
+ break;
+ case 0x05:
+ printf("WEP-104");
+ break;
+ default:
+ printf("Reserved (%.02x)", data[3]);
+ break;
+ }
+ } else if (memcmp(data, vendor_oui, 3) == 0)
+ printf("Vendor specific (%.02x)", data[3]);
+ else
+ printf("Other");
+}
+
+static void print_auth(const unsigned char *oui, unsigned char *data)
+{
+ if (memcmp(data, oui, 3) == 0) {
+ switch (data[3]) {
+ case 0x01:
+ printf("802.1x");
+ break;
+ case 0x02:
+ printf("PSK");
+ break;
+ default:
+ printf("Reserved (%.02x)", data[3]);
+ break;
+ }
+ } else if (memcmp(data, vendor_oui, 3) == 0)
+ printf("Vendor specific (%.02x)", data[3]);
+ else
+ printf("Other");
+}
+
+static void print_wpa(const char *ie, const unsigned char *oui,
+ unsigned char len, unsigned char *data)
+{
+ bool first = true;
+ __u16 version, count, capa;
+ int i;
+
+ printf("\t%s:", ie);
+
+ if (len < 2) {
+ printf(" <too short> data:");
+ for(i = 0; i < len; i++)
+ printf(" %.02x", data[i]);
+ printf("\n");
+ return;
+ }
+
+ version = data[0] + (data[1] << 8);
+ tab_on_first(&first);
+ printf("\t * Version: %d\n", version);
+
+ data += 2;
+ len -= 2;
+
+ if (len < 4) {
+ tab_on_first(&first);
+ printf("\t * Group cipher: TKIP\n");
+ printf("\t * Pairwise ciphers: TKIP\n");
+ return;
+ }
+
+ tab_on_first(&first);
+ printf("\t * Group cipher: ");
+ print_cipher(oui, data);
+ printf("\n");
+
+ data += 4;
+ len -= 4;
+
+ if (len < 2) {
+ tab_on_first(&first);
+ printf("\t * Pairwise ciphers: TKIP\n");
+ return;
+ }
+
+ count = data[0] | (data[1] << 8);
+ tab_on_first(&first);
+ printf("\t * Pairwise ciphers:");
+ for (i=0; i<count; i++) {
+ printf(" ");
+ print_cipher(oui, data + 2 + (i * 4));
+ }
+ printf("\n");
+
+ data += 2 + (count * 4);
+ len -= 2 + (count * 4);
+
+ if (len < 2)
+ return;
+
+ count = data[0] | (data[1] << 8);
+ tab_on_first(&first);
+ printf("\t * Authentication suites:");
+ for (i=0; i<count; i++) {
+ printf(" ");
+ print_auth(oui, data + 2 + (i * 4));
+ }
+ printf("\n");
+
+ data += 2 + (count * 4);
+ len -= 2 + (count * 4);
+
+ if (len < 2)
+ return;
+
+ capa = data[0] | (data[1] << 8);
+ tab_on_first(&first);
+ printf("\t * Capabilities: 0x%.4x\n", capa);
+}
+
+static void print_rsn(unsigned char type, unsigned char len, unsigned char *data)
+{
+ print_wpa("WPA2", cipher_oui, len, data);
+}
+
static const printfn ieprinters[] = {
[0] = print_ssid,
[1] = print_supprates,
[3] = print_ds,
[5] = print_ign,
+ [48] = print_rsn,
[50] = print_supprates,
};
-static void tab_on_first(bool *first)
+static void print_wifi_wpa(unsigned char type, unsigned char len, unsigned char *data)
{
- if (!*first)
- printf("\t");
- else
- *first = false;
+ print_wpa("WPA", vendor_oui, len, data);
}
static void print_wifi_wps(unsigned char type, unsigned char len, unsigned char *data)
@@ -177,6 +320,7 @@ static void print_wifi_wps(unsigned char type, unsigned char len, unsigned char
}
static const printfn wifiprinters[] = {
+ [1] = print_wifi_wpa,
[4] = print_wifi_wps,
};
@@ -193,7 +337,7 @@ static void print_vendor(unsigned char len, unsigned char *data,
return;
}
- if (len >= 4 && data[0] == 0x00 && data[1] == 0x50 && data[2] == 0xF2) {
+ if (len >= 4 && memcmp(data, vendor_oui, 3) == 0) {
if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]])
return wifiprinters[data[3]](data[3], len - 4, data + 4);
if (!params->unknown)
--
1.6.0.6
On Mon, May 04, 2009 at 01:53:24AM -0700, Marcel Holtmann wrote:
> we can add them later. I just wanna have basic support for parsing the
> WPA IE. However can you point me to download links for the specs. I get
> easily lost in the amount of WiFi/802.11 specs.
IEEE 802.11r-2008 is available through the GetIEEE 802 Program
(http://standards.ieee.org/getieee802/802.11.html), but IEEE 802.11w
drafts are not yet publicly available (i.e., only for IEEE 802.11 WG
members at this point). Anyway, as far as the RSN IE assigned values are
concerned, you can get the latest information from the IEEE 802.11 ANA
database:
https://mentor.ieee.org/802.11/dcn/09/11-09-0031-04-0000-ana-database-assigned-number-authority.xls
(the 7.3.2.25.* tabs are for RSN IE)
--
Jouni Malinen PGP id EFC895FA
On Sun, 2009-05-03 at 21:46 -0700, Marcel Holtmann wrote:
>
> +static unsigned char vendor_oui[3] = { 0x00, 0x50, 0xf2 };
> +static unsigned char cipher_oui[3] = { 0x00, 0x0f, 0xac };
??
00-50-f2 is "WiFi OUI" (registered to Microsoft), 00-0f-ac is "802.11
OUI", registered to 802.11.
> +static void print_cipher(const unsigned char *oui, unsigned char *data)
> +{
Why are you passing in the OUI?
> + if (memcmp(data, oui, 3) == 0) {
> + switch (data[3]) {
> + case 0x00:
> + printf("Use group cipher suite");
> + break;
> + case 0x01:
> + printf("WEP-40");
> + break;
> + case 0x02:
> + printf("TKIP");
> + break;
> + case 0x04:
> + printf("CCMP");
> + break;
> + case 0x05:
> + printf("WEP-104");
> + break;
> + default:
> + printf("Reserved (%.02x)", data[3]);
> + break;
> + }
> + } else if (memcmp(data, vendor_oui, 3) == 0)
> + printf("Vendor specific (%.02x)", data[3]);
> + else
> + printf("Other");
That's wrong, if it matches the "vendor_oui" which you should rename to
"oui_wifi" or something then it's not "Vendor specific", then it's from
WiFi, if it doesn't match then you could print out the OUI of the vendor
it belongs to.
> +static void print_auth(const unsigned char *oui, unsigned char *data)
same here
> +static void print_wpa(const char *ie, const unsigned char *oui,
> + unsigned char len, unsigned char *data)
again, no need to pass in the OUI.
> + bool first = true;
> + __u16 version, count, capa;
> + int i;
> +
> + printf("\t%s:", ie);
> +
> + if (len < 2) {
> + printf(" <too short> data:");
> + for(i = 0; i < len; i++)
> + printf(" %.02x", data[i]);
> + printf("\n");
> + return;
> + }
> +
> + version = data[0] + (data[1] << 8);
> + tab_on_first(&first);
> + printf("\t * Version: %d\n", version);
> +
> + data += 2;
> + len -= 2;
> +
> + if (len < 4) {
> + tab_on_first(&first);
> + printf("\t * Group cipher: TKIP\n");
> + printf("\t * Pairwise ciphers: TKIP\n");
> + return;
> + }
Huh? I don't quite understand this? Is that some backward compat code?
Or is this some WPA1 thing I don't know about?
> +static void print_rsn(unsigned char type, unsigned char len, unsigned char *data)
> +{
> + print_wpa("WPA2", cipher_oui, len, data);
> +}
That's "oui_80211" I guess, not "cipher_oui". Ok I see now why you want
to pass in the OUI... However, it would be better to just duplicate the
code, I think for example 11w won't be announced in WPA1 IEs so we
shouldn't parse it there when we add support for parsing it to RSN IEs.
johannes
Hi Johannes,
> > +static unsigned char vendor_oui[3] = { 0x00, 0x50, 0xf2 };
> > +static unsigned char cipher_oui[3] = { 0x00, 0x0f, 0xac };
>
> ??
> 00-50-f2 is "WiFi OUI" (registered to Microsoft), 00-0f-ac is "802.11
> OUI", registered to 802.11.
I can rename them if that helps.
> > +static void print_cipher(const unsigned char *oui, unsigned char *data)
> > +{
>
> Why are you passing in the OUI?
The WPA1 and WPA2 IE are uses a different OUI for basically exactly the
same thing.
> > + if (memcmp(data, oui, 3) == 0) {
> > + switch (data[3]) {
> > + case 0x00:
> > + printf("Use group cipher suite");
> > + break;
> > + case 0x01:
> > + printf("WEP-40");
> > + break;
> > + case 0x02:
> > + printf("TKIP");
> > + break;
> > + case 0x04:
> > + printf("CCMP");
> > + break;
> > + case 0x05:
> > + printf("WEP-104");
> > + break;
> > + default:
> > + printf("Reserved (%.02x)", data[3]);
> > + break;
> > + }
> > + } else if (memcmp(data, vendor_oui, 3) == 0)
> > + printf("Vendor specific (%.02x)", data[3]);
> > + else
> > + printf("Other");
>
> That's wrong, if it matches the "vendor_oui" which you should rename to
> "oui_wifi" or something then it's not "Vendor specific", then it's from
> WiFi, if it doesn't match then you could print out the OUI of the vendor
> it belongs to.
I can just update the print_cipher to handle wifi_oui and 80211_oui with
the same details. Would that be good enough. Than we also don't need the
OUI passing here.
> > +static void print_auth(const unsigned char *oui, unsigned char *data)
>
> same here
>
> > +static void print_wpa(const char *ie, const unsigned char *oui,
> > + unsigned char len, unsigned char *data)
>
> again, no need to pass in the OUI.
>
> > + bool first = true;
> > + __u16 version, count, capa;
> > + int i;
> > +
> > + printf("\t%s:", ie);
> > +
> > + if (len < 2) {
> > + printf(" <too short> data:");
> > + for(i = 0; i < len; i++)
> > + printf(" %.02x", data[i]);
> > + printf("\n");
> > + return;
> > + }
> > +
> > + version = data[0] + (data[1] << 8);
> > + tab_on_first(&first);
> > + printf("\t * Version: %d\n", version);
> > +
> > + data += 2;
> > + len -= 2;
> > +
> > + if (len < 4) {
> > + tab_on_first(&first);
> > + printf("\t * Group cipher: TKIP\n");
> > + printf("\t * Pairwise ciphers: TKIP\n");
> > + return;
> > + }
>
> Huh? I don't quite understand this? Is that some backward compat code?
> Or is this some WPA1 thing I don't know about?
The specification says that the only mandatory field is the version and
after that everything else is optional and falls back to default
TKIP/TKIP. At least that is what I read of it.
> > +static void print_rsn(unsigned char type, unsigned char len, unsigned char *data)
> > +{
> > + print_wpa("WPA2", cipher_oui, len, data);
> > +}
>
> That's "oui_80211" I guess, not "cipher_oui". Ok I see now why you want
> to pass in the OUI... However, it would be better to just duplicate the
> code, I think for example 11w won't be announced in WPA1 IEs so we
> shouldn't parse it there when we add support for parsing it to RSN IEs.
Since iw is just printing the actual IE, I don't think we should be
bothering here with code duplication. We can just print what the element
actually contains. If for some weird fucked up AP, has 11w inside WPA1,
then I actually wanna have iw print that :)
Regards
Marcel
Hi Jouni,
> > +static void print_auth(const unsigned char *oui, unsigned char *data)
> > +{
> > + if (memcmp(data, oui, 3) == 0) {
> > + switch (data[3]) {
> > + case 0x01:
> > + printf("802.1x");
>
> s/802.1x/IEEE 802.1X/
>
> > + break;
> > + case 0x02:
> > + printf("PSK");
> > + break;
>
> If you want more coverage here, IEEE 802.11r-2008 adds 00-0F-AC:3 (FT
> authentication negotiated over IEEE 802.1X) and 00-0F-AC:4 (FT
> authentication using PSK). Please note that these are defined only for
> OUI 00-0F-AC, though.
>
> In addition, IEEE 802.11w will be adding 00-0F-AC:5 (IEEE 802.1X or
> PMKSA caching with SHA256 Key Derivation) and 00-0F-AC-6 (PSK with
> SHA256 Key Derivation).
we can add them later. I just wanna have basic support for parsing the
WPA IE. However can you point me to download links for the specs. I get
easily lost in the amount of WiFi/802.11 specs.
> > +static void print_wpa(const char *ie, const unsigned char *oui,
> > + unsigned char len, unsigned char *data)
> > +{
>
> > + if (len < 4) {
> > + tab_on_first(&first);
> > + printf("\t * Group cipher: TKIP\n");
> > + printf("\t * Pairwise ciphers: TKIP\n");
>
> These default are correct for WPA IE, but not for RSN IE/WPA2. However,
> it looks like this function is used for both and as such, the WPA2 case
> should print out CCMP here (and same below if only the pairwise cipher
> suite field is omitted).
Fixed that.
> In addition, this could show the default AKM value (IEEE 802.1X) if it
> is not included in the IE.
And added a default for that.
Regards
Marcel
Hi,
On Mon, 2009-05-04 at 00:51 -0700, Marcel Holtmann wrote:
> I will fix that. Was a misconception on my side. I have to rebase the
> other patches, so can you have a quick look, then I can redo the whole
> batch.
Ok. The others look pretty much good, just a small comment or two, will
reply to them.
johannes
Hi Jouni,
> > we can add them later. I just wanna have basic support for parsing the
> > WPA IE. However can you point me to download links for the specs. I get
> > easily lost in the amount of WiFi/802.11 specs.
>
> IEEE 802.11r-2008 is available through the GetIEEE 802 Program
> (http://standards.ieee.org/getieee802/802.11.html), but IEEE 802.11w
> drafts are not yet publicly available (i.e., only for IEEE 802.11 WG
> members at this point). Anyway, as far as the RSN IE assigned values are
> concerned, you can get the latest information from the IEEE 802.11 ANA
> database:
> https://mentor.ieee.org/802.11/dcn/09/11-09-0031-04-0000-ana-database-assigned-number-authority.xls
>
> (the 7.3.2.25.* tabs are for RSN IE)
thanks for the pointers, but I do leave this now for someone else to
fix. The basic RSN parsing code is in iw now and adding new ciphers etc.
is pretty simple :)
Regards
Marcel
Hi Johannes,
> > > > +static unsigned char vendor_oui[3] = { 0x00, 0x50, 0xf2 };
> > > > +static unsigned char cipher_oui[3] = { 0x00, 0x0f, 0xac };
> > >
> > > ??
> > > 00-50-f2 is "WiFi OUI" (registered to Microsoft), 00-0f-ac is "802.11
> > > OUI", registered to 802.11.
> >
> > I can rename them if that helps.
>
> Yes, please do, but also synchronise the things you print out. _All_
> cipher specs are effectively vendor-specified, but some use vendor
> "WiFi" and some use vendor "802.11" so are standardised in some form. I
> don't think printing "Vendor specified: ..." for the WiFi OUI or "Other"
> for "real" vendor-specified ones helps.
>
> > > Why are you passing in the OUI?
> >
> > The WPA1 and WPA2 IE are uses a different OUI for basically exactly the
> > same thing.
>
> Yeah, I noticed later.
>
> > > > + if (len < 4) {
> > > > + tab_on_first(&first);
> > > > + printf("\t * Group cipher: TKIP\n");
> > > > + printf("\t * Pairwise ciphers: TKIP\n");
> > > > + return;
> > > > + }
> > >
> > > Huh? I don't quite understand this? Is that some backward compat code?
> > > Or is this some WPA1 thing I don't know about?
> >
> > The specification says that the only mandatory field is the version and
> > after that everything else is optional and falls back to default
> > TKIP/TKIP. At least that is what I read of it.
>
> Ok, makes sense I guess.
>
> > > > +static void print_rsn(unsigned char type, unsigned char len, unsigned char *data)
> > > > +{
> > > > + print_wpa("WPA2", cipher_oui, len, data);
> > > > +}
> > >
> > > That's "oui_80211" I guess, not "cipher_oui". Ok I see now why you want
> > > to pass in the OUI... However, it would be better to just duplicate the
> > > code, I think for example 11w won't be announced in WPA1 IEs so we
> > > shouldn't parse it there when we add support for parsing it to RSN IEs.
> >
> > Since iw is just printing the actual IE, I don't think we should be
> > bothering here with code duplication. We can just print what the element
> > actually contains. If for some weird fucked up AP, has 11w inside WPA1,
> > then I actually wanna have iw print that :)
>
> No, this is the wrong approach. See, there are two defined cipher suites
> for, say, CCMP:
> 00:50:f2-4 and 00:0f:ac-4
>
> However, it is not necessarily true that 00:50:f2-N is _always_ the same
> as 00:0f:ac-N. 11w adds 00:0f:ac-6 (AES-128-CMAC, you could add that to
> your patch), but 00:50:f2-6 stays undefined since the WiFi spec defines
> that one, not the 802.11 spec. The WiFi spec could very well define
> 00:50:f2-6 as "quantum cryptography mode reserved for future" if it
> wishes.
I will fix that. Was a misconception on my side. I have to rebase the
other patches, so can you have a quick look, then I can redo the whole
batch.
Regards
Marcel
Hi,
> > > +static unsigned char vendor_oui[3] = { 0x00, 0x50, 0xf2 };
> > > +static unsigned char cipher_oui[3] = { 0x00, 0x0f, 0xac };
> >
> > ??
> > 00-50-f2 is "WiFi OUI" (registered to Microsoft), 00-0f-ac is "802.11
> > OUI", registered to 802.11.
>
> I can rename them if that helps.
Yes, please do, but also synchronise the things you print out. _All_
cipher specs are effectively vendor-specified, but some use vendor
"WiFi" and some use vendor "802.11" so are standardised in some form. I
don't think printing "Vendor specified: ..." for the WiFi OUI or "Other"
for "real" vendor-specified ones helps.
> > Why are you passing in the OUI?
>
> The WPA1 and WPA2 IE are uses a different OUI for basically exactly the
> same thing.
Yeah, I noticed later.
> > > + if (len < 4) {
> > > + tab_on_first(&first);
> > > + printf("\t * Group cipher: TKIP\n");
> > > + printf("\t * Pairwise ciphers: TKIP\n");
> > > + return;
> > > + }
> >
> > Huh? I don't quite understand this? Is that some backward compat code?
> > Or is this some WPA1 thing I don't know about?
>
> The specification says that the only mandatory field is the version and
> after that everything else is optional and falls back to default
> TKIP/TKIP. At least that is what I read of it.
Ok, makes sense I guess.
> > > +static void print_rsn(unsigned char type, unsigned char len, unsigned char *data)
> > > +{
> > > + print_wpa("WPA2", cipher_oui, len, data);
> > > +}
> >
> > That's "oui_80211" I guess, not "cipher_oui". Ok I see now why you want
> > to pass in the OUI... However, it would be better to just duplicate the
> > code, I think for example 11w won't be announced in WPA1 IEs so we
> > shouldn't parse it there when we add support for parsing it to RSN IEs.
>
> Since iw is just printing the actual IE, I don't think we should be
> bothering here with code duplication. We can just print what the element
> actually contains. If for some weird fucked up AP, has 11w inside WPA1,
> then I actually wanna have iw print that :)
No, this is the wrong approach. See, there are two defined cipher suites
for, say, CCMP:
00:50:f2-4 and 00:0f:ac-4
However, it is not necessarily true that 00:50:f2-N is _always_ the same
as 00:0f:ac-N. 11w adds 00:0f:ac-6 (AES-128-CMAC, you could add that to
your patch), but 00:50:f2-6 stays undefined since the WiFi spec defines
that one, not the 802.11 spec. The WiFi spec could very well define
00:50:f2-6 as "quantum cryptography mode reserved for future" if it
wishes.
johannes
On Sun, May 03, 2009 at 09:46:21PM -0700, Marcel Holtmann wrote:
> +static void print_auth(const unsigned char *oui, unsigned char *data)
> +{
> + if (memcmp(data, oui, 3) == 0) {
> + switch (data[3]) {
> + case 0x01:
> + printf("802.1x");
s/802.1x/IEEE 802.1X/
> + break;
> + case 0x02:
> + printf("PSK");
> + break;
If you want more coverage here, IEEE 802.11r-2008 adds 00-0F-AC:3 (FT
authentication negotiated over IEEE 802.1X) and 00-0F-AC:4 (FT
authentication using PSK). Please note that these are defined only for
OUI 00-0F-AC, though.
In addition, IEEE 802.11w will be adding 00-0F-AC:5 (IEEE 802.1X or
PMKSA caching with SHA256 Key Derivation) and 00-0F-AC-6 (PSK with
SHA256 Key Derivation).
> +static void print_wpa(const char *ie, const unsigned char *oui,
> + unsigned char len, unsigned char *data)
> +{
> + if (len < 4) {
> + tab_on_first(&first);
> + printf("\t * Group cipher: TKIP\n");
> + printf("\t * Pairwise ciphers: TKIP\n");
These default are correct for WPA IE, but not for RSN IE/WPA2. However,
it looks like this function is used for both and as such, the WPA2 case
should print out CCMP here (and same below if only the pairwise cipher
suite field is omitted).
In addition, this could show the default AKM value (IEEE 802.1X) if it
is not included in the IE.
--
Jouni Malinen PGP id EFC895FA
On Tue, 2009-05-05 at 08:56 -0700, Marcel Holtmann wrote:
> thanks for the pointers, but I do leave this now for someone else to
> fix. The basic RSN parsing code is in iw now and adding new ciphers etc.
> is pretty simple :)
I've done it already ;)
johannes