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

Reply via email to