// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Wifi performance tracker * * Copyright 2022 Google LLC. * * Author: Star Chang */ #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; dev_hold(dev); core->client->priv = dev; return tp_monitor_init(&core->tp); } static void down_event_handler(struct wlan_ptracker_core *core) { struct net_device *dev = core->dev; tp_monitor_exit(&core->tp); core->dev = NULL; core->client->priv = NULL; if (dev) dev_put(dev); } 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; }