netdev: Handle Action Frames in netdev

Action Frames are sent by nl80211 as unicast data.  We're not receiving
any other unicast packets in iwd at this time so let netdev directly
handle all unicast data on the genl socket.
This commit is contained in:
Andrew Zaborowski 2016-12-23 05:38:00 -05:00 committed by Denis Kenzior
parent b0f51a2527
commit 8646ab5bdd
1 changed files with 116 additions and 0 deletions

View File

@ -1489,6 +1489,75 @@ int netdev_disconnect(struct netdev *netdev,
return 0;
}
static void netdev_action_frame_event(struct netdev *netdev,
const uint8_t *data, size_t len)
{
uint8_t category;
if (len < 1) {
l_debug("Action frame too short");
return;
}
category = data[0];
switch (category) {
default:
l_debug("Unknown action frame category %u received", category);
break;
}
}
static void netdev_mgmt_frame_event(struct l_genl_msg *msg,
struct netdev *netdev)
{
struct l_genl_attr attr;
uint16_t type, len, body_len = 0;
const void *data, *body = NULL;
uint16_t frame_type;
if (!l_genl_attr_init(&attr, msg))
return;
while (l_genl_attr_next(&attr, &type, &len, &data)) {
switch (type) {
case NL80211_ATTR_FRAME:
if (body)
return;
body = data;
body_len = len;
break;
}
}
if (!body || body_len < 25)
return;
frame_type = l_get_le16(body + 0);
if (memcmp(body + 4, netdev->addr, 6))
return;
/* Is this a management frame */
if (((frame_type >> 2) & 3) != 0) {
l_debug("Unknown frame of type %04x received",
(unsigned) frame_type);
return;
}
switch ((frame_type >> 4) & 15) {
case 0xd: /* Action frame */
netdev_action_frame_event(netdev, body + 24, body_len - 24);
break;
default:
l_debug("Unknown frame of type %04x received",
(unsigned) frame_type);
break;
}
}
static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
{
struct netdev *netdev = NULL;
@ -1547,6 +1616,48 @@ static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
}
}
static void netdev_unicast_notify(struct l_genl_msg *msg, void *user_data)
{
struct netdev *netdev = NULL;
struct l_genl_attr attr;
uint16_t type, len;
const void *data;
uint8_t cmd;
cmd = l_genl_msg_get_command(msg);
if (!cmd)
return;
l_debug("Unicast notification %u", cmd);
if (!l_genl_attr_init(&attr, msg))
return;
while (l_genl_attr_next(&attr, &type, &len, &data)) {
switch (type) {
case NL80211_ATTR_IFINDEX:
if (len != sizeof(uint32_t)) {
l_warn("Invalid interface index attribute");
return;
}
netdev = netdev_find(*((uint32_t *) data));
break;
}
}
if (!netdev) {
l_warn("Unicast notification is missing ifindex attribute");
return;
}
switch (cmd) {
case NL80211_CMD_FRAME:
netdev_mgmt_frame_event(msg, netdev);
break;
}
}
struct netdev_watch_event_data {
struct netdev *netdev;
enum netdev_watch_event type;
@ -1970,6 +2081,7 @@ bool netdev_init(struct l_genl_family *in,
const char *whitelist, const char *blacklist)
{
struct l_genl_msg *msg;
struct l_genl *genl = l_genl_family_get_genl(in);
if (rtnl)
return false;
@ -2009,6 +2121,10 @@ bool netdev_init(struct l_genl_family *in,
NULL, NULL))
l_error("Registering for MLME notification failed");
if (!l_genl_set_unicast_handler(genl, netdev_unicast_notify,
NULL, NULL))
l_error("Registering for unicast notification failed");
__handshake_set_install_tk_func(netdev_set_tk);
__handshake_set_install_gtk_func(netdev_set_gtk);
__handshake_set_install_igtk_func(netdev_set_igtk);