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