Hi Robert,
I have something. I created a fromdevice2 element that pushes pkttype
== PACKET_OUTGOING packets, and a radiotapdecap2 element that process
radiotap tx feedbacks packets, these tx feedback packets are using a
radiotap tx header (is different from the typical radiotap rx header).
Use:
from_dev :: FromDevice2($DEVICE, PROMISC true)
from_dev[0] -> ... //process normal packets
from_dev[1] -> Discard;
from_dev[2] -> RadiotapDecap2(DEBUG true) -> Discard; //process tx
feedback packets
The RadiotapDecap2 is not finished because i am only interested in
retries. But if u look at the code it should be easy to complete.
On Sun, Jul 26, 2009 at 12:56 AM, Robert
Sombrutzki<[email protected]> wrote:
> Hi Javier,
> did you solve the problem with txfeedback-packets ? I had the same problem
> with Madwifi and Click. My solution was to change the packettype in the
> madwifi-driver. I changed the packettype for feedback-packets to
> PACKET_OTHERHOST in the madwifi-driver and it works. But i think, that's not
> the right way. However, in early madwifi-versions ( e.g. 0.9.1.), the
> packettype for all received or feedbacked packets in monitormode is
> PACKET_OTHERHOST.
> Did you find any other solutions ??
>
> Best regards,
> Robert
>
> Patch for packettype -> PACKET_OTHERHOST;
>
> diff --git a/net80211/ieee80211_monitor.c b/net80211/ieee80211_monitor.c
> index 3b3f65a..71dac5d 100644
> --- a/net80211/ieee80211_monitor.c
> +++ b/net80211/ieee80211_monitor.c
> @@ -350,7 +353,8 @@ ieee80211_input_monitor(struct ieee80211com *ic, struct
> sk_buff *skb,
> * on the contents of the frame to set pkttype.
> */
> if (tx)
> - pkttype = PACKET_OUTGOING;
> + //pkttype = PACKET_OUTGOING;
> + pkttype = PACKET_OTHERHOST;
> else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
> if (IEEE80211_ADDR_EQ(wh->i_addr1,
> dev->broadcast))
> pkttype = PACKET_BROADCAST;
>
>
>>Hi,
>>
>>Madwifi driver is forwading a tx packet with some stats into monitor
>>device each time it transmits a packet (or fails).
>>
>>The problem is that this packet is pkttype == PACKET_OUTGOING and
>>fromdevice element is not processing it. It is possible that other
>>drivers have this behavior too.
>>
>>May be an optional output to fromdevice element may be useful for this
>>packets?
>>
>>Regards
>>Javier
>
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* fromdevice.{cc,hh} -- element reads packets live from network via pcap
* Douglas S. J. De Couto, Eddie Kohler, John Jannotti
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2001 International Computer Science Institute
* Copyright (c) 2005-2007 Regents of the University of California
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include "fromdevice2.hh"
#include <click/error.hh>
#include <click/straccum.hh>
#include <click/confparse.hh>
#include <click/glue.hh>
#include <click/packet_anno.hh>
#include <click/standard/scheduleinfo.hh>
#include <click/userutils.hh>
#include <unistd.h>
#include <fcntl.h>
//#include <click/fakepcap.hh>
#include <../elements/userlevel/fakepcap.hh>
#ifndef __sun
#include <sys/ioctl.h>
#else
#include <sys/ioccom.h>
#endif
#if FROMDEVICE_LINUX
# include <sys/socket.h>
# include <net/if.h>
# include <features.h>
# if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
# include <netpacket/packet.h>
# include <net/ethernet.h>
# else
# include <net/if_packet.h>
# include <linux/if_packet.h>
# include <linux/if_ether.h>
# endif
#endif
CLICK_DECLS
FromDevice2::FromDevice2()
:
#if FROMDEVICE_LINUX
_linux_fd(-1),
#endif
#if FROMDEVICE_PCAP
_pcap(0), _pcap_task(this), _pcap_complaints(0),
#endif
_count(0), _promisc(0), _snaplen(0)
{
}
FromDevice2::~FromDevice2()
{
}
int
FromDevice2::configure(Vector<String> &conf, ErrorHandler *errh)
{
bool promisc = false, outbound = false, sniffer = true;
_snaplen = 2046;
_headroom = Packet::default_headroom;
_headroom += (4 - (_headroom + 2) % 4) % 4; // default 4/2 alignment
_force_ip = false;
String bpf_filter, capture;
if (cp_va_kparse(conf, this, errh,
"DEVNAME", cpkP+cpkM, cpString, &_ifname,
"PROMISC", cpkP, cpBool, &promisc,
"SNAPLEN", cpkP, cpUnsigned, &_snaplen,
"SNIFFER", 0, cpBool, &sniffer,
"FORCE_IP", 0, cpBool, &_force_ip,
"CAPTURE", 0, cpWord, &capture,
"BPF_FILTER", 0, cpString, &bpf_filter,
"OUTBOUND", 0, cpBool, &outbound,
"HEADROOM", 0, cpUnsigned, &_headroom,
cpEnd) < 0)
return -1;
if (_snaplen > 8190 || _snaplen < 14)
return errh->error("SNAPLEN out of range");
if (_headroom > 8190)
return errh->error("HEADROOM out of range");
#if FROMDEVICE_PCAP
_bpf_filter = bpf_filter;
#endif
// set _capture
if (capture == "") {
#if FROMDEVICE_PCAP && FROMDEVICE_LINUX
_capture = (bpf_filter ? CAPTURE_PCAP : CAPTURE_LINUX);
#elif FROMDEVICE_LINUX
_capture = CAPTURE_LINUX;
#elif FROMDEVICE_PCAP
_capture = CAPTURE_PCAP;
#else
return errh->error("this platform does not support any capture method");
#endif
}
#if FROMDEVICE_LINUX
else if (capture == "LINUX")
_capture = CAPTURE_LINUX;
#endif
#if FROMDEVICE_PCAP
else if (capture == "PCAP")
_capture = CAPTURE_PCAP;
#endif
else
return errh->error("capture method '%s' not supported", capture.c_str());
if (bpf_filter && _capture != CAPTURE_PCAP)
errh->warning("not using PCAP capture method, BPF filter ignored");
_sniffer = sniffer;
_promisc = promisc;
_outbound = outbound;
return 0;
}
#if FROMDEVICE_LINUX
int
FromDevice2::open_packet_socket(String ifname, ErrorHandler *errh)
{
int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fd == -1)
return errh->error("%s: socket: %s", ifname.c_str(), strerror(errno));
// get interface index
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
int res = ioctl(fd, SIOCGIFINDEX, &ifr);
if (res != 0) {
close(fd);
return errh->error("%s: SIOCGIFINDEX: %s", ifname.c_str(), strerror(errno));
}
int ifindex = ifr.ifr_ifindex;
// bind to the specified interface. from packet man page, only
// sll_protocol and sll_ifindex fields are used; also have to set
// sll_family
sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons(ETH_P_ALL);
sa.sll_ifindex = ifindex;
res = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
if (res != 0) {
close(fd);
return errh->error("%s: bind: %s", ifname.c_str(), strerror(errno));
}
// nonblocking I/O on the packet socket so we can poll
fcntl(fd, F_SETFL, O_NONBLOCK);
return fd;
}
int
FromDevice2::set_promiscuous(int fd, String ifname, bool promisc)
{
// get interface flags
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0)
return -2;
int was_promisc = (ifr.ifr_flags & IFF_PROMISC ? 1 : 0);
// set or reset promiscuous flag
#ifdef SOL_PACKET
if (ioctl(fd, SIOCGIFINDEX, &ifr) != 0)
return -2;
struct packet_mreq mr;
memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = ifr.ifr_ifindex;
mr.mr_type = (promisc ? PACKET_MR_PROMISC : PACKET_MR_ALLMULTI);
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
return -3;
#else
if (was_promisc != promisc) {
ifr.ifr_flags = (promisc ? ifr.ifr_flags | IFF_PROMISC : ifr.ifr_flags & ~IFF_PROMISC);
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
return -3;
}
#endif
return was_promisc;
}
#endif /* FROMDEVICE_LINUX */
int
FromDevice2::initialize(ErrorHandler *errh)
{
if (!_ifname)
return errh->error("interface not set");
#if FROMDEVICE_PCAP
if (_capture == CAPTURE_PCAP) {
assert(!_pcap);
char *ifname = _ifname.mutable_c_str();
char ebuf[PCAP_ERRBUF_SIZE];
_pcap = pcap_open_live(ifname, _snaplen, _promisc,
1, /* timeout: don't wait for packets */
ebuf);
// Note: pcap error buffer will contain the interface name
if (!_pcap)
return errh->error("%s", ebuf);
// nonblocking I/O on the packet socket so we can poll
int pcap_fd = fd();
# if HAVE_PCAP_SETNONBLOCK
if (pcap_setnonblock(_pcap, 1, ebuf) < 0)
errh->warning("pcap_setnonblock: %s", ebuf);
# else
if (fcntl(pcap_fd, F_SETFL, O_NONBLOCK) < 0)
errh->warning("setting nonblocking: %s", strerror(errno));
# endif
# ifdef BIOCSSEESENT
{
int r, accept = _outbound;
if ((r = ioctl(pcap_fd, BIOCSSEESENT, &accept)) == -1)
return errh->error("%s: BIOCSSEESENT: %s", ifname, strerror(errno));
else if (r != 0)
errh->warning("%s: BIOCSSEESENT returns %d", ifname, r);
}
# endif
# if defined(BIOCIMMEDIATE) && !defined(__sun) // pcap/bpf ioctl, not in DLPI/bufmod
{
int r, yes = 1;
if ((r = ioctl(pcap_fd, BIOCIMMEDIATE, &yes)) == -1)
return errh->error("%s: BIOCIMMEDIATE: %s", ifname, strerror(errno));
else if (r != 0)
errh->warning("%s: BIOCIMMEDIATE returns %d", ifname, r);
}
# endif
bpf_u_int32 netmask;
bpf_u_int32 localnet;
if (pcap_lookupnet(ifname, &localnet, &netmask, ebuf) < 0)
errh->warning("%s", ebuf);
// Later versions of pcap distributed with linux (e.g. the redhat
// linux pcap-0.4-16) want to have a filter installed before they
// will pick up any packets.
// compile the BPF filter
struct bpf_program fcode;
if (pcap_compile(_pcap, &fcode, _bpf_filter.mutable_c_str(), 0, netmask) < 0)
return errh->error("%s: %s", ifname, pcap_geterr(_pcap));
if (pcap_setfilter(_pcap, &fcode) < 0)
return errh->error("%s: %s", ifname, pcap_geterr(_pcap));
add_select(pcap_fd, SELECT_READ);
_datalink = pcap_datalink(_pcap);
if (_force_ip && !fake_pcap_dlt_force_ipable(_datalink))
errh->warning("%s: strange data link type %d, FORCE_IP will not work", ifname, _datalink);
ScheduleInfo::initialize_task(this, &_pcap_task, false, errh);
}
#endif
#if FROMDEVICE_LINUX
if (_capture == CAPTURE_LINUX) {
_linux_fd = open_packet_socket(_ifname, errh);
if (_linux_fd < 0)
return -1;
int promisc_ok = set_promiscuous(_linux_fd, _ifname, _promisc);
if (promisc_ok < 0) {
if (_promisc)
errh->warning("cannot set promiscuous mode");
_was_promisc = -1;
} else
_was_promisc = promisc_ok;
add_select(_linux_fd, SELECT_READ);
_datalink = FAKE_DLT_EN10MB;
}
#endif
if (!_sniffer)
if (KernelFilter::device_filter(_ifname, true, errh) < 0)
_sniffer = true;
return 0;
}
void
FromDevice2::cleanup(CleanupStage stage)
{
if (stage >= CLEANUP_INITIALIZED && !_sniffer)
KernelFilter::device_filter(_ifname, false, ErrorHandler::default_handler());
#if FROMDEVICE_LINUX
if (_linux_fd >= 0) {
if (_was_promisc >= 0)
set_promiscuous(_linux_fd, _ifname, _was_promisc);
close(_linux_fd);
_linux_fd = -1;
}
#endif
#if FROMDEVICE_PCAP
if (_pcap) {
pcap_close(_pcap);
_pcap = 0;
}
#endif
}
#if FROMDEVICE_PCAP
CLICK_ENDDECLS
extern "C" {
void
FromDevice2_get_packet(u_char* clientdata,
const struct pcap_pkthdr* pkthdr,
const u_char* data)
{
static char bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
FromDevice2 *fd = (FromDevice2 *) clientdata;
int length = pkthdr->caplen;
Packet *p = Packet::make(fd->_headroom, data, length, 0);
// set packet type annotation
if (p->data()[0] & 1) {
if (memcmp(bcast_addr, p->data(), 6) == 0)
p->set_packet_type_anno(Packet::BROADCAST);
else
p->set_packet_type_anno(Packet::MULTICAST);
}
// set annotations
p->set_timestamp_anno(Timestamp::make_usec(pkthdr->ts.tv_sec, pkthdr->ts.tv_usec));
p->set_mac_header(p->data());
SET_EXTRA_LENGTH_ANNO(p, pkthdr->len - length);
if (!fd->_force_ip || fake_pcap_force_ip(p, fd->_datalink))
fd->output(0).push(p);
else
fd->checked_output_push(1, p);
}
}
CLICK_DECLS
#endif
void
FromDevice2::selected(int)
{
#if FROMDEVICE_PCAP
if (_capture == CAPTURE_PCAP) {
// Read and push() at most one packet.
int r = pcap_dispatch(_pcap, 1, FromDevice2_get_packet, (u_char *) this);
if (r > 0)
_pcap_task.reschedule();
else if (r < 0 && ++_pcap_complaints < 5)
ErrorHandler::default_handler()->error("%{element}: %s", this, pcap_geterr(_pcap));
}
#endif
#if FROMDEVICE_LINUX
if (_capture == CAPTURE_LINUX)
{
struct sockaddr_ll sa;
socklen_t fromlen = sizeof(sa);
WritablePacket *p = Packet::make(_headroom, 0, _snaplen, 0);
int len = recvfrom(_linux_fd, p->data(), p->length(), MSG_TRUNC, (sockaddr *)&sa, &fromlen);
if (len > 0 && (sa.sll_pkttype != PACKET_OUTGOING || _outbound))
{
if (len > _snaplen) {
assert(p->length() == (uint32_t)_snaplen);
SET_EXTRA_LENGTH_ANNO(p, len - _snaplen);
} else
p->take(_snaplen - len);
p->set_packet_type_anno((Packet::PacketType)sa.sll_pkttype);
p->timestamp_anno().set_timeval_ioctl(_linux_fd, SIOCGSTAMP);
p->set_mac_header(p->data());
if (!_force_ip || fake_pcap_force_ip(p, _datalink))
output(0).push(p);
else
checked_output_push(1, p);
}
else if (len > 0 && (sa.sll_pkttype == PACKET_OUTGOING))
{
//click_chatter("FromDevice2: OUTGOING");
if (len > _snaplen) {
assert(p->length() == (uint32_t)_snaplen);
SET_EXTRA_LENGTH_ANNO(p, len - _snaplen);
} else
p->take(_snaplen - len);
p->set_packet_type_anno((Packet::PacketType)sa.sll_pkttype);
p->timestamp_anno().set_timeval_ioctl(_linux_fd, SIOCGSTAMP);
p->set_mac_header(p->data());
checked_output_push(2, p);
}
else
{
p->kill();
if (len <= 0 && errno != EAGAIN)
click_chatter("FromDevice2(%s): recvfrom: %s", _ifname.c_str(), strerror(errno));
}
}
#endif
}
#if FROMDEVICE_PCAP
bool
FromDevice2::run_task(Task *)
{
// Read and push() at most one packet.
int r = pcap_dispatch(_pcap, 1, FromDevice2_get_packet, (u_char *) this);
if (r > 0)
_pcap_task.fast_reschedule();
else if (r < 0 && ++_pcap_complaints < 5)
ErrorHandler::default_handler()->error("%{element}: %s", this, pcap_geterr(_pcap));
return r > 0;
}
#endif
void
FromDevice2::kernel_drops(bool& known, int& max_drops) const
{
#if FROMDEVICE_LINUX
// You might be able to do this better by parsing netstat/ifconfig output,
// but for now, we just give up.
#endif
known = false, max_drops = -1;
#if FROMDEVICE_PCAP
if (_capture == CAPTURE_PCAP) {
struct pcap_stat stats;
if (pcap_stats(_pcap, &stats) >= 0)
known = true, max_drops = stats.ps_drop;
}
#endif
}
String
FromDevice2::read_handler(Element* e, void *thunk)
{
FromDevice2* fd = static_cast<FromDevice2*>(e);
if (thunk == (void *) 0) {
int max_drops;
bool known;
fd->kernel_drops(known, max_drops);
if (known)
return String(max_drops);
else if (max_drops >= 0)
return "<" + String(max_drops);
else
return "??";
} else if (thunk == (void *) 1)
return String(fake_pcap_unparse_dlt(fd->_datalink));
else
return String(fd->_count);
}
int
FromDevice2::write_handler(const String &, Element *e, void *, ErrorHandler *)
{
FromDevice2* fd = static_cast<FromDevice2*>(e);
fd->_count = 0;
return 0;
}
void
FromDevice2::add_handlers()
{
add_read_handler("kernel_drops", read_handler, (void *) 0);
add_read_handler("encap", read_handler, (void *) 1);
add_read_handler("count", read_handler, (void *) 2);
add_write_handler("reset_counts", write_handler, 0, Handler::BUTTON);
}
CLICK_ENDDECLS
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter)
EXPORT_ELEMENT(FromDevice2)
#ifndef CLICK_FROMDEVICE2_USERLEVEL_HH
#define CLICK_FROMDEVICE2_USERLEVEL_HH
#include <click/element.hh>
#include "elements/userlevel/kernelfilter.hh"
#ifdef __linux__
# define FROMDEVICE_LINUX 1
#endif
#ifdef HAVE_PCAP
# define FROMDEVICE_PCAP 1
# include <click/task.hh>
extern "C" {
# include <pcap.h>
/* Prototype pcap_setnonblock if we have it, but not the prototype. */
# if HAVE_PCAP_SETNONBLOCK && !HAVE_DECL_PCAP_SETNONBLOCK
int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf);
# endif
void FromDevice2_get_packet(u_char*, const struct pcap_pkthdr*, const u_char*);
}
#endif
CLICK_DECLS
/*
=title FromDevice2.u
=c
FromDevice2(DEVNAME [, I<keywords> SNIFFER, PROMISC, SNAPLEN, FORCE_IP, CAPTURE, BPF_FILTER, OUTBOUND, HEADROOM])
=s netdevices
reads packets from network device (user-level)
=d
This manual page describes the user-level version of the FromDevice2
element. For the Linux kernel module element, read the FromDevice2(n) manual
page.
Reads packets from the kernel that were received on the network controller
named DEVNAME.
User-level FromDevice2 behaves like a packet sniffer by default. Packets
emitted by FromDevice2 are also received and processed by the kernel. Thus, it
doesn't usually make sense to run a router with user-level Click, since each
packet will get processed twice (once by Click, once by the kernel). Install
firewalling rules in your kernel if you want to prevent this, for instance
using the KernelFilter element or FromDevice2's SNIFFER false argument.
Under Linux, a FromDevice2 element will not receive packets sent by a
ToDevice element for the same device. Under other operating systems, your
mileage may vary.
Sets the packet type annotation appropriately. Also sets the timestamp
annotation to the time the kernel reports that the packet was received.
Keyword arguments are:
=over 8
=item SNIFFER
Boolean. Specifies whether FromDevice2 should run in sniffer mode. In
non-sniffer mode, FromDevice2 installs KernelFilter filtering rules to block
the kernel from handling any packets arriving on device DEVNAME. Default is
true (sniffer mode).
=item PROMISC
Boolean. FromDevice2 puts the device in promiscuous mode if PROMISC is true.
The default is false.
=item SNAPLEN
Unsigned. On some systems, packets larger than SNAPLEN will be truncated.
Defaults to 2046.
=item FORCE_IP
Boolean. If true, then output only IP packets. (Any link-level header remains,
but the IP header annotation has been set appropriately.) Default is false.
=item CAPTURE
Word. Defines the capture method FromDevice2 will use to read packets from the
kernel. Linux targets generally support PCAP and LINUX; other targets support
only PCAP. Defaults to LINUX on Linux targets (unless you give a BPF_FILTER),
and PCAP elsewhere.
=item BPF_FILTER
String. A BPF filter expression used to select the interesting packets.
Default is the empty string, which means all packets. If CAPTURE is not PCAP,
then any filter expression is ignored with a warning.
=item OUTBOUND
Boolean. If true, then emit packets that the kernel sends to the given
interface, as well as packets that the kernel receives from it. Default is
false.
=item HEADROOM
Integer. Amount of bytes of headroom to leave before the packet data. Defaults
to roughly 28.
=back
=e
FromDevice2(eth0) -> ...
=n
FromDevice2 sets packets' extra length annotations as appropriate.
=h count read-only
Returns the number of packets read by the device.
=h reset_counts write-only
Resets "count" to zero.
=h kernel_drops read-only
Returns the number of packets dropped by the kernel, probably due to memory
constraints, before FromDevice2 could get them. This may be an integer; the
notation C<"<I<d>">, meaning at most C<I<d>> drops; or C<"??">, meaning the
number of drops is not known.
=h encap read-only
Returns a string indicating the encapsulation type on this link. Can be
`C<IP>', `C<ETHER>', or `C<FDDI>', for example.
=a ToDevice.u, FromDump, ToDump, KernelFilter, FromDevice2(n) */
class FromDevice2 : public Element { public:
FromDevice2();
~FromDevice2();
const char *class_name() const { return "FromDevice2"; }
const char *port_count() const { return "0/-3"; }
const char *processing() const { return PUSH; }
int configure_phase() const { return KernelFilter::CONFIGURE_PHASE_FROMDEVICE; }
int configure(Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *);
void cleanup(CleanupStage);
void add_handlers();
String ifname() const { return _ifname; }
inline int fd() const;
void selected(int fd);
#if FROMDEVICE_PCAP
bool run_task(Task *);
#endif
#if FROMDEVICE_LINUX
static int open_packet_socket(String, ErrorHandler *);
static int set_promiscuous(int, String, bool);
#endif
void kernel_drops(bool& known, int& max_drops) const;
private:
#if FROMDEVICE_LINUX
int _linux_fd;
unsigned char *_linux_packetbuf;
#endif
#if FROMDEVICE_PCAP
pcap_t* _pcap;
Task _pcap_task;
int _pcap_complaints;
friend void FromDevice2_get_packet(u_char*, const struct pcap_pkthdr*,
const u_char*);
#endif
bool _force_ip;
int _datalink;
#if HAVE_INT64_TYPES
typedef uint64_t counter_t;
#else
typedef uint32_t counter_t;
#endif
counter_t _count;
String _ifname;
bool _sniffer : 1;
bool _promisc : 1;
bool _outbound : 1;
int _was_promisc : 2;
int _snaplen;
unsigned _headroom;
enum { CAPTURE_PCAP, CAPTURE_LINUX };
int _capture;
#if FROMDEVICE_PCAP
String _bpf_filter;
#endif
static String read_handler(Element*, void*);
static int write_handler(const String&, Element*, void*, ErrorHandler*);
};
inline int
FromDevice2::fd() const
{
#if FROMDEVICE_LINUX
if (_linux_fd >= 0)
return _linux_fd;
#endif
#if FROMDEVICE_PCAP
if (_pcap)
return pcap_fileno(_pcap);
#endif
return -1;
}
CLICK_ENDDECLS
#endif
/*
* radiotapdecap.{cc,hh} -- decapsultates 802.11 packets
* John Bicket
*
* Copyright (c) 2004 Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include "radiotapdecap2.hh"
//#include <click/etheraddress.hh>
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include <clicknet/wifi.h>
#include <clicknet/radiotap.h>
#include <click/packet_anno.hh>
//#include <clicknet/llc.h>
#include <click/straccum.hh>
CLICK_DECLS
// generic? radiotap rx header (MADWIFI is using this)
struct ath_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
u_int64_t wr_tsft; //Value in microseconds of the MAC's 64-bit 802.11 Time
u_int8_t wr_flags;
u_int8_t wr_rate;
u_int16_t wr_chan_freq;
u_int16_t wr_chan_flags;
int8_t wr_dbm_antsignal;
int8_t wr_dbm_antnoise;
u_int8_t wr_antenna;
u_int8_t wr_antsignal;
}CLICK_SIZE_PACKED_ATTRIBUTE;
// generic? radiotap tx feedback header (MADWIFI is using this)
struct ath_tx_radiotap_header {
struct ieee80211_radiotap_header wt_ihdr;
u_int64_t wt_tsft; //Value in microseconds of the MAC's 64-bit 802.11 Time
u_int8_t wt_flags;
u_int8_t wt_rate;
u_int8_t wt_antenna;
u_int8_t wt_pad;
u_int16_t wt_txflags;
u_int8_t wt_dataretries;
}CLICK_SIZE_PACKED_ATTRIBUTE;
RadiotapDecap2::RadiotapDecap2()
{
}
RadiotapDecap2::~RadiotapDecap2()
{
}
int
RadiotapDecap2::configure(Vector<String> &conf, ErrorHandler *errh)
{
_debug = false;
if (cp_va_kparse(conf, this, errh,
"DEBUG", 0, cpBool, &_debug,
cpEnd) < 0)
return -1;
return 0;
}
Packet *
RadiotapDecap2::simple_action(Packet *p)
{
StringAccum sa;
struct ath_tx_radiotap_header *th = (struct ath_tx_radiotap_header *) p->data();
struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p);
sa << name().c_str();
// TODO header verification, at the moment only looks at heaader len
// TODO madwifi is doning something wrong ¿? , for each packet it feedbacks 2 packets
// one is the correct (header len == 23)
// another is incorrect (header len != 23)
if (le16_to_cpu(th->wt_ihdr.it_len) != 23)
{
//not a valid tx feedback
//sa << " incorrect tx feedback frame ";
//if (_debug) click_chatter ("%s \n",sa.c_str());
return 0;
}
ceh->magic = WIFI_EXTRA_MAGIC;
ceh->retries = (u_int8_t) th->wt_dataretries;
int retries = (int) ceh->retries;
//TODO read more elements from radiotaptx header.
sa << " size of header " << sizeof(struct ath_tx_radiotap_header);
sa << " retries " << retries;
if (_debug) click_chatter ("%s \n",sa.c_str());
return p;
}
enum {H_DEBUG};
static String
RadiotapDecap2_read_param(Element *e, void *thunk)
{
RadiotapDecap2 *td = (RadiotapDecap2 *)e;
switch ((uintptr_t) thunk) {
case H_DEBUG:
return String(td->_debug) + "\n";
default:
return String();
}
}
static int
RadiotapDecap2_write_param(const String &in_s, Element *e, void *vparam,
ErrorHandler *errh)
{
RadiotapDecap2 *f = (RadiotapDecap2 *)e;
String s = cp_uncomment(in_s);
switch((intptr_t)vparam) {
case H_DEBUG: { //debug
bool debug;
if (!cp_bool(s, &debug))
return errh->error("debug parameter must be boolean");
f->_debug = debug;
break;
}
}
return 0;
}
void
RadiotapDecap2::add_handlers()
{
add_read_handler("debug", RadiotapDecap2_read_param, (void *) H_DEBUG);
add_write_handler("debug", RadiotapDecap2_write_param, (void *) H_DEBUG);
}
CLICK_ENDDECLS
EXPORT_ELEMENT(RadiotapDecap2)
#ifndef CLICK_RADIOTAPDECAP2_HH
#define CLICK_RADIOTAPDECAP2_HH
#include <click/element.hh>
#include <clicknet/ether.h>
CLICK_DECLS
/*
=c
RadiotapDecap()
=s Wifi
Pulls the click_wifi_radiotap header from a packet and stores it in Packet::anno()
=d
Removes the radiotap header and copies to to Packet->anno(). This contains
informatino such as rssi, noise, bitrate, etc.
=a RadiotapEncap
*/
class RadiotapDecap2 : public Element { public:
RadiotapDecap2();
~RadiotapDecap2();
const char *class_name() const { return "RadiotapDecap2"; }
const char *port_count() const { return PORTS_1_1; }
const char *processing() const { return AGNOSTIC; }
int configure(Vector<String> &, ErrorHandler *);
bool can_live_reconfigure() const { return true; }
Packet *simple_action(Packet *);
void add_handlers();
bool _debug;
private:
};
CLICK_ENDDECLS
#endif
_______________________________________________
click mailing list
[email protected]
https://amsterdam.lcs.mit.edu/mailman/listinfo/click