diff options
Diffstat (limited to 'notifier.c')
-rw-r--r-- | notifier.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/notifier.c b/notifier.c new file mode 100644 index 0000000..7f9712d --- /dev/null +++ b/notifier.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Wifi performance tracker + * + * Copyright 2022 Google LLC. + * + * Author: Star Chang <starchang@google.com> + */ +#include "core.h" + +#define notifier_to_core(notifier) \ + container_of(notifier, struct wlan_ptracker_core, notifier) + +#define nb_to_notifier(nb) \ + (container_of(nb, struct wlan_ptracker_notifier, nb)) + +static int up_event_handler(struct wlan_ptracker_core *core, struct net_device *dev) +{ + core->dev = dev; + core->client->core = core; + core->client->priv = dev; + return tp_monitor_init(&core->tp); +} + +static void down_event_handler(struct wlan_ptracker_core *core) +{ + tp_monitor_exit(&core->tp); + core->dev = NULL; + core->client->core = NULL; + core->client->priv = NULL; +} + +static int netdevice_notifier_handler(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + struct wlan_ptracker_notifier *notifier = nb_to_notifier(nb); + struct wlan_ptracker_core *core = notifier_to_core(notifier); + + if (!core->client) + return NOTIFY_DONE; + + if (strcmp(netdev->name, core->client->ifname)) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + ptracker_info(core, "interface up (%s)\n", netdev->name); + up_event_handler(core, netdev); + break; + case NETDEV_DOWN: + ptracker_info(core, "interface down (%s)\n", netdev->name); + down_event_handler(core); + break; + default: + break; + } + return NOTIFY_OK; +} + +int wlan_ptracker_register_notifier(struct wlan_ptracker_notifier *notifier, + struct notifier_block *nb) +{ + return blocking_notifier_chain_register(¬ifier->notifier_head, nb); +} + +void wlan_ptracker_unregister_notifier(struct wlan_ptracker_notifier *notifier, + struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(¬ifier->notifier_head, nb); +} + +int wlan_ptracker_call_chain(struct wlan_ptracker_notifier *notifier, + unsigned long event, void *priv) +{ + struct wlan_ptracker_core *core = priv; + int ret; + + ret = blocking_notifier_call_chain(¬ifier->notifier_head, event, priv); + if (ret & NOTIFY_STOP_MASK) + ptracker_err(core, "notifier chain fail with status %#x\n", ret); + + return notifier_to_errno(ret); +} + +void wlan_ptracker_notifier_init(struct wlan_ptracker_notifier *notifier) +{ + notifier->prev_event = jiffies; + /* register to device notifier */ + notifier->nb.priority = 0; + notifier->nb.notifier_call = netdevice_notifier_handler; + register_netdevice_notifier(¬ifier->nb); + /* init notifier chain to notify plugin modules */ + BLOCKING_INIT_NOTIFIER_HEAD(¬ifier->notifier_head); +} + +void wlan_ptracker_notifier_exit(struct wlan_ptracker_notifier *notifier) +{ + /* reset notifier */ + BLOCKING_INIT_NOTIFIER_HEAD(¬ifier->notifier_head); + /* unregister netdevice notifier*/ + unregister_netdevice_notifier(¬ifier->nb); + notifier->prev_event = 0; +} + |