Created a patch for mac80211 that allows to capture the raw IEEE80211 packets

(management, control, data) of one or more wireless interfaces.
Not necessary the monitor interface. The patch allows to discriminate which
IEEE802.11 types and IEEE802.11 subtypes capture.
This commit is contained in:
vemax78
2014-06-04 22:58:34 +02:00
parent 0ebf1a434f
commit 92c86462dc
7 changed files with 586 additions and 44 deletions

View File

@ -3,48 +3,138 @@
#include <linux/netlink.h>
#include <net/genetlink.h>
#include <linux/rcupdate.h>
#include <linux/err.h>
#include <net/mac80211.h>
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
#define NLSMARTCAPWAP_FLAG_NEED_RTNL 0x01
struct nlsmartcapwap_device {
struct list_head list;
struct ieee80211_pcktunnel pcktunnel_handler;
u32 ifindex;
};
/* */
static u32 g_nlusermodeid = 0;
static u32 nlsmartcapwap_usermodeid = 0;
static LIST_HEAD(nlsmartcapwap_dev_list);
/* */
static int nlsmartcapwap_handler(struct sk_buff *skb, int sig_dbm, unsigned char rate, void *data) {
printk("Receive packet\n");
return 0;
}
/* */
static struct nlsmartcapwap_device* nlsmartcapwap_new_device(u32 ifindex) {
struct nlsmartcapwap_device* nldev;
/* Create device */
nldev = (struct nlsmartcapwap_device*)kzalloc(sizeof(struct nlsmartcapwap_device), GFP_KERNEL);
if (nldev) {
/* Initialize device */
nldev->pcktunnel_handler.handler = nlsmartcapwap_handler;
nldev->pcktunnel_handler.data = (void*)nldev;
nldev->ifindex = ifindex;
}
return nldev;
}
/* */
static void nlsmartcapwap_free_device(struct nlsmartcapwap_device* nldev) {
/* Disconnect device from mac80211 */
ieee80211_pcktunnel_deregister(nldev->ifindex, &nldev->pcktunnel_handler);
/* Free memory */
kfree(nldev);
}
/* */
static struct nlsmartcapwap_device* nlsmartcapwap_register_device(u32 ifindex) {
struct nlsmartcapwap_device* nldev;
ASSERT_RTNL();
/* Search device */
list_for_each_entry(nldev, &nlsmartcapwap_dev_list, list) {
if (nldev->ifindex == ifindex) {
return nldev;
}
}
/* Create device */
nldev = nlsmartcapwap_new_device(ifindex);
if (nldev) {
list_add_rcu(&nldev->list, &nlsmartcapwap_dev_list);
}
return nldev;
}
/* */
static int nlsmartcapwap_unregister_device(u32 ifindex) {
int ret = -ENODEV;
struct nlsmartcapwap_device* nldev;
ASSERT_RTNL();
/* Search device */
list_for_each_entry(nldev, &nlsmartcapwap_dev_list, list) {
if (nldev->ifindex == ifindex) {
/* Remove from list */
list_del_rcu(&nldev->list);
synchronize_net();
/* Free device */
ret = 0;
nlsmartcapwap_free_device(nldev);
break;
}
}
return ret;
}
/* */
static void nlsmartcapwap_close(void) {
struct nlsmartcapwap_device* nldev;
struct nlsmartcapwap_device* tmp;
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_dev_list, list) {
list_del(&nldev->list);
/* Free device */
nlsmartcapwap_free_device(nldev);
}
}
/* */
static int nlsmartcapwap_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
int rtnl = ((ops->internal_flags & NLSMARTCAPWAP_FLAG_NEED_RTNL) ? 1 : 0);
/* */
if (rtnl) {
rtnl_lock();
}
rtnl_lock();
return 0;
}
/* */
static void nlsmartcapwap_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
if (ops->internal_flags & NLSMARTCAPWAP_FLAG_NEED_RTNL) {
rtnl_unlock();
}
rtnl_unlock();
}
/* */
static int nlsmartcapwap_connect(struct sk_buff *skb, struct genl_info *info) {
int result = 0;
static int nlsmartcapwap_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
u32 portid = genl_info_snd_portid(info);
if (!g_nlusermodeid) {
g_nlusermodeid = portid;
} else if (g_nlusermodeid == portid) {
result = -EALREADY;
if (!nlsmartcapwap_usermodeid) {
nlsmartcapwap_usermodeid = portid;
} else if (nlsmartcapwap_usermodeid == portid) {
ret = -EALREADY;
} else {
result = -EBUSY;
ret = -EBUSY;
}
return result;
return ret;
}
/* */
@ -53,11 +143,14 @@ static int nlsmartcapwap_netlink_notify(struct notifier_block* nb, unsigned long
u32 portid = netlink_notify_portid(notify);
/* */
if (state = NETLINK_URELEASE) {
if (state == NETLINK_URELEASE) {
rtnl_lock();
if (g_nlusermodeid == portid) {
g_nlusermodeid = 0;
if (nlsmartcapwap_usermodeid == portid) {
nlsmartcapwap_usermodeid = 0;
/* Close all devices */
nlsmartcapwap_close();
}
rtnl_unlock();
@ -66,6 +159,68 @@ static int nlsmartcapwap_netlink_notify(struct notifier_block* nb, unsigned long
return NOTIFY_DONE;
}
/* */
static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex;
struct nlsmartcapwap_device* nldev;
int ret = -EINVAL;
/* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
return -EINVAL;
}
ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]);
if (!ifindex) {
return -EINVAL;
}
/* Register device */
nldev = nlsmartcapwap_register_device(ifindex);
if (!nldev) {
return -EINVAL;
}
/* Set subtype masking */
if (info->attrs[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK]) {
nldev->pcktunnel_handler.subtype_mask[0] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK]);
}
if (info->attrs[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK]) {
nldev->pcktunnel_handler.subtype_mask[1] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK]);
}
if (info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]) {
nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]);
}
/* Connect device to mac80211 */
ret = ieee80211_pcktunnel_register(ifindex, &nldev->pcktunnel_handler);
if (ret) {
nlsmartcapwap_unregister_device(ifindex);
}
return ret;
}
/* */
static int nlsmartcapwap_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex;
/* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
return -EINVAL;
}
ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]);
if (!ifindex) {
return -EINVAL;
}
/* Unregister device */
return nlsmartcapwap_unregister_device(ifindex);
}
/* Netlink Family */
static struct genl_family nlsmartcapwap_family = {
.id = GENL_ID_GENERATE,
@ -80,16 +235,30 @@ static struct genl_family nlsmartcapwap_family = {
static const struct nla_policy nlsmartcapwap_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_ATTR_IFINDEX] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 },
};
/* Netlink Ops */
static __genl_const struct genl_ops nlsmartcapwap_ops[] = {
{
.cmd = NLSMARTCAPWAP_CMD_CONNECT,
.doit = nlsmartcapwap_connect,
.cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = nlsmartcapwap_link,
.policy = nlsmartcapwap_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
.doit = nlsmartcapwap_join_mac80211_device,
.policy = nlsmartcapwap_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
.doit = nlsmartcapwap_leave_mac80211_device,
.policy = nlsmartcapwap_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NLSMARTCAPWAP_FLAG_NEED_RTNL,
},
};
@ -100,26 +269,32 @@ static struct notifier_block nlsmartcapwap_netlink_notifier = {
/* */
int nlsmartcapwap_init(void) {
int result;
int ret;
/* Register netlink family */
result = genl_register_family_with_ops(&nlsmartcapwap_family, nlsmartcapwap_ops);
if (result) {
return result;
ret = genl_register_family_with_ops(&nlsmartcapwap_family, nlsmartcapwap_ops);
if (ret) {
return ret;
}
/* Register netlink notifier */
result = netlink_register_notifier(&nlsmartcapwap_netlink_notifier);
if (result) {
ret = netlink_register_notifier(&nlsmartcapwap_netlink_notifier);
if (ret) {
genl_unregister_family(&nlsmartcapwap_family);
return result;
return ret;
}
return result;
return ret;
}
/* */
void nlsmartcapwap_exit(void) {
/* */
rtnl_lock();
nlsmartcapwap_close();
rtnl_unlock();
/* */
netlink_unregister_notifier(&nlsmartcapwap_netlink_notifier);
genl_unregister_family(&nlsmartcapwap_family);
}

View File

@ -9,6 +9,9 @@ enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_UNSPEC,
NLSMARTCAPWAP_ATTR_IFINDEX,
NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK,
/* Last attribute */
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
@ -19,7 +22,17 @@ enum nlsmartcapwap_attrs {
enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_UNSPEC,
NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_SET_AC_ADDRESS,
NLSMARTCAPWAP_CMD_CONNECT,
NLSMARTCAPWAP_CMD_TEARDOWN,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
/* Last command */
__NLSMARTCAPWAP_CMD_AFTER_LAST,

View File

@ -6,6 +6,7 @@
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include "wtp_kmod.h"
/* Local version of nl80211 with all feature to remove the problem of frag version of nl80211 */
#include "nl80211_v3_10.h"
@ -353,7 +354,7 @@ static int nl80211_device_changefrequency(struct wifi_device* device, struct wif
/* Set wifi frequency */
result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL);
if (!result) {
capwap_logging_error("Change %s frequency %d", wlan->virtname, (int)freq->frequency);
capwap_logging_info("Change %s frequency %d", wlan->virtname, (int)freq->frequency);
} else {
capwap_logging_error("Unable set frequency %d, error code: %d", (int)freq->frequency, result);
}
@ -802,6 +803,11 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
wlan->flags |= WIFI_WLAN_OPERSTATE_RUNNING;
netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP);
/* */
if (!wtp_kmod_join_mac80211_device(wlan->virtindex)) {
capwap_logging_info("Joined in kernel mode the interface %d", wlan->virtindex);
}
return 0;
}

View File

@ -145,7 +145,7 @@ static int wtp_kmod_send_and_recv_msg(struct nl_msg* msg, wtp_kmod_valid_cb vali
}
/* */
static int wtp_kmod_connect(void) {
static int wtp_kmod_link(void) {
int result;
struct nl_msg* msg;
@ -156,7 +156,7 @@ static int wtp_kmod_connect(void) {
}
/* */
genlmsg_put(msg, 0, 0, g_kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CONNECT, 0);
genlmsg_put(msg, 0, 0, g_kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
@ -173,6 +173,38 @@ static int wtp_kmod_connect(void) {
return result;
}
/* */
int wtp_kmod_join_mac80211_device(uint32_t ifindex) {
int result;
struct nl_msg* msg;
/* */
if (!g_kmodhandle.nlsmartcapwap_id) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, ifindex);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, 0xffff);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_warning("Unable to join with interface: %d", ifindex);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_init(void) {
int result;
@ -197,6 +229,7 @@ int wtp_kmod_init(void) {
/* Get nlsmartcapwap netlink family */
g_kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_kmodhandle.nl, SMARTCAPWAP_GENL_NAME);
if (g_kmodhandle.nlsmartcapwap_id < 0) {
capwap_logging_warning("Unable to found kernel module");
wtp_kmod_free();
return -1;
}
@ -205,8 +238,8 @@ int wtp_kmod_init(void) {
nl_cb_set(g_kmodhandle.nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, wtp_kmod_no_seq_check, NULL);
nl_cb_set(g_kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wtp_kmod_valid_handler, NULL);
/* Connect to kernel module */
result = wtp_kmod_connect();
/* Link to kernel module */
result = wtp_kmod_link();
if (result) {
wtp_kmod_free();
return result;
@ -224,4 +257,7 @@ void wtp_kmod_free(void) {
if (g_kmodhandle.nl_cb) {
nl_cb_put(g_kmodhandle.nl_cb);
}
/* */
memset(&g_kmodhandle, 0, sizeof(struct wtp_kmod_handle));
}

View File

@ -5,4 +5,7 @@
int wtp_kmod_init(void);
void wtp_kmod_free(void);
/* */
int wtp_kmod_join_mac80211_device(uint32_t ifindex);
#endif /* __WTP_KMOD_HEADER__ */