batctl: add raw wifi packet decapsulation support
Commit Message
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
batctl/tcpdump.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
batctl/tcpdump.h | 49 +++++++++++++++++++++++++
2 files changed, 152 insertions(+), 1 deletions(-)
Comments
On Wednesday 26 January 2011 15:30:08 Marek Lindner wrote:
> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
> ---
> + buff_len -= PRISM_HEADER_LEN;
> + packet_buff += PRISM_HEADER_LEN;
> +
> + /* we assume a minimum size of 38 bytes
> + * (802.11 data frame + LLC)
> + * before we calculate the real size */
> + if (buff_len <= 38)
> + return;
> +
> + wifi_hdr = (struct ieee80211_hdr *)packet_buff;
> + fc = wifi_hdr->frame_control;
> +
> + /* not carrying payload */
> + if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
> + return;
Didn't we say yesterday that we must either use ntohs or only read the first
byte of the framecontrol? The last option which comes to my mind is to define
IEEE80211_FCTL_FTYPE and IEEE80211_FTYPE_DATA for big and little endian
independently.
The same for
IEEE80211_FCTL_TODS 0x0100
IEEE80211_FCTL_FROMDS 0x0200
IEEE80211_FCTL_PROTECTED 0x4000
IEEE80211_STYPE_QOS_DATA 0x0080
Your current version should only work on little endian systems. I would
suggest following version:
#define IEEE80211_FCTL_FTYPE 0x0c00
#define IEEE80211_FTYPE_DATA 0x0800
#define IEEE80211_FCTL_TODS 0x0001
#define IEEE80211_FCTL_FROMDS 0x0002
#define IEEE80211_FCTL_PROTECTED 0x0040
#define IEEE80211_STYPE_QOS_DATA 0x8000
fc = ntohs(wifi_hdr->frame_control);
> + if (fc & IEEE80211_STYPE_QOS_DATA)
> + hdr_len += 2;
Here are you testing only on bit. Are you sure that the other 3 bits aren't
interesting? At least one combination isn't well defined by the 802.11
standard from 2007 and some others are null data types.
Best regards,
Sven
Hi Marek
> + shost = wifi_hdr->addr2;
> + if (fc & IEEE80211_FCTL_FROMDS)
> + shost = wifi_hdr->addr3;
> + else if (fc & IEEE80211_FCTL_TODS)
> + shost = wifi_hdr->addr4;
> +
> + dhost = wifi_hdr->addr1;
> + if (fc & IEEE80211_FCTL_TODS)
> + dhost = wifi_hdr->addr3;
What would happen if you happened to pick up a WDS packet? Four
addresses in the packet. Do we see sensible addresses?
> +
> + hdr_len = 24;
> + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
> + hdr_len = 30;
Again, WDS? We are now a few bytes out when decoding the rest of the
packet.
Andrew
Hi,
> > + shost = wifi_hdr->addr2;
> > + if (fc & IEEE80211_FCTL_FROMDS)
> > + shost = wifi_hdr->addr3;
> > + else if (fc & IEEE80211_FCTL_TODS)
> > + shost = wifi_hdr->addr4;
> > +
> > + dhost = wifi_hdr->addr1;
> > + if (fc & IEEE80211_FCTL_TODS)
> > + dhost = wifi_hdr->addr3;
>
> What would happen if you happened to pick up a WDS packet? Four
> addresses in the packet. Do we see sensible addresses?
we should - that is what addr4 is used for but I did not test it. Let me know
if it does not work for you.
> > +
> > + hdr_len = 24;
> > + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
> > + hdr_len = 30;
>
> Again, WDS? We are now a few bytes out when decoding the rest of the
> packet.
I don't understand what you are trying to say here. Are you sure it is not
working or are you worried that WDS might not work ? If you have doubts please
explain them in more detail.
Thanks,
Marek
On Wednesday 26 January 2011 16:02:32 Sven Eckelmann wrote:
> Didn't we say yesterday that we must either use ntohs or only read the
> first byte of the framecontrol? The last option which comes to my mind is
> to define IEEE80211_FCTL_FTYPE and IEEE80211_FTYPE_DATA for big and little
> endian independently.
I must have misunderstood something but you are right - I'm going to change it
and publish a second patch.
> > + if (fc & IEEE80211_STYPE_QOS_DATA)
> > + hdr_len += 2;
>
> Here are you testing only on bit. Are you sure that the other 3 bits aren't
> interesting? At least one combination isn't well defined by the 802.11
> standard from 2007 and some others are null data types.
I'd claim we only care if it is QoS or not because all QoS packets have a
longer header (QoS control field).
The spec says: "bit 7 is set to 1 in the QoS data subtypes, which have QoS
Control fields in their MAC headers"
Regards,
Marek
On Thu, Jan 27, 2011 at 01:27:57PM +0100, Marek Lindner wrote:
>
> Hi,
>
> > > + shost = wifi_hdr->addr2;
> > > + if (fc & IEEE80211_FCTL_FROMDS)
> > > + shost = wifi_hdr->addr3;
> > > + else if (fc & IEEE80211_FCTL_TODS)
> > > + shost = wifi_hdr->addr4;
> > > +
> > > + dhost = wifi_hdr->addr1;
> > > + if (fc & IEEE80211_FCTL_TODS)
> > > + dhost = wifi_hdr->addr3;
> >
> > What would happen if you happened to pick up a WDS packet? Four
> > addresses in the packet. Do we see sensible addresses?
>
> we should - that is what addr4 is used for but I did not test it. Let me know
> if it does not work for you.
>
>
> > > +
> > > + hdr_len = 24;
> > > + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
> > > + hdr_len = 30;
> >
> > Again, WDS? We are now a few bytes out when decoding the rest of the
> > packet.
OK. Sorry. I'm wrong.
What confused me is time spent debugging WDS in madwifi. It has macros
similar to what you have:
#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */
#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */
#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */
#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */
So i was expecting to see something like DSTODS. However the madwifi
macros are for the complete DIR field, where as you are looking at
individual bits. So
(fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)
is equivalent to the madwifi IEEE80211_FC1_DIR_DSTODS.
So you header length calculation looks O.K.
Andrew
On Friday 28 January 2011 18:24:16 Andrew Lunn wrote:
> So i was expecting to see something like DSTODS. However the madwifi
> macros are for the complete DIR field, where as you are looking at
> individual bits. So
>
> (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)
>
> is equivalent to the madwifi IEEE80211_FC1_DIR_DSTODS.
>
> So you header length calculation looks O.K.
I rather discuss potential bugs even if they turn out not to be bugs instead
of letting them through. :)
Thanks for your review,
Marek
@@ -29,6 +29,7 @@
#include <sys/time.h>
#include <arpa/inet.h>
#include <net/if.h>
+#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
@@ -458,6 +459,75 @@ static void parse_eth_hdr(unsigned char *packet_buff, ssize_t buff_len, int read
}
}
+static void parse_wifi_hdr(unsigned char *packet_buff, ssize_t buff_len, int read_opt, int time_printed)
+{
+ struct ether_header *eth_hdr;
+ struct ieee80211_hdr *wifi_hdr;
+ unsigned char *shost, *dhost;
+ uint16_t fc;
+ int hdr_len;
+
+ if (buff_len <= (ssize_t)PRISM_HEADER_LEN)
+ return;
+
+ buff_len -= PRISM_HEADER_LEN;
+ packet_buff += PRISM_HEADER_LEN;
+
+ /* we assume a minimum size of 38 bytes
+ * (802.11 data frame + LLC)
+ * before we calculate the real size */
+ if (buff_len <= 38)
+ return;
+
+ wifi_hdr = (struct ieee80211_hdr *)packet_buff;
+ fc = wifi_hdr->frame_control;
+
+ /* not carrying payload */
+ if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+ return;
+
+ /* encrypted packet */
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ return;
+
+ shost = wifi_hdr->addr2;
+ if (fc & IEEE80211_FCTL_FROMDS)
+ shost = wifi_hdr->addr3;
+ else if (fc & IEEE80211_FCTL_TODS)
+ shost = wifi_hdr->addr4;
+
+ dhost = wifi_hdr->addr1;
+ if (fc & IEEE80211_FCTL_TODS)
+ dhost = wifi_hdr->addr3;
+
+ hdr_len = 24;
+ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+ hdr_len = 30;
+
+ if (fc & IEEE80211_STYPE_QOS_DATA)
+ hdr_len += 2;
+
+ /* LLC */
+ hdr_len += 8;
+ hdr_len -= sizeof(struct ether_header);
+
+ if (buff_len <= hdr_len)
+ return;
+
+ buff_len -= hdr_len;
+ packet_buff += hdr_len;
+
+ eth_hdr = (struct ether_header *)packet_buff;
+ memmove(eth_hdr->ether_shost, shost, ETH_ALEN);
+ memmove(eth_hdr->ether_dhost, dhost, ETH_ALEN);
+
+ /* printf("parse_wifi_hdr(): ether_type: 0x%04x\n", ntohs(eth_hdr->ether_type));
+ printf("parse_wifi_hdr(): shost: %s\n", ether_ntoa_long((struct ether_addr *)eth_hdr->ether_shost));
+ printf("parse_wifi_hdr(): dhost: %s\n", ether_ntoa_long((struct ether_addr *)eth_hdr->ether_dhost)); */
+
+ parse_eth_hdr(packet_buff, buff_len, read_opt, time_printed);
+}
+
int tcpdump(int argc, char **argv)
{
struct ifreq req;
@@ -526,6 +596,27 @@ int tcpdump(int argc, char **argv)
memset(&req, 0, sizeof (struct ifreq));
strncpy(req.ifr_name, dump_if->dev, IFNAMSIZ);
+ res = ioctl(dump_if->raw_sock, SIOCGIFHWADDR, &req);
+ if (res < 0) {
+ printf("Error - can't create raw socket (SIOCGIFHWADDR): %s\n", strerror(errno));
+ close(dump_if->raw_sock);
+ goto out;
+ }
+
+ dump_if->hw_type = req.ifr_hwaddr.sa_family;
+
+ switch (dump_if->hw_type) {
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE80211_PRISM:
+ break;
+ default:
+ printf("Error - interface '%s' is of unknown type: %i\n", dump_if->dev, dump_if->hw_type);
+ goto out;
+ }
+
+ memset(&req, 0, sizeof (struct ifreq));
+ strncpy(req.ifr_name, dump_if->dev, IFNAMSIZ);
+
res = ioctl(dump_if->raw_sock, SIOCGIFINDEX, &req);
if (res < 0) {
@@ -588,7 +679,18 @@ int tcpdump(int argc, char **argv)
continue;
}
- parse_eth_hdr(packet_buff, read_len, read_opt, 0);
+ switch (dump_if->hw_type) {
+ case ARPHRD_ETHER:
+ parse_eth_hdr(packet_buff, read_len, read_opt, 0);
+ break;
+ case ARPHRD_IEEE80211_PRISM:
+ parse_wifi_hdr(packet_buff, read_len, read_opt, 0);
+ break;
+ default:
+ /* should not happen */
+ break;
+ }
+
fflush(stdout);
}
@@ -23,6 +23,10 @@
#include <netpacket/packet.h>
#include "list-batman.h"
+#ifndef ARPHRD_IEEE80211_PRISM
+#define ARPHRD_IEEE80211_PRISM 802
+#endif
+
#define DUMP_TYPE_BATOGM 1
#define DUMP_TYPE_BATICMP 2
#define DUMP_TYPE_BATUCAST 4
@@ -31,11 +35,21 @@
#define DUMP_TYPE_BATFRAG 32
#define DUMP_TYPE_NONBAT 64
+#define IEEE80211_FCTL_FTYPE 0x000c
+#define IEEE80211_FCTL_TODS 0x0100
+#define IEEE80211_FCTL_FROMDS 0x0200
+#define IEEE80211_FCTL_PROTECTED 0x4000
+
+#define IEEE80211_FTYPE_DATA 0x0008
+
+#define IEEE80211_STYPE_QOS_DATA 0x0080
+
struct dump_if {
struct list_head list;
char *dev;
int32_t raw_sock;
struct sockaddr_ll addr;
+ int32_t hw_type;
};
struct vlanhdr {
@@ -43,4 +57,39 @@ struct vlanhdr {
u_int16_t ether_type;
} __attribute__ ((packed));
+struct ieee80211_hdr {
+ u_int16_t frame_control;
+ u_int16_t duration_id;
+ u_int8_t addr1[6];
+ u_int8_t addr2[6];
+ u_int8_t addr3[6];
+ u_int16_t seq_ctrl;
+ u_int8_t addr4[6];
+} __attribute__ ((packed));
+
+struct prism_item {
+ u_int32_t did;
+ u_int16_t status;
+ u_int16_t len;
+ u_int32_t data;
+};
+
+struct prism_header {
+ u_int32_t msgcode;
+ u_int32_t msglen;
+ u_int8_t devname[16];
+ struct prism_item hosttime;
+ struct prism_item mactime;
+ struct prism_item channel;
+ struct prism_item rssi;
+ struct prism_item sq;
+ struct prism_item signal;
+ struct prism_item noise;
+ struct prism_item rate;
+ struct prism_item istx;
+ struct prism_item frmlen;
+};
+
+#define PRISM_HEADER_LEN sizeof(struct prism_header)
+
int tcpdump(int argc, char **argv);