3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-26 18:59:22 +01:00

netdev: Simplify frame_watch using watchlist

This commit is contained in:
Denis Kenzior 2017-08-31 16:57:05 -05:00
parent fa7fab196e
commit af124da544

View File

@ -92,8 +92,7 @@ struct netdev {
struct watchlist event_watches; struct watchlist event_watches;
struct l_queue *frame_watches; struct watchlist frame_watches;
uint32_t next_frame_watch_id;
bool connected : 1; bool connected : 1;
bool operational : 1; bool operational : 1;
@ -115,12 +114,10 @@ struct netdev_watch {
}; };
struct netdev_frame_watch { struct netdev_frame_watch {
uint32_t id;
uint16_t frame_type; uint16_t frame_type;
uint8_t *prefix; uint8_t *prefix;
size_t prefix_len; size_t prefix_len;
netdev_frame_watch_func_t handler; struct watchlist_item super;
void *user_data;
}; };
static struct l_netlink *rtnl = NULL; static struct l_netlink *rtnl = NULL;
@ -508,14 +505,6 @@ static void netdev_connect_failed(struct l_genl_msg *msg, void *user_data)
connect_data); connect_data);
} }
static void netdev_frame_watch_free(void *data)
{
struct netdev_frame_watch *fw = data;
l_free(fw->prefix);
l_free(fw);
}
static void netdev_free(void *data) static void netdev_free(void *data)
{ {
struct netdev *netdev = data; struct netdev *netdev = data;
@ -544,8 +533,7 @@ static void netdev_free(void *data)
device_remove(netdev->device); device_remove(netdev->device);
watchlist_destroy(&netdev->event_watches); watchlist_destroy(&netdev->event_watches);
watchlist_destroy(&netdev->frame_watches);
l_queue_destroy(netdev->frame_watches, netdev_frame_watch_free);
l_free(netdev); l_free(netdev);
} }
@ -2817,7 +2805,9 @@ struct frame_prefix_info {
static bool netdev_frame_watch_match_prefix(const void *a, const void *b) static bool netdev_frame_watch_match_prefix(const void *a, const void *b)
{ {
const struct netdev_frame_watch *fw = a; const struct watchlist_item *item = a;
const struct netdev_frame_watch *fw =
container_of(item, struct netdev_frame_watch, super);
const struct frame_prefix_info *info = b; const struct frame_prefix_info *info = b;
return fw->frame_type == info->frame_type && return fw->frame_type == info->frame_type &&
@ -2834,7 +2824,6 @@ static void netdev_mgmt_frame_event(struct l_genl_msg *msg,
const struct mmpdu_header *mpdu = NULL; const struct mmpdu_header *mpdu = NULL;
const uint8_t *body; const uint8_t *body;
struct frame_prefix_info info; struct frame_prefix_info info;
const struct l_queue_entry *fw_entry;
static const uint8_t bcast_addr[6] = { static const uint8_t bcast_addr[6] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
}; };
@ -2872,15 +2861,10 @@ static void netdev_mgmt_frame_event(struct l_genl_msg *msg,
info.body = (const uint8_t *) body; info.body = (const uint8_t *) body;
info.body_len = (const uint8_t *) mpdu + frame_len - body; info.body_len = (const uint8_t *) mpdu + frame_len - body;
for (fw_entry = l_queue_get_entries(netdev->frame_watches); fw_entry; WATCHLIST_NOTIFY_MATCHES(&netdev->frame_watches,
fw_entry = fw_entry->next) { netdev_frame_watch_match_prefix, &info,
const struct netdev_frame_watch *fw = fw_entry->data; netdev_frame_watch_func_t,
netdev, mpdu, body, info.body_len);
if (!netdev_frame_watch_match_prefix(fw, &info))
continue;
fw->handler(netdev, mpdu, body, info.body_len, fw->user_data);
}
} }
static void netdev_unicast_notify(struct l_genl_msg *msg, void *user_data) static void netdev_unicast_notify(struct l_genl_msg *msg, void *user_data)
@ -3231,14 +3215,19 @@ check_blacklist:
return true; return true;
} }
static bool netdev_frame_watch_match_id(const void *a, const void *b) static void netdev_frame_watch_free(struct watchlist_item *item)
{ {
const struct netdev_frame_watch *fw = a; struct netdev_frame_watch *fw =
uint32_t id = L_PTR_TO_UINT(b); container_of(item, struct netdev_frame_watch, super);
return fw->id == id; l_free(fw->prefix);
l_free(fw);
} }
static const struct watchlist_ops netdev_frame_watch_ops = {
.item_free = netdev_frame_watch_free,
};
uint32_t netdev_frame_watch_add(struct netdev *netdev, uint16_t frame_type, uint32_t netdev_frame_watch_add(struct netdev *netdev, uint16_t frame_type,
const uint8_t *prefix, size_t prefix_len, const uint8_t *prefix, size_t prefix_len,
netdev_frame_watch_func_t handler, netdev_frame_watch_func_t handler,
@ -3248,25 +3237,21 @@ uint32_t netdev_frame_watch_add(struct netdev *netdev, uint16_t frame_type,
struct l_genl_msg *msg; struct l_genl_msg *msg;
struct frame_prefix_info info = { frame_type, prefix, prefix_len }; struct frame_prefix_info info = { frame_type, prefix, prefix_len };
bool registered; bool registered;
uint32_t id;
fw = l_new(struct netdev_frame_watch, 1); fw = l_new(struct netdev_frame_watch, 1);
fw->id = netdev->next_frame_watch_id++;
fw->frame_type = frame_type; fw->frame_type = frame_type;
fw->prefix = l_memdup(prefix, prefix_len); fw->prefix = l_memdup(prefix, prefix_len);
fw->prefix_len = prefix_len; fw->prefix_len = prefix_len;
fw->handler = handler; id = watchlist_link(&netdev->frame_watches, &fw->super,
fw->user_data = user_data; handler, user_data, NULL);
registered = l_queue_find(netdev->frame_watches, registered = l_queue_find(netdev->frame_watches.items,
netdev_frame_watch_match_prefix, netdev_frame_watch_match_prefix,
&info); &info);
if (!netdev->frame_watches)
netdev->frame_watches = l_queue_new();
l_queue_push_tail(netdev->frame_watches, fw);
if (registered) if (registered)
return fw->id; return id;
msg = l_genl_msg_new_sized(NL80211_CMD_REGISTER_FRAME, 32 + prefix_len); msg = l_genl_msg_new_sized(NL80211_CMD_REGISTER_FRAME, 32 + prefix_len);
@ -3277,27 +3262,17 @@ uint32_t netdev_frame_watch_add(struct netdev *netdev, uint16_t frame_type,
l_genl_family_send(nl80211, msg, NULL, NULL, NULL); l_genl_family_send(nl80211, msg, NULL, NULL, NULL);
return fw->id; return id;
} }
bool netdev_frame_watch_remove(struct netdev *netdev, uint32_t id) bool netdev_frame_watch_remove(struct netdev *netdev, uint32_t id)
{ {
struct netdev_frame_watch *fw;
/* /*
* There's no way to unregister from notifications but that's not a * There's no way to unregister from notifications but that's not a
* problem, we leave them active in the kernel but * problem, we leave them active in the kernel but
* netdev_mgmt_frame_event will ignore these events. * netdev_mgmt_frame_event will ignore these events.
*/ */
return watchlist_remove(&netdev->frame_watches, id);
fw = l_queue_remove_if(netdev->frame_watches,
netdev_frame_watch_match_id, L_UINT_TO_PTR(id));
if (!fw)
return false;
netdev_frame_watch_free(fw);
return true;
} }
static void netdev_create_from_genl(struct l_genl_msg *msg) static void netdev_create_from_genl(struct l_genl_msg *msg)
@ -3399,6 +3374,7 @@ static void netdev_create_from_genl(struct l_genl_msg *msg)
memcpy(netdev->name, ifname, ifname_len); memcpy(netdev->name, ifname, ifname_len);
netdev->wiphy = wiphy; netdev->wiphy = wiphy;
watchlist_init(&netdev->event_watches, NULL); watchlist_init(&netdev->event_watches, NULL);
watchlist_init(&netdev->frame_watches, &netdev_frame_watch_ops);
l_queue_push_tail(netdev_list, netdev); l_queue_push_tail(netdev_list, netdev);