--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -24,6 +24,7 @@ mac80211-y := \
 	wme.o \
 	event.o \
 	chan.o \
+	collector.o \
 	mlme.o
 
 mac80211-$(CONFIG_COMPAT_MAC80211_DRIVER_API_TRACER) += trace.o
--- /dev/null
+++ b/net/mac80211/collector.c
@@ -0,0 +1,244 @@
+#include "collector.h"
+
+static struct nla_policy collector_genl_policy[COLLECTOR_ATTR_MAX + 1] = {
+       [COLLECTOR_ATTR_TIMESTAMP] = { .type = NLA_UNSPEC,
+                                 .len = sizeof( struct timeval ) },
+        [COLLECTOR_ATTR_EVENT] = { .type = NLA_U32 },
+        [COLLECTOR_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC,
+                                       .len = 6*sizeof(u8) },
+        [COLLECTOR_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC,
+                                          .len = 6*sizeof(u8) },
+       [COLLECTOR_ATTR_LEN] = { .type = NLA_U32 },
+        [COLLECTOR_ATTR_FLAGS] = { .type = NLA_U32 },
+        [COLLECTOR_ATTR_RX_RATE] = { .type = NLA_U32 },
+        [COLLECTOR_ATTR_SIGNAL] = { .type = NLA_U32 },
+        [COLLECTOR_ATTR_TX_INFO] = { .type = NLA_UNSPEC,
+                                 .len = IEEE80211_TX_MAX_RATES*sizeof(
+                                        struct ieee80211_tx_rate)},
+};
+
+enum {
+        COLLECTOR_CMD_UNSPEC,
+       COLLECTOR_CMD_EVENT,
+        COLLECTOR_CMD_REGISTER,
+       __COLLECTOR_CMD_MAX,
+};
+#define COLLECTOR_CMD_MAX (_COLLECTOR_CMD_MAX - 1)
+
+/* netlink */
+static struct genl_family collector_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .hdrsize = 0,
+       .name = "MAC80211_COLL",
+       .version = VERSION_NR,
+       .maxattr = COLLECTOR_ATTR_MAX,
+};
+// Collector user process pid
+static atomic_t collector_pid;
+
+// Check if the collector is active
+static int collector_active(void){
+       return atomic_read(&collector_pid);
+}
+
+// Notify the event to userspace
+void collector_event_notify( struct sk_buff *my_skb, u32 event )
+{
+       struct sk_buff *skb;
+       void *msg_head;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb);
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(my_skb);
+       size_t data_len = my_skb->len - ieee80211_hdrlen(hdr->frame_control);
+       struct timeval now;
+
+       if( !collector_active() || data_len == 0 )
+               return;
+
+        skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+        if (skb == NULL)
+                goto nla_put_failure;
+
+        msg_head = genlmsg_put(skb, 0, 0, &collector_genl_family, 0,
+                               COLLECTOR_CMD_EVENT);
+        if (msg_head == NULL) {
+                printk(KERN_DEBUG "mac80211_collect: problem with msg_head\n");
+                goto nla_put_failure;
+        }    
+
+       /* Get and put event timestamp */
+       do_gettimeofday(&now);
+        NLA_PUT(skb, COLLECTOR_ATTR_TIMESTAMP,
+                           sizeof(struct timeval), &now );
+       /* Put event ID */
+        NLA_PUT_U32(skb, COLLECTOR_ATTR_EVENT, event);
+
+       /* Put the rx address */
+        NLA_PUT(skb, COLLECTOR_ATTR_ADDR_RECEIVER,
+                     sizeof(u8) * 6, hdr->addr1);
+
+
+       /* Put the tx address */
+        NLA_PUT(skb, COLLECTOR_ATTR_ADDR_TRANSMITTER,
+                     sizeof(u8) * 6, hdr->addr2);
+
+       /* Put the packet len */
+       NLA_PUT_U32(skb, COLLECTOR_ATTR_LEN, data_len);
+
+        /* Put the flags for this transmission */
+        NLA_PUT_U32(skb, COLLECTOR_ATTR_FLAGS, info->flags);
+
+       switch(event){
+               case EVENT_END_TX:
+               {
+                               /* Put the tx control (rate and retries) info*/
+                       NLA_PUT(skb, COLLECTOR_ATTR_TX_INFO,
+                            sizeof(struct ieee80211_tx_rate)*IEEE80211_TX_MAX_RATES,
+                            info->status.rates);
+       
+                       break;
+               }
+               case EVENT_END_RX:
+               {
+                       /* Put the rx signal */
+                       NLA_PUT_U32(skb, COLLECTOR_ATTR_SIGNAL,status->signal);
+
+                       /* Put the rx rate */
+                       NLA_PUT_U32(skb, COLLECTOR_ATTR_RX_RATE,status->rate_idx);      
+
+                       break;
+
+               }
+      }
+       genlmsg_end(skb, msg_head);
+       genlmsg_unicast(&init_net, skb, atomic_read(&collector_pid));
+
+       return;
+
+nla_put_failure:
+        printk(KERN_DEBUG "mac80211_collector: error occured in %s\n", __func__);
+               
+}
+
+// Manage a a registration of an userspace process
+static int collector_register_received_nl(struct sk_buff *skb_2,
+                                      struct genl_info *info)
+{
+        if (info == NULL)
+                goto out;
+
+        atomic_set(&collector_pid, info->snd_pid);
+
+        printk(KERN_DEBUG "mac80211_collector: received a REGISTER, "
+               "activate event collection to pid %d\n", info->snd_pid);
+
+        return 0;
+
+out:
+        printk(KERN_DEBUG "mac80211_collector: error occured in %s\n", __func__);
+        return -1;
+}
+
+// mac80211 allows communications only kernel -> userspace, I'm not supposed to receive anything here
+static int collector_received_nl(struct sk_buff *skb_2,
+                                      struct genl_info *info)
+{
+        if (info == NULL)
+                goto out;
+
+        printk(KERN_DEBUG "mac80211_collector: received an unknown request , "
+               "in kernel space\n"); 
+
+        return -1;
+
+out:
+        printk(KERN_DEBUG "mac80211_collector: error occured in %s\n", __func__);
+        return -1;
+}
+
+/* Generic Netlink operations array */
+static struct genl_ops collector_ops[] = {
+{    
+       .cmd = COLLECTOR_CMD_REGISTER,
+       .flags = 0, 
+       .policy = collector_genl_policy,
+       .doit = collector_register_received_nl,
+       .dumpit = NULL,
+},   
+{
+        .cmd = COLLECTOR_CMD_EVENT,
+        .flags = 0,
+        .policy = collector_genl_policy,
+        .doit = collector_received_nl,
+        .dumpit = NULL,
+},
+
+};
+
+// Collect release event
+static int mac80211_collector_netlink_notify(struct notifier_block *nb,
+                                         unsigned long state,
+                                         void *_notify)
+{
+        struct netlink_notify *notify = _notify;
+
+        if (state != NETLINK_URELEASE)
+                return NOTIFY_DONE;
+
+       if (notify->pid == atomic_read(&collector_pid)) {
+               printk(KERN_INFO "mac80211_collector: collector released netlink"
+                      " socket, disabling event collection\n");
+                atomic_set(&collector_pid, 0);
+        }
+        return NOTIFY_DONE;
+
+}
+
+
+static struct notifier_block collector_netlink_notifier = {
+        .notifier_call = mac80211_collector_netlink_notify,
+};
+
+// Initialize collector
+int __init
+collector_init_netlink(void)
+{
+        int rc;
+        printk(KERN_INFO "mac80211_collector: initializing netlink\n");
+
+        atomic_set(&collector_pid, 0);
+
+        rc = genl_register_family_with_ops(&collector_genl_family,
+                collector_ops, ARRAY_SIZE(collector_ops));
+        if (rc)
+                goto failure;
+
+        rc = netlink_register_notifier(&collector_netlink_notifier);
+        if (rc)
+                goto failure;
+
+        return 0;
+
+failure:
+        printk(KERN_DEBUG "mac80211_collector: error occured in %s\n", __func__);
+        return -1;
+}
+
+// Initialize collector
+void __exit
+collector_exit_netlink(void)
+{
+        int ret;
+
+        printk(KERN_INFO "mac80211_collector: closing netlink\n");
+        /* unregister the notifier */
+        netlink_unregister_notifier(&collector_netlink_notifier);
+        /* unregister the family */
+        ret = genl_unregister_family(&collector_genl_family);
+        if (ret)
+               printk(KERN_DEBUG "mac80211_collector: "
+                       "unregister family %i\n", ret);
+}
+
+
+
--- /dev/null
+++ b/net/mac80211/collector.h
@@ -0,0 +1,61 @@
+/*
+ * mac80211_hwsim - user space event collector for mac80211
+ * Copyright (c) 2011, Carlo Vallati <warner83@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <net/genetlink.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+extern int collector_init_netlink(void);
+extern void collector_exit_netlink(void);
+extern void collector_event_notify( struct sk_buff *my_skb, u32 event );
+
+
+/**
+ * enum collector_attrs - collector netlink attributes
+ *
+ * @COLLECTOR_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @COLLECTOR_ATTR_EVENT: Event occurred 0 -> TX, 1 -> RX
+ * @COLLECTOR_ATTR_ADDR_RECEIVER: MAC address of the radio device that
+ *     the frame is broadcasted to
+ * @COLLECTOR_ATTR_ADDR_TRANSMITTER: MAC address of the radio device that
+ *     the frame was broadcasted from
+ * @COLLECTOR_ATTR_FLAGS: mac80211 transmission flags 
+ * @COLLECTOR_ATTR_RX_RATE: rx rate index for this frame 
+ * @COLLECTOR_ATTR_SIGNAL: RX signal for this frame 
+ * @COLLECTOR_ATTR_TX_INFO: ieee80211_tx_rate array
+ * @__COLLECTOR_ATTR_MAX: enum limit
+ */
+
+
+enum {
+       COLLECTOR_ATTR_UNSPEC,
+       COLLECTOR_ATTR_EVENT,
+       COLLECTOR_ATTR_ADDR_RECEIVER,
+       COLLECTOR_ATTR_ADDR_TRANSMITTER,
+       COLLECTOR_ATTR_LEN,
+       COLLECTOR_ATTR_FLAGS,
+       COLLECTOR_ATTR_RX_RATE,
+       COLLECTOR_ATTR_SIGNAL,
+       COLLECTOR_ATTR_TX_INFO,
+       COLLECTOR_ATTR_TIMESTAMP,
+       __COLLECTOR_ATTR_MAX,
+};
+#define COLLECTOR_ATTR_MAX (__COLLECTOR_ATTR_MAX - 1)
+
+#define VERSION_NR 1
+
+enum{
+        EVENT_START_TX,
+        EVENT_END_TX,
+        EVENT_END_RX,
+        __EVENT_MAX,
+};
+
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -32,6 +32,7 @@
 #include "led.h"
 #include "cfg.h"
 #include "debugfs.h"
+#include "collector.h"
 
 static struct lock_class_key ieee80211_rx_skb_queue_class;
 
@@ -1120,6 +1121,12 @@ static int __init ieee80211_init(void)
 	if (ret)
 		goto err_netdev;
 
+       ret = collector_init_netlink();
+       if (ret)
+               goto err_netlink;
+
+
+
 	return 0;
  err_netdev:
 	rc80211_pid_exit();
@@ -1127,7 +1134,8 @@ static int __init ieee80211_init(void)
 	rc80211_minstrel_ht_exit();
  err_minstrel:
 	rc80211_minstrel_exit();
-
+ err_netlink:
+       collector_exit_netlink();
 	return ret;
 }
 
@@ -1136,6 +1144,7 @@ static void __exit ieee80211_exit(void)
 	rc80211_pid_exit();
 	rc80211_minstrel_ht_exit();
 	rc80211_minstrel_exit();
+	collector_exit_netlink();
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37))
 	flush_scheduled_work();
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -30,6 +30,7 @@
 #include "tkip.h"
 #include "wme.h"
 #include "rate.h"
+#include "collector.h"
 
 /*
  * monitor mode reception
@@ -2907,6 +2908,8 @@ static bool ieee80211_prepare_and_rx_han
 		rx->skb = skb;
 	}
 
+	collector_event_notify(skb, EVENT_END_RX);
+
 	ieee80211_invoke_rx_handlers(rx);
 	return true;
 }
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -18,7 +18,7 @@
 #include "mesh.h"
 #include "led.h"
 #include "wme.h"
-
+#include "collector.h"
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 				 struct sk_buff *skb)
@@ -548,7 +548,10 @@ void ieee80211_tx_status(struct ieee8021
 	 * Fragments are passed to low-level drivers as separate skbs, so these
 	 * are actually fragments, not frames. Update frame counters only for
 	 * the first fragment of the frame. */
-	if (info->flags & IEEE80211_TX_STAT_ACK) {
+	if (info->flags & IEEE80211_TX_STAT_ACK){ 
+               // Notify the event to the collector
+               collector_event_notify(skb, EVENT_END_TX);
+
 		if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
 			local->dot11TransmittedFrameCount++;
 			if (is_multicast_ether_addr(hdr->addr1))
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -33,7 +33,7 @@
 #include "wpa.h"
 #include "wme.h"
 #include "rate.h"
-
+#include "collector.h"
 /* misc utils */
 
 static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
@@ -1412,7 +1412,11 @@ static bool ieee80211_tx(struct ieee8021
 	if (!invoke_tx_handlers(&tx))
 		result = __ieee80211_tx(local, &tx.skbs, led_len,
 					tx.sta, txpending);
- out:
+
+	// Collect the event
+       collector_event_notify(skb, EVENT_START_TX);
+
+out:
 	rcu_read_unlock();
 	return result;
 }
