^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Linux WiMAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Mappping of generic netlink family IDs to net devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * We assign a single generic netlink family ID to each device (to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * simplify lookup).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * We need a way to map family ID to a wimax_dev pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * The idea is to use a very simple lookup. Using a netlink attribute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * with (for example) the interface name implies a heavier search over
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * all the network devices; seemed kind of a waste given that we know
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * we are looking for a WiMAX device and that most systems will have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * just a single WiMAX adapter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * We put all the WiMAX devices in the system in a linked list and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * match the generic link family ID against the list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * By using a linked list, the case of a single adapter in the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * becomes (almost) no overhead, while still working for many more. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * it ever goes beyond two, I'll be surprised.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <net/genetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/wimax.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "wimax-internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define D_SUBMODULE id_table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include "debug-levels.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static DEFINE_SPINLOCK(wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static struct list_head wimax_id_table = LIST_HEAD_INIT(wimax_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * wimax_id_table_add - add a gennetlink familiy ID / wimax_dev mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * @wimax_dev: WiMAX device descriptor to associate to the Generic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Netlink family ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * Look for an empty spot in the ID table; if none found, double the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * table's size and get the first spot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) void wimax_id_table_add(struct wimax_dev *wimax_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) spin_lock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) list_add(&wimax_dev->id_table_node, &wimax_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) spin_unlock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) d_fnend(3, NULL, "(wimax_dev %p)\n", wimax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * wimax_get_netdev_by_info - lookup a wimax_dev from the gennetlink info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * The generic netlink family ID has been filled out in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * nlmsghdr->nlmsg_type field, so we pull it from there, look it up in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * the mapping table and reference the wimax_dev.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * When done, the reference should be dropped with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * 'dev_put(wimax_dev->net_dev)'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct wimax_dev *wimax_dev_get_by_genl_info(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct genl_info *info, int ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct wimax_dev *wimax_dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) d_fnstart(3, NULL, "(info %p ifindex %d)\n", info, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) spin_lock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) list_for_each_entry(wimax_dev, &wimax_id_table, id_table_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (wimax_dev->net_dev->ifindex == ifindex) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) dev_hold(wimax_dev->net_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) wimax_dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) d_printf(1, NULL, "wimax: no devices found with ifindex %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) found:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) spin_unlock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) d_fnend(3, NULL, "(info %p ifindex %d) = %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) info, ifindex, wimax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return wimax_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * wimax_id_table_rm - Remove a gennetlink familiy ID / wimax_dev mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * @id: family ID to remove from the table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) void wimax_id_table_rm(struct wimax_dev *wimax_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) spin_lock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) list_del_init(&wimax_dev->id_table_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) spin_unlock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * Release the gennetlink family id / mapping table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * On debug, verify that the table is empty upon removal. We want the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * code always compiled, to ensure it doesn't bit rot. It will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * compiled out if CONFIG_BUG is disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) void wimax_id_table_release(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct wimax_dev *wimax_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #ifndef CONFIG_BUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) spin_lock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) list_for_each_entry(wimax_dev, &wimax_id_table, id_table_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) pr_err("BUG: %s wimax_dev %p ifindex %d not cleared\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) __func__, wimax_dev, wimax_dev->net_dev->ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) spin_unlock(&wimax_id_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }