1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker * Copyright (c) 2003-2008 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker */
5*4dc78e53SAndroid Build Coastguard Worker
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker * @ingroup link
8*4dc78e53SAndroid Build Coastguard Worker * @defgroup link_API Link Modules API
9*4dc78e53SAndroid Build Coastguard Worker * @brief API for modules implementing specific link types/semantics.
10*4dc78e53SAndroid Build Coastguard Worker *
11*4dc78e53SAndroid Build Coastguard Worker * @par 1) Registering/Unregistering a new link info type
12*4dc78e53SAndroid Build Coastguard Worker * @code
13*4dc78e53SAndroid Build Coastguard Worker * static struct rtnl_link_info_ops vlan_info_ops = {
14*4dc78e53SAndroid Build Coastguard Worker * .io_name = "vlan",
15*4dc78e53SAndroid Build Coastguard Worker * .io_alloc = vlan_alloc,
16*4dc78e53SAndroid Build Coastguard Worker * .io_parse = vlan_parse,
17*4dc78e53SAndroid Build Coastguard Worker * .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief,
18*4dc78e53SAndroid Build Coastguard Worker * .io_dump[NL_DUMP_FULL] = vlan_dump_full,
19*4dc78e53SAndroid Build Coastguard Worker * .io_free = vlan_free,
20*4dc78e53SAndroid Build Coastguard Worker * };
21*4dc78e53SAndroid Build Coastguard Worker *
22*4dc78e53SAndroid Build Coastguard Worker * static void _nl_init vlan_init(void)
23*4dc78e53SAndroid Build Coastguard Worker * {
24*4dc78e53SAndroid Build Coastguard Worker * rtnl_link_register_info(&vlan_info_ops);
25*4dc78e53SAndroid Build Coastguard Worker * }
26*4dc78e53SAndroid Build Coastguard Worker *
27*4dc78e53SAndroid Build Coastguard Worker * static void _nl_exit vlan_exit(void)
28*4dc78e53SAndroid Build Coastguard Worker * {
29*4dc78e53SAndroid Build Coastguard Worker * rtnl_link_unregister_info(&vlan_info_ops);
30*4dc78e53SAndroid Build Coastguard Worker * }
31*4dc78e53SAndroid Build Coastguard Worker * @endcode
32*4dc78e53SAndroid Build Coastguard Worker *
33*4dc78e53SAndroid Build Coastguard Worker * @{
34*4dc78e53SAndroid Build Coastguard Worker */
35*4dc78e53SAndroid Build Coastguard Worker
36*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
37*4dc78e53SAndroid Build Coastguard Worker
38*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
39*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
40*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/link.h>
41*4dc78e53SAndroid Build Coastguard Worker
42*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
43*4dc78e53SAndroid Build Coastguard Worker #include "link-api.h"
44*4dc78e53SAndroid Build Coastguard Worker
45*4dc78e53SAndroid Build Coastguard Worker static NL_LIST_HEAD(info_ops);
46*4dc78e53SAndroid Build Coastguard Worker
47*4dc78e53SAndroid Build Coastguard Worker /* lock protecting info_ops and af_ops */
48*4dc78e53SAndroid Build Coastguard Worker static NL_RW_LOCK(info_lock);
49*4dc78e53SAndroid Build Coastguard Worker
__rtnl_link_info_ops_lookup(const char * name)50*4dc78e53SAndroid Build Coastguard Worker static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
51*4dc78e53SAndroid Build Coastguard Worker {
52*4dc78e53SAndroid Build Coastguard Worker struct rtnl_link_info_ops *ops;
53*4dc78e53SAndroid Build Coastguard Worker
54*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry(ops, &info_ops, io_list)
55*4dc78e53SAndroid Build Coastguard Worker if (!strcmp(ops->io_name, name))
56*4dc78e53SAndroid Build Coastguard Worker return ops;
57*4dc78e53SAndroid Build Coastguard Worker
58*4dc78e53SAndroid Build Coastguard Worker return NULL;
59*4dc78e53SAndroid Build Coastguard Worker }
60*4dc78e53SAndroid Build Coastguard Worker
61*4dc78e53SAndroid Build Coastguard Worker /**
62*4dc78e53SAndroid Build Coastguard Worker * @name Link Info Modules
63*4dc78e53SAndroid Build Coastguard Worker * @{
64*4dc78e53SAndroid Build Coastguard Worker */
65*4dc78e53SAndroid Build Coastguard Worker
66*4dc78e53SAndroid Build Coastguard Worker /**
67*4dc78e53SAndroid Build Coastguard Worker * Return operations of a specific link info type
68*4dc78e53SAndroid Build Coastguard Worker * @arg name Name of link info type.
69*4dc78e53SAndroid Build Coastguard Worker *
70*4dc78e53SAndroid Build Coastguard Worker * @note The returned pointer must be given back using rtnl_link_info_ops_put()
71*4dc78e53SAndroid Build Coastguard Worker *
72*4dc78e53SAndroid Build Coastguard Worker * @return Pointer to operations or NULL if unavailable.
73*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_info_ops_lookup(const char * name)74*4dc78e53SAndroid Build Coastguard Worker struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
75*4dc78e53SAndroid Build Coastguard Worker {
76*4dc78e53SAndroid Build Coastguard Worker struct rtnl_link_info_ops *ops;
77*4dc78e53SAndroid Build Coastguard Worker
78*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
79*4dc78e53SAndroid Build Coastguard Worker if ((ops = __rtnl_link_info_ops_lookup(name)))
80*4dc78e53SAndroid Build Coastguard Worker ops->io_refcnt++;
81*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
82*4dc78e53SAndroid Build Coastguard Worker
83*4dc78e53SAndroid Build Coastguard Worker return ops;
84*4dc78e53SAndroid Build Coastguard Worker }
85*4dc78e53SAndroid Build Coastguard Worker
86*4dc78e53SAndroid Build Coastguard Worker /**
87*4dc78e53SAndroid Build Coastguard Worker * Take reference to a set of operations.
88*4dc78e53SAndroid Build Coastguard Worker * @arg ops Link info operations.
89*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_info_ops_get(struct rtnl_link_info_ops * ops)90*4dc78e53SAndroid Build Coastguard Worker void rtnl_link_info_ops_get(struct rtnl_link_info_ops *ops)
91*4dc78e53SAndroid Build Coastguard Worker {
92*4dc78e53SAndroid Build Coastguard Worker if (!ops)
93*4dc78e53SAndroid Build Coastguard Worker return;
94*4dc78e53SAndroid Build Coastguard Worker
95*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
96*4dc78e53SAndroid Build Coastguard Worker ops->io_refcnt++;
97*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
98*4dc78e53SAndroid Build Coastguard Worker }
99*4dc78e53SAndroid Build Coastguard Worker
100*4dc78e53SAndroid Build Coastguard Worker /**
101*4dc78e53SAndroid Build Coastguard Worker * Give back reference to a set of operations.
102*4dc78e53SAndroid Build Coastguard Worker * @arg ops Link info operations.
103*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_info_ops_put(struct rtnl_link_info_ops * ops)104*4dc78e53SAndroid Build Coastguard Worker void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
105*4dc78e53SAndroid Build Coastguard Worker {
106*4dc78e53SAndroid Build Coastguard Worker if (!ops)
107*4dc78e53SAndroid Build Coastguard Worker return;
108*4dc78e53SAndroid Build Coastguard Worker
109*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
110*4dc78e53SAndroid Build Coastguard Worker _nl_assert(ops->io_refcnt > 0);
111*4dc78e53SAndroid Build Coastguard Worker ops->io_refcnt--;
112*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
113*4dc78e53SAndroid Build Coastguard Worker }
114*4dc78e53SAndroid Build Coastguard Worker
115*4dc78e53SAndroid Build Coastguard Worker /**
116*4dc78e53SAndroid Build Coastguard Worker * Register operations for a link info type
117*4dc78e53SAndroid Build Coastguard Worker * @arg ops Link info operations
118*4dc78e53SAndroid Build Coastguard Worker *
119*4dc78e53SAndroid Build Coastguard Worker * This function must be called by modules implementing a specific link
120*4dc78e53SAndroid Build Coastguard Worker * info type. It will make the operations implemented by the module
121*4dc78e53SAndroid Build Coastguard Worker * available for everyone else.
122*4dc78e53SAndroid Build Coastguard Worker *
123*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code.
124*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_INVAL Link info name not specified.
125*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_EXIST Operations for address family already registered.
126*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_register_info(struct rtnl_link_info_ops * ops)127*4dc78e53SAndroid Build Coastguard Worker int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
128*4dc78e53SAndroid Build Coastguard Worker {
129*4dc78e53SAndroid Build Coastguard Worker int err = 0;
130*4dc78e53SAndroid Build Coastguard Worker
131*4dc78e53SAndroid Build Coastguard Worker if (ops->io_name == NULL)
132*4dc78e53SAndroid Build Coastguard Worker return -NLE_INVAL;
133*4dc78e53SAndroid Build Coastguard Worker
134*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
135*4dc78e53SAndroid Build Coastguard Worker if (__rtnl_link_info_ops_lookup(ops->io_name)) {
136*4dc78e53SAndroid Build Coastguard Worker err = -NLE_EXIST;
137*4dc78e53SAndroid Build Coastguard Worker goto errout;
138*4dc78e53SAndroid Build Coastguard Worker }
139*4dc78e53SAndroid Build Coastguard Worker
140*4dc78e53SAndroid Build Coastguard Worker NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
141*4dc78e53SAndroid Build Coastguard Worker
142*4dc78e53SAndroid Build Coastguard Worker nl_list_add_tail(&ops->io_list, &info_ops);
143*4dc78e53SAndroid Build Coastguard Worker errout:
144*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
145*4dc78e53SAndroid Build Coastguard Worker
146*4dc78e53SAndroid Build Coastguard Worker return err;
147*4dc78e53SAndroid Build Coastguard Worker }
148*4dc78e53SAndroid Build Coastguard Worker
149*4dc78e53SAndroid Build Coastguard Worker /**
150*4dc78e53SAndroid Build Coastguard Worker * Unregister operations for a link info type
151*4dc78e53SAndroid Build Coastguard Worker * @arg ops Link info operations
152*4dc78e53SAndroid Build Coastguard Worker *
153*4dc78e53SAndroid Build Coastguard Worker * This function must be called if a module implementing a specific link
154*4dc78e53SAndroid Build Coastguard Worker * info type is unloaded or becomes unavailable. It must provide a
155*4dc78e53SAndroid Build Coastguard Worker * set of operations which have previously been registered using
156*4dc78e53SAndroid Build Coastguard Worker * rtnl_link_register_info().
157*4dc78e53SAndroid Build Coastguard Worker *
158*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code
159*4dc78e53SAndroid Build Coastguard Worker * @return _NLE_OPNOTSUPP Link info operations not registered.
160*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_BUSY Link info operations still in use.
161*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_unregister_info(struct rtnl_link_info_ops * ops)162*4dc78e53SAndroid Build Coastguard Worker int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
163*4dc78e53SAndroid Build Coastguard Worker {
164*4dc78e53SAndroid Build Coastguard Worker struct rtnl_link_info_ops *t;
165*4dc78e53SAndroid Build Coastguard Worker int err = -NLE_OPNOTSUPP;
166*4dc78e53SAndroid Build Coastguard Worker
167*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
168*4dc78e53SAndroid Build Coastguard Worker
169*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry(t, &info_ops, io_list) {
170*4dc78e53SAndroid Build Coastguard Worker if (t == ops) {
171*4dc78e53SAndroid Build Coastguard Worker _nl_assert(t->io_refcnt >= 0);
172*4dc78e53SAndroid Build Coastguard Worker if (t->io_refcnt > 0) {
173*4dc78e53SAndroid Build Coastguard Worker err = -NLE_BUSY;
174*4dc78e53SAndroid Build Coastguard Worker goto errout;
175*4dc78e53SAndroid Build Coastguard Worker }
176*4dc78e53SAndroid Build Coastguard Worker
177*4dc78e53SAndroid Build Coastguard Worker nl_list_del(&t->io_list);
178*4dc78e53SAndroid Build Coastguard Worker
179*4dc78e53SAndroid Build Coastguard Worker NL_DBG(1, "Unregistered link info operations %s\n",
180*4dc78e53SAndroid Build Coastguard Worker ops->io_name);
181*4dc78e53SAndroid Build Coastguard Worker err = 0;
182*4dc78e53SAndroid Build Coastguard Worker goto errout;
183*4dc78e53SAndroid Build Coastguard Worker }
184*4dc78e53SAndroid Build Coastguard Worker }
185*4dc78e53SAndroid Build Coastguard Worker
186*4dc78e53SAndroid Build Coastguard Worker errout:
187*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
188*4dc78e53SAndroid Build Coastguard Worker
189*4dc78e53SAndroid Build Coastguard Worker return err;
190*4dc78e53SAndroid Build Coastguard Worker }
191*4dc78e53SAndroid Build Coastguard Worker
192*4dc78e53SAndroid Build Coastguard Worker /** @} */
193*4dc78e53SAndroid Build Coastguard Worker
194*4dc78e53SAndroid Build Coastguard Worker /**
195*4dc78e53SAndroid Build Coastguard Worker * @name Link Address Family Modules
196*4dc78e53SAndroid Build Coastguard Worker * @{
197*4dc78e53SAndroid Build Coastguard Worker */
198*4dc78e53SAndroid Build Coastguard Worker
199*4dc78e53SAndroid Build Coastguard Worker static struct rtnl_link_af_ops *af_ops[AF_MAX];
200*4dc78e53SAndroid Build Coastguard Worker
201*4dc78e53SAndroid Build Coastguard Worker /**
202*4dc78e53SAndroid Build Coastguard Worker * Return operations of a specific link address family
203*4dc78e53SAndroid Build Coastguard Worker * @arg family Address family
204*4dc78e53SAndroid Build Coastguard Worker *
205*4dc78e53SAndroid Build Coastguard Worker * @note The returned pointer must be given back using rtnl_link_af_ops_put()
206*4dc78e53SAndroid Build Coastguard Worker *
207*4dc78e53SAndroid Build Coastguard Worker * @return Pointer to operations or NULL if unavailable.
208*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_ops_lookup(const unsigned int family)209*4dc78e53SAndroid Build Coastguard Worker struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
210*4dc78e53SAndroid Build Coastguard Worker {
211*4dc78e53SAndroid Build Coastguard Worker if (family == AF_UNSPEC || family >= AF_MAX)
212*4dc78e53SAndroid Build Coastguard Worker return NULL;
213*4dc78e53SAndroid Build Coastguard Worker
214*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
215*4dc78e53SAndroid Build Coastguard Worker if (af_ops[family])
216*4dc78e53SAndroid Build Coastguard Worker af_ops[family]->ao_refcnt++;
217*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
218*4dc78e53SAndroid Build Coastguard Worker
219*4dc78e53SAndroid Build Coastguard Worker return af_ops[family];
220*4dc78e53SAndroid Build Coastguard Worker }
221*4dc78e53SAndroid Build Coastguard Worker
222*4dc78e53SAndroid Build Coastguard Worker /**
223*4dc78e53SAndroid Build Coastguard Worker * Give back reference to a set of operations.
224*4dc78e53SAndroid Build Coastguard Worker * @arg ops Address family operations.
225*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_ops_put(struct rtnl_link_af_ops * ops)226*4dc78e53SAndroid Build Coastguard Worker void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
227*4dc78e53SAndroid Build Coastguard Worker {
228*4dc78e53SAndroid Build Coastguard Worker if (ops) {
229*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
230*4dc78e53SAndroid Build Coastguard Worker ops->ao_refcnt--;
231*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
232*4dc78e53SAndroid Build Coastguard Worker }
233*4dc78e53SAndroid Build Coastguard Worker }
234*4dc78e53SAndroid Build Coastguard Worker
235*4dc78e53SAndroid Build Coastguard Worker /**
236*4dc78e53SAndroid Build Coastguard Worker * Allocate and return data buffer for link address family modules
237*4dc78e53SAndroid Build Coastguard Worker * @arg link Link object
238*4dc78e53SAndroid Build Coastguard Worker * @arg ops Address family operations
239*4dc78e53SAndroid Build Coastguard Worker *
240*4dc78e53SAndroid Build Coastguard Worker * This function must be called by link address family modules in all
241*4dc78e53SAndroid Build Coastguard Worker * cases where the API does not provide the data buffer as argument
242*4dc78e53SAndroid Build Coastguard Worker * already. This typically includes set functions the module provides.
243*4dc78e53SAndroid Build Coastguard Worker * Calling this function is strictly required to ensure proper allocation
244*4dc78e53SAndroid Build Coastguard Worker * of the buffer upon first use. Link objects will NOT proactively
245*4dc78e53SAndroid Build Coastguard Worker * allocate a data buffer for each registered link address family.
246*4dc78e53SAndroid Build Coastguard Worker *
247*4dc78e53SAndroid Build Coastguard Worker * @return Pointer to data buffer or NULL on error.
248*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_alloc(struct rtnl_link * link,const struct rtnl_link_af_ops * ops)249*4dc78e53SAndroid Build Coastguard Worker void *rtnl_link_af_alloc(struct rtnl_link *link,
250*4dc78e53SAndroid Build Coastguard Worker const struct rtnl_link_af_ops *ops)
251*4dc78e53SAndroid Build Coastguard Worker {
252*4dc78e53SAndroid Build Coastguard Worker int family;
253*4dc78e53SAndroid Build Coastguard Worker
254*4dc78e53SAndroid Build Coastguard Worker if (!link || !ops)
255*4dc78e53SAndroid Build Coastguard Worker BUG();
256*4dc78e53SAndroid Build Coastguard Worker
257*4dc78e53SAndroid Build Coastguard Worker family = ops->ao_family;
258*4dc78e53SAndroid Build Coastguard Worker
259*4dc78e53SAndroid Build Coastguard Worker if (!link->l_af_data[family]) {
260*4dc78e53SAndroid Build Coastguard Worker if (!ops->ao_alloc)
261*4dc78e53SAndroid Build Coastguard Worker BUG();
262*4dc78e53SAndroid Build Coastguard Worker
263*4dc78e53SAndroid Build Coastguard Worker link->l_af_data[family] = ops->ao_alloc(link);
264*4dc78e53SAndroid Build Coastguard Worker if (!link->l_af_data[family])
265*4dc78e53SAndroid Build Coastguard Worker return NULL;
266*4dc78e53SAndroid Build Coastguard Worker }
267*4dc78e53SAndroid Build Coastguard Worker
268*4dc78e53SAndroid Build Coastguard Worker return link->l_af_data[family];
269*4dc78e53SAndroid Build Coastguard Worker }
270*4dc78e53SAndroid Build Coastguard Worker
271*4dc78e53SAndroid Build Coastguard Worker /**
272*4dc78e53SAndroid Build Coastguard Worker * Return data buffer for link address family modules
273*4dc78e53SAndroid Build Coastguard Worker * @arg link Link object
274*4dc78e53SAndroid Build Coastguard Worker * @arg ops Address family operations
275*4dc78e53SAndroid Build Coastguard Worker *
276*4dc78e53SAndroid Build Coastguard Worker * This function returns a pointer to the data buffer for the specified link
277*4dc78e53SAndroid Build Coastguard Worker * address family module or NULL if the buffer was not allocated yet. This
278*4dc78e53SAndroid Build Coastguard Worker * function is typically used by get functions of modules which are not
279*4dc78e53SAndroid Build Coastguard Worker * interested in having the data buffer allocated if no values have been set
280*4dc78e53SAndroid Build Coastguard Worker * yet.
281*4dc78e53SAndroid Build Coastguard Worker *
282*4dc78e53SAndroid Build Coastguard Worker * @return Pointer to data buffer or NULL on error.
283*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_data(const struct rtnl_link * link,const struct rtnl_link_af_ops * ops)284*4dc78e53SAndroid Build Coastguard Worker void *rtnl_link_af_data(const struct rtnl_link *link,
285*4dc78e53SAndroid Build Coastguard Worker const struct rtnl_link_af_ops *ops)
286*4dc78e53SAndroid Build Coastguard Worker {
287*4dc78e53SAndroid Build Coastguard Worker if (!link || !ops)
288*4dc78e53SAndroid Build Coastguard Worker BUG();
289*4dc78e53SAndroid Build Coastguard Worker
290*4dc78e53SAndroid Build Coastguard Worker return link->l_af_data[ops->ao_family];
291*4dc78e53SAndroid Build Coastguard Worker }
292*4dc78e53SAndroid Build Coastguard Worker
293*4dc78e53SAndroid Build Coastguard Worker /**
294*4dc78e53SAndroid Build Coastguard Worker * Register operations for a link address family
295*4dc78e53SAndroid Build Coastguard Worker * @arg ops Address family operations
296*4dc78e53SAndroid Build Coastguard Worker *
297*4dc78e53SAndroid Build Coastguard Worker * This function must be called by modules implementing a specific link
298*4dc78e53SAndroid Build Coastguard Worker * address family. It will make the operations implemented by the module
299*4dc78e53SAndroid Build Coastguard Worker * available for everyone else.
300*4dc78e53SAndroid Build Coastguard Worker *
301*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code.
302*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_INVAL Address family is out of range (0..AF_MAX)
303*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_EXIST Operations for address family already registered.
304*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_register(struct rtnl_link_af_ops * ops)305*4dc78e53SAndroid Build Coastguard Worker int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
306*4dc78e53SAndroid Build Coastguard Worker {
307*4dc78e53SAndroid Build Coastguard Worker int err = 0;
308*4dc78e53SAndroid Build Coastguard Worker
309*4dc78e53SAndroid Build Coastguard Worker if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
310*4dc78e53SAndroid Build Coastguard Worker return -NLE_INVAL;
311*4dc78e53SAndroid Build Coastguard Worker
312*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
313*4dc78e53SAndroid Build Coastguard Worker if (af_ops[ops->ao_family]) {
314*4dc78e53SAndroid Build Coastguard Worker err = -NLE_EXIST;
315*4dc78e53SAndroid Build Coastguard Worker goto errout;
316*4dc78e53SAndroid Build Coastguard Worker }
317*4dc78e53SAndroid Build Coastguard Worker
318*4dc78e53SAndroid Build Coastguard Worker ops->ao_refcnt = 0;
319*4dc78e53SAndroid Build Coastguard Worker af_ops[ops->ao_family] = ops;
320*4dc78e53SAndroid Build Coastguard Worker
321*4dc78e53SAndroid Build Coastguard Worker NL_DBG(1, "Registered link address family operations %u\n",
322*4dc78e53SAndroid Build Coastguard Worker ops->ao_family);
323*4dc78e53SAndroid Build Coastguard Worker
324*4dc78e53SAndroid Build Coastguard Worker errout:
325*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
326*4dc78e53SAndroid Build Coastguard Worker
327*4dc78e53SAndroid Build Coastguard Worker return err;
328*4dc78e53SAndroid Build Coastguard Worker }
329*4dc78e53SAndroid Build Coastguard Worker
330*4dc78e53SAndroid Build Coastguard Worker /**
331*4dc78e53SAndroid Build Coastguard Worker * Unregister operations for a link address family
332*4dc78e53SAndroid Build Coastguard Worker * @arg ops Address family operations
333*4dc78e53SAndroid Build Coastguard Worker *
334*4dc78e53SAndroid Build Coastguard Worker * This function must be called if a module implementing a specific link
335*4dc78e53SAndroid Build Coastguard Worker * address family is unloaded or becomes unavailable. It must provide a
336*4dc78e53SAndroid Build Coastguard Worker * set of operations which have previously been registered using
337*4dc78e53SAndroid Build Coastguard Worker * rtnl_link_af_register().
338*4dc78e53SAndroid Build Coastguard Worker *
339*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code
340*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_INVAL ops is NULL
341*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
342*4dc78e53SAndroid Build Coastguard Worker * @return -NLE_BUSY Address family operations still in use.
343*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_unregister(struct rtnl_link_af_ops * ops)344*4dc78e53SAndroid Build Coastguard Worker int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
345*4dc78e53SAndroid Build Coastguard Worker {
346*4dc78e53SAndroid Build Coastguard Worker int err = -NLE_INVAL;
347*4dc78e53SAndroid Build Coastguard Worker
348*4dc78e53SAndroid Build Coastguard Worker if (!ops)
349*4dc78e53SAndroid Build Coastguard Worker return err;
350*4dc78e53SAndroid Build Coastguard Worker
351*4dc78e53SAndroid Build Coastguard Worker nl_write_lock(&info_lock);
352*4dc78e53SAndroid Build Coastguard Worker if (!af_ops[ops->ao_family]) {
353*4dc78e53SAndroid Build Coastguard Worker err = -NLE_OBJ_NOTFOUND;
354*4dc78e53SAndroid Build Coastguard Worker goto errout;
355*4dc78e53SAndroid Build Coastguard Worker }
356*4dc78e53SAndroid Build Coastguard Worker
357*4dc78e53SAndroid Build Coastguard Worker if (ops->ao_refcnt > 0) {
358*4dc78e53SAndroid Build Coastguard Worker err = -NLE_BUSY;
359*4dc78e53SAndroid Build Coastguard Worker goto errout;
360*4dc78e53SAndroid Build Coastguard Worker }
361*4dc78e53SAndroid Build Coastguard Worker
362*4dc78e53SAndroid Build Coastguard Worker af_ops[ops->ao_family] = NULL;
363*4dc78e53SAndroid Build Coastguard Worker
364*4dc78e53SAndroid Build Coastguard Worker NL_DBG(1, "Unregistered link address family operations %u\n",
365*4dc78e53SAndroid Build Coastguard Worker ops->ao_family);
366*4dc78e53SAndroid Build Coastguard Worker
367*4dc78e53SAndroid Build Coastguard Worker errout:
368*4dc78e53SAndroid Build Coastguard Worker nl_write_unlock(&info_lock);
369*4dc78e53SAndroid Build Coastguard Worker
370*4dc78e53SAndroid Build Coastguard Worker return err;
371*4dc78e53SAndroid Build Coastguard Worker }
372*4dc78e53SAndroid Build Coastguard Worker
373*4dc78e53SAndroid Build Coastguard Worker /**
374*4dc78e53SAndroid Build Coastguard Worker * Compare af data for a link address family
375*4dc78e53SAndroid Build Coastguard Worker * @arg a Link object a
376*4dc78e53SAndroid Build Coastguard Worker * @arg b Link object b
377*4dc78e53SAndroid Build Coastguard Worker * @arg family af data family
378*4dc78e53SAndroid Build Coastguard Worker *
379*4dc78e53SAndroid Build Coastguard Worker * This function will compare af_data between two links
380*4dc78e53SAndroid Build Coastguard Worker * a and b of family given by arg family
381*4dc78e53SAndroid Build Coastguard Worker *
382*4dc78e53SAndroid Build Coastguard Worker * @return 0 if address family specific data matches or is not present
383*4dc78e53SAndroid Build Coastguard Worker * or != 0 if it mismatches.
384*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_af_data_compare(struct rtnl_link * a,struct rtnl_link * b,int family)385*4dc78e53SAndroid Build Coastguard Worker int rtnl_link_af_data_compare(struct rtnl_link *a, struct rtnl_link *b,
386*4dc78e53SAndroid Build Coastguard Worker int family)
387*4dc78e53SAndroid Build Coastguard Worker {
388*4dc78e53SAndroid Build Coastguard Worker struct rtnl_link_af_ops *af_ops;
389*4dc78e53SAndroid Build Coastguard Worker int ret = 0;
390*4dc78e53SAndroid Build Coastguard Worker
391*4dc78e53SAndroid Build Coastguard Worker if (!a->l_af_data[family] && !b->l_af_data[family])
392*4dc78e53SAndroid Build Coastguard Worker return 0;
393*4dc78e53SAndroid Build Coastguard Worker
394*4dc78e53SAndroid Build Coastguard Worker if (!a->l_af_data[family] || !b->l_af_data[family])
395*4dc78e53SAndroid Build Coastguard Worker return ~0;
396*4dc78e53SAndroid Build Coastguard Worker
397*4dc78e53SAndroid Build Coastguard Worker af_ops = rtnl_link_af_ops_lookup(family);
398*4dc78e53SAndroid Build Coastguard Worker if (!af_ops)
399*4dc78e53SAndroid Build Coastguard Worker return ~0;
400*4dc78e53SAndroid Build Coastguard Worker
401*4dc78e53SAndroid Build Coastguard Worker if (af_ops->ao_compare == NULL) {
402*4dc78e53SAndroid Build Coastguard Worker ret = ~0;
403*4dc78e53SAndroid Build Coastguard Worker goto out;
404*4dc78e53SAndroid Build Coastguard Worker }
405*4dc78e53SAndroid Build Coastguard Worker
406*4dc78e53SAndroid Build Coastguard Worker ret = af_ops->ao_compare(a, b, family, ~0, 0);
407*4dc78e53SAndroid Build Coastguard Worker
408*4dc78e53SAndroid Build Coastguard Worker out:
409*4dc78e53SAndroid Build Coastguard Worker rtnl_link_af_ops_put(af_ops);
410*4dc78e53SAndroid Build Coastguard Worker
411*4dc78e53SAndroid Build Coastguard Worker return ret;
412*4dc78e53SAndroid Build Coastguard Worker }
413*4dc78e53SAndroid Build Coastguard Worker
414*4dc78e53SAndroid Build Coastguard Worker /**
415*4dc78e53SAndroid Build Coastguard Worker * Compare link info data
416*4dc78e53SAndroid Build Coastguard Worker * @arg a Link object a
417*4dc78e53SAndroid Build Coastguard Worker * @arg b Link object b
418*4dc78e53SAndroid Build Coastguard Worker *
419*4dc78e53SAndroid Build Coastguard Worker * This function will compare link_info data between two links
420*4dc78e53SAndroid Build Coastguard Worker * a and b
421*4dc78e53SAndroid Build Coastguard Worker *
422*4dc78e53SAndroid Build Coastguard Worker * @return 0 if link_info data matches or is not present
423*4dc78e53SAndroid Build Coastguard Worker * or != 0 if it mismatches.
424*4dc78e53SAndroid Build Coastguard Worker */
rtnl_link_info_data_compare(struct rtnl_link * a,struct rtnl_link * b,int flags)425*4dc78e53SAndroid Build Coastguard Worker int rtnl_link_info_data_compare(struct rtnl_link *a, struct rtnl_link *b, int flags)
426*4dc78e53SAndroid Build Coastguard Worker {
427*4dc78e53SAndroid Build Coastguard Worker if (a->l_info_ops != b->l_info_ops)
428*4dc78e53SAndroid Build Coastguard Worker return ~0;
429*4dc78e53SAndroid Build Coastguard Worker
430*4dc78e53SAndroid Build Coastguard Worker if (!a->l_info_ops || !a->l_info_ops->io_compare)
431*4dc78e53SAndroid Build Coastguard Worker return 0;
432*4dc78e53SAndroid Build Coastguard Worker
433*4dc78e53SAndroid Build Coastguard Worker return a->l_info_ops->io_compare(a, b, flags);
434*4dc78e53SAndroid Build Coastguard Worker }
435*4dc78e53SAndroid Build Coastguard Worker
436*4dc78e53SAndroid Build Coastguard Worker /** @} */
437*4dc78e53SAndroid Build Coastguard Worker
438*4dc78e53SAndroid Build Coastguard Worker /** @} */
439*4dc78e53SAndroid Build Coastguard Worker
440