xref: /aosp_15_r20/external/libnl/lib/cache.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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-2012 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 cache_mngt
8*4dc78e53SAndroid Build Coastguard Worker  * @defgroup cache Cache
9*4dc78e53SAndroid Build Coastguard Worker  *
10*4dc78e53SAndroid Build Coastguard Worker  * @code
11*4dc78e53SAndroid Build Coastguard Worker  *   Cache Management             |    | Type Specific Cache Operations
12*4dc78e53SAndroid Build Coastguard Worker  *
13*4dc78e53SAndroid Build Coastguard Worker  *                                |    | +----------------+ +------------+
14*4dc78e53SAndroid Build Coastguard Worker  *                                       | request update | | msg_parser |
15*4dc78e53SAndroid Build Coastguard Worker  *                                |    | +----------------+ +------------+
16*4dc78e53SAndroid Build Coastguard Worker  *                                     +- - - - -^- - - - - - - -^- -|- - - -
17*4dc78e53SAndroid Build Coastguard Worker  *    nl_cache_update:            |              |               |   |
18*4dc78e53SAndroid Build Coastguard Worker  *          1) --------- co_request_update ------+               |   |
19*4dc78e53SAndroid Build Coastguard Worker  *                                |                              |   |
20*4dc78e53SAndroid Build Coastguard Worker  *          2) destroy old cache     +----------- pp_cb ---------|---+
21*4dc78e53SAndroid Build Coastguard Worker  *                                |  |                           |
22*4dc78e53SAndroid Build Coastguard Worker  *          3) ---------- nl_recvmsgs ----------+   +- cb_valid -+
23*4dc78e53SAndroid Build Coastguard Worker  *             +--------------+   |  |          |   |
24*4dc78e53SAndroid Build Coastguard Worker  *             | nl_cache_add |<-----+   + - - -v- -|- - - - - - - - - - -
25*4dc78e53SAndroid Build Coastguard Worker  *             +--------------+   |      | +-------------+
26*4dc78e53SAndroid Build Coastguard Worker  *                                         | nl_recvmsgs |
27*4dc78e53SAndroid Build Coastguard Worker  *                                |      | +-----|-^-----+
28*4dc78e53SAndroid Build Coastguard Worker  *                                           +---v-|---+
29*4dc78e53SAndroid Build Coastguard Worker  *                                |      |   | nl_recv |
30*4dc78e53SAndroid Build Coastguard Worker  *                                           +---------+
31*4dc78e53SAndroid Build Coastguard Worker  *                                |      |                 Core Netlink
32*4dc78e53SAndroid Build Coastguard Worker  * @endcode
33*4dc78e53SAndroid Build Coastguard Worker  *
34*4dc78e53SAndroid Build Coastguard Worker  * Related sections in the development guide:
35*4dc78e53SAndroid Build Coastguard Worker  * - @core_doc{core_cache, Caching System}
36*4dc78e53SAndroid Build Coastguard Worker  *
37*4dc78e53SAndroid Build Coastguard Worker  * @{
38*4dc78e53SAndroid Build Coastguard Worker  *
39*4dc78e53SAndroid Build Coastguard Worker  * Header
40*4dc78e53SAndroid Build Coastguard Worker  * ------
41*4dc78e53SAndroid Build Coastguard Worker  * ~~~~{.c}
42*4dc78e53SAndroid Build Coastguard Worker  * #include <netlink/cache.h>
43*4dc78e53SAndroid Build Coastguard Worker  * ~~~~
44*4dc78e53SAndroid Build Coastguard Worker  */
45*4dc78e53SAndroid Build Coastguard Worker 
46*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
47*4dc78e53SAndroid Build Coastguard Worker 
48*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
49*4dc78e53SAndroid Build Coastguard Worker #include <netlink/cache.h>
50*4dc78e53SAndroid Build Coastguard Worker #include <netlink/object.h>
51*4dc78e53SAndroid Build Coastguard Worker #include <netlink/hashtable.h>
52*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
53*4dc78e53SAndroid Build Coastguard Worker 
54*4dc78e53SAndroid Build Coastguard Worker #include "nl-core.h"
55*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/nl-core.h"
56*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/object-api.h"
57*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/cache-api.h"
58*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-core/nl-core.h"
59*4dc78e53SAndroid Build Coastguard Worker 
60*4dc78e53SAndroid Build Coastguard Worker /**
61*4dc78e53SAndroid Build Coastguard Worker  * @name Access Functions
62*4dc78e53SAndroid Build Coastguard Worker  * @{
63*4dc78e53SAndroid Build Coastguard Worker  */
64*4dc78e53SAndroid Build Coastguard Worker 
65*4dc78e53SAndroid Build Coastguard Worker /**
66*4dc78e53SAndroid Build Coastguard Worker  * Return the number of items in the cache
67*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache handle
68*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_nitems(struct nl_cache * cache)69*4dc78e53SAndroid Build Coastguard Worker int nl_cache_nitems(struct nl_cache *cache)
70*4dc78e53SAndroid Build Coastguard Worker {
71*4dc78e53SAndroid Build Coastguard Worker 	return cache->c_nitems;
72*4dc78e53SAndroid Build Coastguard Worker }
73*4dc78e53SAndroid Build Coastguard Worker 
74*4dc78e53SAndroid Build Coastguard Worker /**
75*4dc78e53SAndroid Build Coastguard Worker  * Return the number of items matching a filter in the cache
76*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache object.
77*4dc78e53SAndroid Build Coastguard Worker  * @arg filter		Filter object.
78*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_nitems_filter(struct nl_cache * cache,struct nl_object * filter)79*4dc78e53SAndroid Build Coastguard Worker int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
80*4dc78e53SAndroid Build Coastguard Worker {
81*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
82*4dc78e53SAndroid Build Coastguard Worker 	int nitems = 0;
83*4dc78e53SAndroid Build Coastguard Worker 
84*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops == NULL)
85*4dc78e53SAndroid Build Coastguard Worker 		BUG();
86*4dc78e53SAndroid Build Coastguard Worker 
87*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
88*4dc78e53SAndroid Build Coastguard Worker 		if (filter && !nl_object_match_filter(obj, filter))
89*4dc78e53SAndroid Build Coastguard Worker 			continue;
90*4dc78e53SAndroid Build Coastguard Worker 
91*4dc78e53SAndroid Build Coastguard Worker 		nitems++;
92*4dc78e53SAndroid Build Coastguard Worker 	}
93*4dc78e53SAndroid Build Coastguard Worker 
94*4dc78e53SAndroid Build Coastguard Worker 	return nitems;
95*4dc78e53SAndroid Build Coastguard Worker }
96*4dc78e53SAndroid Build Coastguard Worker 
97*4dc78e53SAndroid Build Coastguard Worker /**
98*4dc78e53SAndroid Build Coastguard Worker  * Returns \b true if the cache is empty.
99*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache to check
100*4dc78e53SAndroid Build Coastguard Worker  * @return \a true if the cache is empty, otherwise \b false is returned.
101*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_is_empty(struct nl_cache * cache)102*4dc78e53SAndroid Build Coastguard Worker int nl_cache_is_empty(struct nl_cache *cache)
103*4dc78e53SAndroid Build Coastguard Worker {
104*4dc78e53SAndroid Build Coastguard Worker 	return nl_list_empty(&cache->c_items);
105*4dc78e53SAndroid Build Coastguard Worker }
106*4dc78e53SAndroid Build Coastguard Worker 
107*4dc78e53SAndroid Build Coastguard Worker /**
108*4dc78e53SAndroid Build Coastguard Worker  * Return the operations set of the cache
109*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache handle
110*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_get_ops(struct nl_cache * cache)111*4dc78e53SAndroid Build Coastguard Worker struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache)
112*4dc78e53SAndroid Build Coastguard Worker {
113*4dc78e53SAndroid Build Coastguard Worker 	return cache->c_ops;
114*4dc78e53SAndroid Build Coastguard Worker }
115*4dc78e53SAndroid Build Coastguard Worker 
116*4dc78e53SAndroid Build Coastguard Worker /**
117*4dc78e53SAndroid Build Coastguard Worker  * Return the first element in the cache
118*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache handle
119*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_get_first(struct nl_cache * cache)120*4dc78e53SAndroid Build Coastguard Worker struct nl_object *nl_cache_get_first(struct nl_cache *cache)
121*4dc78e53SAndroid Build Coastguard Worker {
122*4dc78e53SAndroid Build Coastguard Worker 	if (nl_list_empty(&cache->c_items))
123*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
124*4dc78e53SAndroid Build Coastguard Worker 
125*4dc78e53SAndroid Build Coastguard Worker 	return nl_list_entry(cache->c_items.next,
126*4dc78e53SAndroid Build Coastguard Worker 			     struct nl_object, ce_list);
127*4dc78e53SAndroid Build Coastguard Worker }
128*4dc78e53SAndroid Build Coastguard Worker 
129*4dc78e53SAndroid Build Coastguard Worker /**
130*4dc78e53SAndroid Build Coastguard Worker  * Return the last element in the cache
131*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache handle
132*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_get_last(struct nl_cache * cache)133*4dc78e53SAndroid Build Coastguard Worker struct nl_object *nl_cache_get_last(struct nl_cache *cache)
134*4dc78e53SAndroid Build Coastguard Worker {
135*4dc78e53SAndroid Build Coastguard Worker 	if (nl_list_empty(&cache->c_items))
136*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
137*4dc78e53SAndroid Build Coastguard Worker 
138*4dc78e53SAndroid Build Coastguard Worker 	return nl_list_entry(cache->c_items.prev,
139*4dc78e53SAndroid Build Coastguard Worker 			     struct nl_object, ce_list);
140*4dc78e53SAndroid Build Coastguard Worker }
141*4dc78e53SAndroid Build Coastguard Worker 
142*4dc78e53SAndroid Build Coastguard Worker /**
143*4dc78e53SAndroid Build Coastguard Worker  * Return the next element in the cache
144*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		current object
145*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_get_next(struct nl_object * obj)146*4dc78e53SAndroid Build Coastguard Worker struct nl_object *nl_cache_get_next(struct nl_object *obj)
147*4dc78e53SAndroid Build Coastguard Worker {
148*4dc78e53SAndroid Build Coastguard Worker 	if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list))
149*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
150*4dc78e53SAndroid Build Coastguard Worker 	else
151*4dc78e53SAndroid Build Coastguard Worker 		return nl_list_entry(obj->ce_list.next,
152*4dc78e53SAndroid Build Coastguard Worker 				     struct nl_object, ce_list);
153*4dc78e53SAndroid Build Coastguard Worker }
154*4dc78e53SAndroid Build Coastguard Worker 
155*4dc78e53SAndroid Build Coastguard Worker /**
156*4dc78e53SAndroid Build Coastguard Worker  * Return the previous element in the cache
157*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		current object
158*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_get_prev(struct nl_object * obj)159*4dc78e53SAndroid Build Coastguard Worker struct nl_object *nl_cache_get_prev(struct nl_object *obj)
160*4dc78e53SAndroid Build Coastguard Worker {
161*4dc78e53SAndroid Build Coastguard Worker 	if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list))
162*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
163*4dc78e53SAndroid Build Coastguard Worker 	else
164*4dc78e53SAndroid Build Coastguard Worker 		return nl_list_entry(obj->ce_list.prev,
165*4dc78e53SAndroid Build Coastguard Worker 				     struct nl_object, ce_list);
166*4dc78e53SAndroid Build Coastguard Worker }
167*4dc78e53SAndroid Build Coastguard Worker 
168*4dc78e53SAndroid Build Coastguard Worker /** @} */
169*4dc78e53SAndroid Build Coastguard Worker 
170*4dc78e53SAndroid Build Coastguard Worker /**
171*4dc78e53SAndroid Build Coastguard Worker  * @name Cache Allocation/Deletion
172*4dc78e53SAndroid Build Coastguard Worker  * @{
173*4dc78e53SAndroid Build Coastguard Worker  */
174*4dc78e53SAndroid Build Coastguard Worker 
175*4dc78e53SAndroid Build Coastguard Worker /**
176*4dc78e53SAndroid Build Coastguard Worker  * Allocate new cache
177*4dc78e53SAndroid Build Coastguard Worker  * @arg ops		Cache operations
178*4dc78e53SAndroid Build Coastguard Worker  *
179*4dc78e53SAndroid Build Coastguard Worker  * Allocate and initialize a new cache based on the cache operations
180*4dc78e53SAndroid Build Coastguard Worker  * provided.
181*4dc78e53SAndroid Build Coastguard Worker  *
182*4dc78e53SAndroid Build Coastguard Worker  * @return Allocated cache or NULL if allocation failed.
183*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_alloc(struct nl_cache_ops * ops)184*4dc78e53SAndroid Build Coastguard Worker struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops)
185*4dc78e53SAndroid Build Coastguard Worker {
186*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache;
187*4dc78e53SAndroid Build Coastguard Worker 
188*4dc78e53SAndroid Build Coastguard Worker 	cache = calloc(1, sizeof(*cache));
189*4dc78e53SAndroid Build Coastguard Worker 	if (!cache)
190*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
191*4dc78e53SAndroid Build Coastguard Worker 
192*4dc78e53SAndroid Build Coastguard Worker 	nl_init_list_head(&cache->c_items);
193*4dc78e53SAndroid Build Coastguard Worker 	cache->c_ops = ops;
194*4dc78e53SAndroid Build Coastguard Worker 	cache->c_flags |= ops->co_flags;
195*4dc78e53SAndroid Build Coastguard Worker 	cache->c_refcnt = 1;
196*4dc78e53SAndroid Build Coastguard Worker 
197*4dc78e53SAndroid Build Coastguard Worker 	/*
198*4dc78e53SAndroid Build Coastguard Worker 	 * If object type provides a hash keygen
199*4dc78e53SAndroid Build Coastguard Worker 	 * functions, allocate a hash table for the
200*4dc78e53SAndroid Build Coastguard Worker 	 * cache objects for faster lookups
201*4dc78e53SAndroid Build Coastguard Worker 	 */
202*4dc78e53SAndroid Build Coastguard Worker 	if (ops->co_obj_ops->oo_keygen) {
203*4dc78e53SAndroid Build Coastguard Worker 		int hashtable_size;
204*4dc78e53SAndroid Build Coastguard Worker 
205*4dc78e53SAndroid Build Coastguard Worker 		if (ops->co_hash_size)
206*4dc78e53SAndroid Build Coastguard Worker 			hashtable_size = ops->co_hash_size;
207*4dc78e53SAndroid Build Coastguard Worker 		else
208*4dc78e53SAndroid Build Coastguard Worker 			hashtable_size = NL_MAX_HASH_ENTRIES;
209*4dc78e53SAndroid Build Coastguard Worker 
210*4dc78e53SAndroid Build Coastguard Worker 		cache->hashtable = nl_hash_table_alloc(hashtable_size);
211*4dc78e53SAndroid Build Coastguard Worker 	}
212*4dc78e53SAndroid Build Coastguard Worker 
213*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
214*4dc78e53SAndroid Build Coastguard Worker 
215*4dc78e53SAndroid Build Coastguard Worker 	return cache;
216*4dc78e53SAndroid Build Coastguard Worker }
217*4dc78e53SAndroid Build Coastguard Worker 
218*4dc78e53SAndroid Build Coastguard Worker /**
219*4dc78e53SAndroid Build Coastguard Worker  * Allocate new cache and fill it
220*4dc78e53SAndroid Build Coastguard Worker  * @arg ops		Cache operations
221*4dc78e53SAndroid Build Coastguard Worker  * @arg sock		Netlink socket
222*4dc78e53SAndroid Build Coastguard Worker  * @arg result		Result pointer
223*4dc78e53SAndroid Build Coastguard Worker  *
224*4dc78e53SAndroid Build Coastguard Worker  * Allocate new cache and fill it. Equivalent to calling:
225*4dc78e53SAndroid Build Coastguard Worker  * @code
226*4dc78e53SAndroid Build Coastguard Worker  * cache = nl_cache_alloc(ops);
227*4dc78e53SAndroid Build Coastguard Worker  * nl_cache_refill(sock, cache);
228*4dc78e53SAndroid Build Coastguard Worker  * @endcode
229*4dc78e53SAndroid Build Coastguard Worker  *
230*4dc78e53SAndroid Build Coastguard Worker  * @see nl_cache_alloc
231*4dc78e53SAndroid Build Coastguard Worker  *
232*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
233*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_alloc_and_fill(struct nl_cache_ops * ops,struct nl_sock * sock,struct nl_cache ** result)234*4dc78e53SAndroid Build Coastguard Worker int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock,
235*4dc78e53SAndroid Build Coastguard Worker 			    struct nl_cache **result)
236*4dc78e53SAndroid Build Coastguard Worker {
237*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache;
238*4dc78e53SAndroid Build Coastguard Worker 	int err;
239*4dc78e53SAndroid Build Coastguard Worker 
240*4dc78e53SAndroid Build Coastguard Worker 	if (!(cache = nl_cache_alloc(ops)))
241*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
242*4dc78e53SAndroid Build Coastguard Worker 
243*4dc78e53SAndroid Build Coastguard Worker 	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
244*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_free(cache);
245*4dc78e53SAndroid Build Coastguard Worker 		return err;
246*4dc78e53SAndroid Build Coastguard Worker 	}
247*4dc78e53SAndroid Build Coastguard Worker 
248*4dc78e53SAndroid Build Coastguard Worker 	*result = cache;
249*4dc78e53SAndroid Build Coastguard Worker 	return 0;
250*4dc78e53SAndroid Build Coastguard Worker }
251*4dc78e53SAndroid Build Coastguard Worker 
252*4dc78e53SAndroid Build Coastguard Worker /**
253*4dc78e53SAndroid Build Coastguard Worker  * Allocate new cache based on type name
254*4dc78e53SAndroid Build Coastguard Worker  * @arg kind		Name of cache type
255*4dc78e53SAndroid Build Coastguard Worker  * @arg result		Result pointer
256*4dc78e53SAndroid Build Coastguard Worker  *
257*4dc78e53SAndroid Build Coastguard Worker  * Lookup cache ops via nl_cache_ops_lookup() and allocate the cache
258*4dc78e53SAndroid Build Coastguard Worker  * by calling nl_cache_alloc(). Stores the allocated cache in the
259*4dc78e53SAndroid Build Coastguard Worker  * result pointer provided.
260*4dc78e53SAndroid Build Coastguard Worker  *
261*4dc78e53SAndroid Build Coastguard Worker  * @see nl_cache_alloc
262*4dc78e53SAndroid Build Coastguard Worker  *
263*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
264*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_alloc_name(const char * kind,struct nl_cache ** result)265*4dc78e53SAndroid Build Coastguard Worker int nl_cache_alloc_name(const char *kind, struct nl_cache **result)
266*4dc78e53SAndroid Build Coastguard Worker {
267*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_ops *ops;
268*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache;
269*4dc78e53SAndroid Build Coastguard Worker 
270*4dc78e53SAndroid Build Coastguard Worker 	ops = nl_cache_ops_lookup_safe(kind);
271*4dc78e53SAndroid Build Coastguard Worker 	if (!ops)
272*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOCACHE;
273*4dc78e53SAndroid Build Coastguard Worker 
274*4dc78e53SAndroid Build Coastguard Worker 	cache = nl_cache_alloc(ops);
275*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_ops_put(ops);
276*4dc78e53SAndroid Build Coastguard Worker 	if (!cache)
277*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
278*4dc78e53SAndroid Build Coastguard Worker 
279*4dc78e53SAndroid Build Coastguard Worker 	*result = cache;
280*4dc78e53SAndroid Build Coastguard Worker 	return 0;
281*4dc78e53SAndroid Build Coastguard Worker }
282*4dc78e53SAndroid Build Coastguard Worker 
283*4dc78e53SAndroid Build Coastguard Worker /**
284*4dc78e53SAndroid Build Coastguard Worker  * Allocate new cache containing a subset of an existing cache
285*4dc78e53SAndroid Build Coastguard Worker  * @arg orig		Original cache to base new cache on
286*4dc78e53SAndroid Build Coastguard Worker  * @arg filter		Filter defining the subset to be filled into the new cache
287*4dc78e53SAndroid Build Coastguard Worker  *
288*4dc78e53SAndroid Build Coastguard Worker  * Allocates a new cache matching the type of the cache specified by
289*4dc78e53SAndroid Build Coastguard Worker  * \p orig. Iterates over the \p orig cache applying the specified
290*4dc78e53SAndroid Build Coastguard Worker  * \p filter and copies all objects that match to the new cache.
291*4dc78e53SAndroid Build Coastguard Worker  *
292*4dc78e53SAndroid Build Coastguard Worker  * The copied objects are clones but do not contain a reference to each
293*4dc78e53SAndroid Build Coastguard Worker  * other. Later modifications to objects in the original cache will
294*4dc78e53SAndroid Build Coastguard Worker  * not affect objects in the new cache.
295*4dc78e53SAndroid Build Coastguard Worker  *
296*4dc78e53SAndroid Build Coastguard Worker  * @return A newly allocated cache or NULL.
297*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_subset(struct nl_cache * orig,struct nl_object * filter)298*4dc78e53SAndroid Build Coastguard Worker struct nl_cache *nl_cache_subset(struct nl_cache *orig,
299*4dc78e53SAndroid Build Coastguard Worker 				 struct nl_object *filter)
300*4dc78e53SAndroid Build Coastguard Worker {
301*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache;
302*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
303*4dc78e53SAndroid Build Coastguard Worker 
304*4dc78e53SAndroid Build Coastguard Worker 	if (!filter)
305*4dc78e53SAndroid Build Coastguard Worker 		BUG();
306*4dc78e53SAndroid Build Coastguard Worker 
307*4dc78e53SAndroid Build Coastguard Worker 	cache = nl_cache_alloc(orig->c_ops);
308*4dc78e53SAndroid Build Coastguard Worker 	if (!cache)
309*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
310*4dc78e53SAndroid Build Coastguard Worker 
311*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Filling subset of cache %p <%s> with filter %p into %p\n",
312*4dc78e53SAndroid Build Coastguard Worker 	       orig, nl_cache_name(orig), filter, cache);
313*4dc78e53SAndroid Build Coastguard Worker 
314*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &orig->c_items, ce_list) {
315*4dc78e53SAndroid Build Coastguard Worker 		if (!nl_object_match_filter(obj, filter))
316*4dc78e53SAndroid Build Coastguard Worker 			continue;
317*4dc78e53SAndroid Build Coastguard Worker 
318*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_add(cache, obj);
319*4dc78e53SAndroid Build Coastguard Worker 	}
320*4dc78e53SAndroid Build Coastguard Worker 
321*4dc78e53SAndroid Build Coastguard Worker 	return cache;
322*4dc78e53SAndroid Build Coastguard Worker }
323*4dc78e53SAndroid Build Coastguard Worker 
324*4dc78e53SAndroid Build Coastguard Worker /**
325*4dc78e53SAndroid Build Coastguard Worker  * Allocate new cache and copy the contents of an existing cache
326*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Original cache to base new cache on
327*4dc78e53SAndroid Build Coastguard Worker  *
328*4dc78e53SAndroid Build Coastguard Worker  * Allocates a new cache matching the type of the cache specified by
329*4dc78e53SAndroid Build Coastguard Worker  * \p cache. Iterates over the \p cache cache and copies all objects
330*4dc78e53SAndroid Build Coastguard Worker  * to the new cache.
331*4dc78e53SAndroid Build Coastguard Worker  *
332*4dc78e53SAndroid Build Coastguard Worker  * The copied objects are clones but do not contain a reference to each
333*4dc78e53SAndroid Build Coastguard Worker  * other. Later modifications to objects in the original cache will
334*4dc78e53SAndroid Build Coastguard Worker  * not affect objects in the new cache.
335*4dc78e53SAndroid Build Coastguard Worker  *
336*4dc78e53SAndroid Build Coastguard Worker  * @return A newly allocated cache or NULL.
337*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_clone(struct nl_cache * cache)338*4dc78e53SAndroid Build Coastguard Worker struct nl_cache *nl_cache_clone(struct nl_cache *cache)
339*4dc78e53SAndroid Build Coastguard Worker {
340*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_ops *ops = nl_cache_get_ops(cache);
341*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *clone;
342*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
343*4dc78e53SAndroid Build Coastguard Worker 
344*4dc78e53SAndroid Build Coastguard Worker 	clone = nl_cache_alloc(ops);
345*4dc78e53SAndroid Build Coastguard Worker 	if (!clone)
346*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
347*4dc78e53SAndroid Build Coastguard Worker 
348*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Cloning %p into %p\n", cache, clone);
349*4dc78e53SAndroid Build Coastguard Worker 
350*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &cache->c_items, ce_list)
351*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_add(clone, obj);
352*4dc78e53SAndroid Build Coastguard Worker 
353*4dc78e53SAndroid Build Coastguard Worker 	return clone;
354*4dc78e53SAndroid Build Coastguard Worker }
355*4dc78e53SAndroid Build Coastguard Worker 
356*4dc78e53SAndroid Build Coastguard Worker /**
357*4dc78e53SAndroid Build Coastguard Worker  * Remove all objects of a cache.
358*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache to clear
359*4dc78e53SAndroid Build Coastguard Worker  *
360*4dc78e53SAndroid Build Coastguard Worker  * The objects are unliked/removed from the cache by calling
361*4dc78e53SAndroid Build Coastguard Worker  * nl_cache_remove() on each object in the cache. If any of the objects
362*4dc78e53SAndroid Build Coastguard Worker  * to not contain any further references to them, those objects will
363*4dc78e53SAndroid Build Coastguard Worker  * be freed.
364*4dc78e53SAndroid Build Coastguard Worker  *
365*4dc78e53SAndroid Build Coastguard Worker  * Unlike with nl_cache_free(), the cache is not freed just emptied.
366*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_clear(struct nl_cache * cache)367*4dc78e53SAndroid Build Coastguard Worker void nl_cache_clear(struct nl_cache *cache)
368*4dc78e53SAndroid Build Coastguard Worker {
369*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj, *tmp;
370*4dc78e53SAndroid Build Coastguard Worker 
371*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
372*4dc78e53SAndroid Build Coastguard Worker 
373*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
374*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_remove(obj);
375*4dc78e53SAndroid Build Coastguard Worker }
376*4dc78e53SAndroid Build Coastguard Worker 
__nl_cache_free(struct nl_cache * cache)377*4dc78e53SAndroid Build Coastguard Worker static void __nl_cache_free(struct nl_cache *cache)
378*4dc78e53SAndroid Build Coastguard Worker {
379*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_clear(cache);
380*4dc78e53SAndroid Build Coastguard Worker 
381*4dc78e53SAndroid Build Coastguard Worker 	if (cache->hashtable)
382*4dc78e53SAndroid Build Coastguard Worker 		nl_hash_table_free(cache->hashtable);
383*4dc78e53SAndroid Build Coastguard Worker 
384*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
385*4dc78e53SAndroid Build Coastguard Worker 	free(cache);
386*4dc78e53SAndroid Build Coastguard Worker }
387*4dc78e53SAndroid Build Coastguard Worker 
388*4dc78e53SAndroid Build Coastguard Worker /**
389*4dc78e53SAndroid Build Coastguard Worker  * Increase reference counter of cache
390*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
391*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_get(struct nl_cache * cache)392*4dc78e53SAndroid Build Coastguard Worker void nl_cache_get(struct nl_cache *cache)
393*4dc78e53SAndroid Build Coastguard Worker {
394*4dc78e53SAndroid Build Coastguard Worker 	cache->c_refcnt++;
395*4dc78e53SAndroid Build Coastguard Worker 
396*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(3, "Incremented cache %p <%s> reference count to %d\n",
397*4dc78e53SAndroid Build Coastguard Worker 	       cache, nl_cache_name(cache), cache->c_refcnt);
398*4dc78e53SAndroid Build Coastguard Worker }
399*4dc78e53SAndroid Build Coastguard Worker 
400*4dc78e53SAndroid Build Coastguard Worker /**
401*4dc78e53SAndroid Build Coastguard Worker  * Free a cache.
402*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache to free.
403*4dc78e53SAndroid Build Coastguard Worker  *
404*4dc78e53SAndroid Build Coastguard Worker  * Calls nl_cache_clear() to remove all objects associated with the
405*4dc78e53SAndroid Build Coastguard Worker  * cache and frees the cache afterwards.
406*4dc78e53SAndroid Build Coastguard Worker  *
407*4dc78e53SAndroid Build Coastguard Worker  * @see nl_cache_clear()
408*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_free(struct nl_cache * cache)409*4dc78e53SAndroid Build Coastguard Worker void nl_cache_free(struct nl_cache *cache)
410*4dc78e53SAndroid Build Coastguard Worker {
411*4dc78e53SAndroid Build Coastguard Worker 	if (!cache)
412*4dc78e53SAndroid Build Coastguard Worker 		return;
413*4dc78e53SAndroid Build Coastguard Worker 
414*4dc78e53SAndroid Build Coastguard Worker 	cache->c_refcnt--;
415*4dc78e53SAndroid Build Coastguard Worker 
416*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(3, "Decremented cache %p <%s> reference count, %d remaining\n",
417*4dc78e53SAndroid Build Coastguard Worker 	       cache, nl_cache_name(cache), cache->c_refcnt);
418*4dc78e53SAndroid Build Coastguard Worker 
419*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_refcnt <= 0)
420*4dc78e53SAndroid Build Coastguard Worker 		__nl_cache_free(cache);
421*4dc78e53SAndroid Build Coastguard Worker }
422*4dc78e53SAndroid Build Coastguard Worker 
nl_cache_put(struct nl_cache * cache)423*4dc78e53SAndroid Build Coastguard Worker void nl_cache_put(struct nl_cache *cache)
424*4dc78e53SAndroid Build Coastguard Worker {
425*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_free(cache);
426*4dc78e53SAndroid Build Coastguard Worker }
427*4dc78e53SAndroid Build Coastguard Worker 
428*4dc78e53SAndroid Build Coastguard Worker /** @} */
429*4dc78e53SAndroid Build Coastguard Worker 
430*4dc78e53SAndroid Build Coastguard Worker /**
431*4dc78e53SAndroid Build Coastguard Worker  * @name Cache Modifications
432*4dc78e53SAndroid Build Coastguard Worker  * @{
433*4dc78e53SAndroid Build Coastguard Worker  */
434*4dc78e53SAndroid Build Coastguard Worker 
__cache_add(struct nl_cache * cache,struct nl_object * obj)435*4dc78e53SAndroid Build Coastguard Worker static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
436*4dc78e53SAndroid Build Coastguard Worker {
437*4dc78e53SAndroid Build Coastguard Worker 	int ret;
438*4dc78e53SAndroid Build Coastguard Worker 
439*4dc78e53SAndroid Build Coastguard Worker 	obj->ce_cache = cache;
440*4dc78e53SAndroid Build Coastguard Worker 
441*4dc78e53SAndroid Build Coastguard Worker 	if (cache->hashtable) {
442*4dc78e53SAndroid Build Coastguard Worker 		ret = nl_hash_table_add(cache->hashtable, obj);
443*4dc78e53SAndroid Build Coastguard Worker 		if (ret < 0) {
444*4dc78e53SAndroid Build Coastguard Worker 			obj->ce_cache = NULL;
445*4dc78e53SAndroid Build Coastguard Worker 			return ret;
446*4dc78e53SAndroid Build Coastguard Worker 		}
447*4dc78e53SAndroid Build Coastguard Worker 	}
448*4dc78e53SAndroid Build Coastguard Worker 
449*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&obj->ce_list, &cache->c_items);
450*4dc78e53SAndroid Build Coastguard Worker 	cache->c_nitems++;
451*4dc78e53SAndroid Build Coastguard Worker 
452*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(3, "Added object %p to cache %p <%s>, nitems %d\n",
453*4dc78e53SAndroid Build Coastguard Worker 	       obj, cache, nl_cache_name(cache), cache->c_nitems);
454*4dc78e53SAndroid Build Coastguard Worker 
455*4dc78e53SAndroid Build Coastguard Worker 	return 0;
456*4dc78e53SAndroid Build Coastguard Worker }
457*4dc78e53SAndroid Build Coastguard Worker 
458*4dc78e53SAndroid Build Coastguard Worker /**
459*4dc78e53SAndroid Build Coastguard Worker  * Add object to cache.
460*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
461*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		Object to be added to the cache
462*4dc78e53SAndroid Build Coastguard Worker  *
463*4dc78e53SAndroid Build Coastguard Worker  * Adds the object \p obj to the specified \p cache. In case the object
464*4dc78e53SAndroid Build Coastguard Worker  * is already associated with another cache, the object is cloned before
465*4dc78e53SAndroid Build Coastguard Worker  * adding it to the cache. In this case, the sole reference to the object
466*4dc78e53SAndroid Build Coastguard Worker  * will be the one of the cache. Therefore clearing/freeing the cache
467*4dc78e53SAndroid Build Coastguard Worker  * will result in the object being freed again.
468*4dc78e53SAndroid Build Coastguard Worker  *
469*4dc78e53SAndroid Build Coastguard Worker  * If the object has not been associated with a cache yet, the reference
470*4dc78e53SAndroid Build Coastguard Worker  * counter of the object is incremented to account for the additional
471*4dc78e53SAndroid Build Coastguard Worker  * reference.
472*4dc78e53SAndroid Build Coastguard Worker  *
473*4dc78e53SAndroid Build Coastguard Worker  * The type of the object and cache must match, otherwise an error is
474*4dc78e53SAndroid Build Coastguard Worker  * returned (-NLE_OBJ_MISMATCH).
475*4dc78e53SAndroid Build Coastguard Worker  *
476*4dc78e53SAndroid Build Coastguard Worker  * @see nl_cache_move()
477*4dc78e53SAndroid Build Coastguard Worker  *
478*4dc78e53SAndroid Build Coastguard Worker  * @return 0 or a negative error code.
479*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_add(struct nl_cache * cache,struct nl_object * obj)480*4dc78e53SAndroid Build Coastguard Worker int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
481*4dc78e53SAndroid Build Coastguard Worker {
482*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *new;
483*4dc78e53SAndroid Build Coastguard Worker 	int ret = 0;
484*4dc78e53SAndroid Build Coastguard Worker 
485*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops->co_obj_ops != obj->ce_ops)
486*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OBJ_MISMATCH;
487*4dc78e53SAndroid Build Coastguard Worker 
488*4dc78e53SAndroid Build Coastguard Worker 	if (!nl_list_empty(&obj->ce_list)) {
489*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(3, "Object %p already in cache, cloning new object\n", obj);
490*4dc78e53SAndroid Build Coastguard Worker 
491*4dc78e53SAndroid Build Coastguard Worker 		new = nl_object_clone(obj);
492*4dc78e53SAndroid Build Coastguard Worker 		if (!new)
493*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
494*4dc78e53SAndroid Build Coastguard Worker 	} else {
495*4dc78e53SAndroid Build Coastguard Worker 		nl_object_get(obj);
496*4dc78e53SAndroid Build Coastguard Worker 		new = obj;
497*4dc78e53SAndroid Build Coastguard Worker 	}
498*4dc78e53SAndroid Build Coastguard Worker 
499*4dc78e53SAndroid Build Coastguard Worker 	ret = __cache_add(cache, new);
500*4dc78e53SAndroid Build Coastguard Worker 	if (ret < 0)
501*4dc78e53SAndroid Build Coastguard Worker 		nl_object_put(new);
502*4dc78e53SAndroid Build Coastguard Worker 
503*4dc78e53SAndroid Build Coastguard Worker 	return ret;
504*4dc78e53SAndroid Build Coastguard Worker }
505*4dc78e53SAndroid Build Coastguard Worker 
506*4dc78e53SAndroid Build Coastguard Worker /**
507*4dc78e53SAndroid Build Coastguard Worker  * Move object from one cache to another
508*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache to move object to.
509*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		Object subject to be moved
510*4dc78e53SAndroid Build Coastguard Worker  *
511*4dc78e53SAndroid Build Coastguard Worker  * Removes the the specified object \p obj from its associated cache
512*4dc78e53SAndroid Build Coastguard Worker  * and moves it to another cache.
513*4dc78e53SAndroid Build Coastguard Worker  *
514*4dc78e53SAndroid Build Coastguard Worker  * If the object is not associated with a cache, the function behaves
515*4dc78e53SAndroid Build Coastguard Worker  * just like nl_cache_add().
516*4dc78e53SAndroid Build Coastguard Worker  *
517*4dc78e53SAndroid Build Coastguard Worker  * The type of the object and cache must match, otherwise an error is
518*4dc78e53SAndroid Build Coastguard Worker  * returned (-NLE_OBJ_MISMATCH).
519*4dc78e53SAndroid Build Coastguard Worker  *
520*4dc78e53SAndroid Build Coastguard Worker  * @see nl_cache_add()
521*4dc78e53SAndroid Build Coastguard Worker  *
522*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
523*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_move(struct nl_cache * cache,struct nl_object * obj)524*4dc78e53SAndroid Build Coastguard Worker int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
525*4dc78e53SAndroid Build Coastguard Worker {
526*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops->co_obj_ops != obj->ce_ops)
527*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OBJ_MISMATCH;
528*4dc78e53SAndroid Build Coastguard Worker 
529*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(3, "Moving object %p from cache %p to cache %p\n",
530*4dc78e53SAndroid Build Coastguard Worker 	       obj, obj->ce_cache, cache);
531*4dc78e53SAndroid Build Coastguard Worker 
532*4dc78e53SAndroid Build Coastguard Worker 	/* Acquire reference, if already in a cache this will be
533*4dc78e53SAndroid Build Coastguard Worker 	 * reverted during removal */
534*4dc78e53SAndroid Build Coastguard Worker 	nl_object_get(obj);
535*4dc78e53SAndroid Build Coastguard Worker 
536*4dc78e53SAndroid Build Coastguard Worker 	if (!nl_list_empty(&obj->ce_list))
537*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_remove(obj);
538*4dc78e53SAndroid Build Coastguard Worker 
539*4dc78e53SAndroid Build Coastguard Worker 	return __cache_add(cache, obj);
540*4dc78e53SAndroid Build Coastguard Worker }
541*4dc78e53SAndroid Build Coastguard Worker 
542*4dc78e53SAndroid Build Coastguard Worker /**
543*4dc78e53SAndroid Build Coastguard Worker  * Remove object from cache.
544*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		Object to remove from cache
545*4dc78e53SAndroid Build Coastguard Worker  *
546*4dc78e53SAndroid Build Coastguard Worker  * Removes the object \c obj from the cache it is associated with. The
547*4dc78e53SAndroid Build Coastguard Worker  * reference counter of the object will be decremented. If the reference
548*4dc78e53SAndroid Build Coastguard Worker  * to the object was the only one remaining, the object will be freed.
549*4dc78e53SAndroid Build Coastguard Worker  *
550*4dc78e53SAndroid Build Coastguard Worker  * If no cache is associated with the object, this function is a NOP.
551*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_remove(struct nl_object * obj)552*4dc78e53SAndroid Build Coastguard Worker void nl_cache_remove(struct nl_object *obj)
553*4dc78e53SAndroid Build Coastguard Worker {
554*4dc78e53SAndroid Build Coastguard Worker 	int ret;
555*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache = obj->ce_cache;
556*4dc78e53SAndroid Build Coastguard Worker 
557*4dc78e53SAndroid Build Coastguard Worker 	if (cache == NULL)
558*4dc78e53SAndroid Build Coastguard Worker 		return;
559*4dc78e53SAndroid Build Coastguard Worker 
560*4dc78e53SAndroid Build Coastguard Worker 	if (cache->hashtable) {
561*4dc78e53SAndroid Build Coastguard Worker 		ret = nl_hash_table_del(cache->hashtable, obj);
562*4dc78e53SAndroid Build Coastguard Worker 		if (ret < 0)
563*4dc78e53SAndroid Build Coastguard Worker 			NL_DBG(2, "Failed to delete %p from cache %p <%s>.\n",
564*4dc78e53SAndroid Build Coastguard Worker 			       obj, cache, nl_cache_name(cache));
565*4dc78e53SAndroid Build Coastguard Worker 	}
566*4dc78e53SAndroid Build Coastguard Worker 
567*4dc78e53SAndroid Build Coastguard Worker 	nl_list_del(&obj->ce_list);
568*4dc78e53SAndroid Build Coastguard Worker 	obj->ce_cache = NULL;
569*4dc78e53SAndroid Build Coastguard Worker 	nl_object_put(obj);
570*4dc78e53SAndroid Build Coastguard Worker 	cache->c_nitems--;
571*4dc78e53SAndroid Build Coastguard Worker 
572*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Deleted object %p from cache %p <%s>.\n",
573*4dc78e53SAndroid Build Coastguard Worker 	       obj, cache, nl_cache_name(cache));
574*4dc78e53SAndroid Build Coastguard Worker }
575*4dc78e53SAndroid Build Coastguard Worker 
576*4dc78e53SAndroid Build Coastguard Worker /** @} */
577*4dc78e53SAndroid Build Coastguard Worker 
578*4dc78e53SAndroid Build Coastguard Worker /**
579*4dc78e53SAndroid Build Coastguard Worker  * @name Synchronization
580*4dc78e53SAndroid Build Coastguard Worker  * @{
581*4dc78e53SAndroid Build Coastguard Worker  */
582*4dc78e53SAndroid Build Coastguard Worker 
583*4dc78e53SAndroid Build Coastguard Worker /**
584*4dc78e53SAndroid Build Coastguard Worker  * Set synchronization arg1 of cache
585*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
586*4dc78e53SAndroid Build Coastguard Worker  * @arg arg		argument
587*4dc78e53SAndroid Build Coastguard Worker  *
588*4dc78e53SAndroid Build Coastguard Worker  * Synchronization arguments are used to specify filters when
589*4dc78e53SAndroid Build Coastguard Worker  * requesting dumps from the kernel.
590*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_set_arg1(struct nl_cache * cache,int arg)591*4dc78e53SAndroid Build Coastguard Worker void nl_cache_set_arg1(struct nl_cache *cache, int arg)
592*4dc78e53SAndroid Build Coastguard Worker {
593*4dc78e53SAndroid Build Coastguard Worker 	cache->c_iarg1 = arg;
594*4dc78e53SAndroid Build Coastguard Worker }
595*4dc78e53SAndroid Build Coastguard Worker 
596*4dc78e53SAndroid Build Coastguard Worker /**
597*4dc78e53SAndroid Build Coastguard Worker  * Set synchronization arg2 of cache
598*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
599*4dc78e53SAndroid Build Coastguard Worker  * @arg arg		argument
600*4dc78e53SAndroid Build Coastguard Worker  *
601*4dc78e53SAndroid Build Coastguard Worker  * Synchronization arguments are used to specify filters when
602*4dc78e53SAndroid Build Coastguard Worker  * requesting dumps from the kernel.
603*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_set_arg2(struct nl_cache * cache,int arg)604*4dc78e53SAndroid Build Coastguard Worker void nl_cache_set_arg2(struct nl_cache *cache, int arg)
605*4dc78e53SAndroid Build Coastguard Worker {
606*4dc78e53SAndroid Build Coastguard Worker 	cache->c_iarg2 = arg;
607*4dc78e53SAndroid Build Coastguard Worker }
608*4dc78e53SAndroid Build Coastguard Worker 
609*4dc78e53SAndroid Build Coastguard Worker /**
610*4dc78e53SAndroid Build Coastguard Worker  * Set cache flags
611*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
612*4dc78e53SAndroid Build Coastguard Worker  * @arg flags		Flags
613*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_set_flags(struct nl_cache * cache,unsigned int flags)614*4dc78e53SAndroid Build Coastguard Worker void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
615*4dc78e53SAndroid Build Coastguard Worker {
616*4dc78e53SAndroid Build Coastguard Worker 	cache->c_flags |= flags;
617*4dc78e53SAndroid Build Coastguard Worker }
618*4dc78e53SAndroid Build Coastguard Worker 
619*4dc78e53SAndroid Build Coastguard Worker /**
620*4dc78e53SAndroid Build Coastguard Worker  * Invoke the request-update operation
621*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netlink socket.
622*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
623*4dc78e53SAndroid Build Coastguard Worker  *
624*4dc78e53SAndroid Build Coastguard Worker  * This function causes the \e request-update function of the cache
625*4dc78e53SAndroid Build Coastguard Worker  * operations to be invoked. This usually causes a dump request to
626*4dc78e53SAndroid Build Coastguard Worker  * be sent over the netlink socket which triggers the kernel to dump
627*4dc78e53SAndroid Build Coastguard Worker  * all objects of a specific type to be dumped onto the netlink
628*4dc78e53SAndroid Build Coastguard Worker  * socket for pickup.
629*4dc78e53SAndroid Build Coastguard Worker  *
630*4dc78e53SAndroid Build Coastguard Worker  * The behaviour of this function depends on the implemenation of
631*4dc78e53SAndroid Build Coastguard Worker  * the \e request_update function of each individual type of cache.
632*4dc78e53SAndroid Build Coastguard Worker  *
633*4dc78e53SAndroid Build Coastguard Worker  * This function will not have any effects on the cache (unless the
634*4dc78e53SAndroid Build Coastguard Worker  * request_update implementation of the cache operations does so).
635*4dc78e53SAndroid Build Coastguard Worker  *
636*4dc78e53SAndroid Build Coastguard Worker  * Use nl_cache_pickup() to pick-up (read) the objects from the socket
637*4dc78e53SAndroid Build Coastguard Worker  * and fill them into the cache.
638*4dc78e53SAndroid Build Coastguard Worker  *
639*4dc78e53SAndroid Build Coastguard Worker  * @see nl_cache_pickup(), nl_cache_resync()
640*4dc78e53SAndroid Build Coastguard Worker  *
641*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code. Some implementations
642*4dc78e53SAndroid Build Coastguard Worker  * of co_request_update() return a positive number on success that is
643*4dc78e53SAndroid Build Coastguard Worker  * the number of bytes sent. Treat any non-negative number as success too.
644*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_request_full_dump(struct nl_sock * sk,struct nl_cache * cache)645*4dc78e53SAndroid Build Coastguard Worker static int nl_cache_request_full_dump(struct nl_sock *sk,
646*4dc78e53SAndroid Build Coastguard Worker 				      struct nl_cache *cache)
647*4dc78e53SAndroid Build Coastguard Worker {
648*4dc78e53SAndroid Build Coastguard Worker 	if (sk->s_proto != cache->c_ops->co_protocol)
649*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_PROTO_MISMATCH;
650*4dc78e53SAndroid Build Coastguard Worker 
651*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops->co_request_update == NULL)
652*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
653*4dc78e53SAndroid Build Coastguard Worker 
654*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Requesting update from kernel for cache %p <%s>\n",
655*4dc78e53SAndroid Build Coastguard Worker 	          cache, nl_cache_name(cache));
656*4dc78e53SAndroid Build Coastguard Worker 
657*4dc78e53SAndroid Build Coastguard Worker 	return cache->c_ops->co_request_update(cache, sk);
658*4dc78e53SAndroid Build Coastguard Worker }
659*4dc78e53SAndroid Build Coastguard Worker 
660*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
661*4dc78e53SAndroid Build Coastguard Worker struct update_xdata {
662*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_ops *ops;
663*4dc78e53SAndroid Build Coastguard Worker 	struct nl_parser_param *params;
664*4dc78e53SAndroid Build Coastguard Worker };
665*4dc78e53SAndroid Build Coastguard Worker 
update_msg_parser(struct nl_msg * msg,void * arg)666*4dc78e53SAndroid Build Coastguard Worker static int update_msg_parser(struct nl_msg *msg, void *arg)
667*4dc78e53SAndroid Build Coastguard Worker {
668*4dc78e53SAndroid Build Coastguard Worker 	struct update_xdata *x = arg;
669*4dc78e53SAndroid Build Coastguard Worker 	int ret = 0;
670*4dc78e53SAndroid Build Coastguard Worker 
671*4dc78e53SAndroid Build Coastguard Worker 	ret = nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
672*4dc78e53SAndroid Build Coastguard Worker 	if (ret == -NLE_EXIST)
673*4dc78e53SAndroid Build Coastguard Worker 		return NL_SKIP;
674*4dc78e53SAndroid Build Coastguard Worker 	else
675*4dc78e53SAndroid Build Coastguard Worker 		return ret;
676*4dc78e53SAndroid Build Coastguard Worker }
677*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
678*4dc78e53SAndroid Build Coastguard Worker 
679*4dc78e53SAndroid Build Coastguard Worker /**
680*4dc78e53SAndroid Build Coastguard Worker  * Pick-up a netlink request-update with your own parser
681*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netlink socket
682*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
683*4dc78e53SAndroid Build Coastguard Worker  * @arg param		Parser parameters
684*4dc78e53SAndroid Build Coastguard Worker  */
__cache_pickup(struct nl_sock * sk,struct nl_cache * cache,struct nl_parser_param * param)685*4dc78e53SAndroid Build Coastguard Worker static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
686*4dc78e53SAndroid Build Coastguard Worker 			  struct nl_parser_param *param)
687*4dc78e53SAndroid Build Coastguard Worker {
688*4dc78e53SAndroid Build Coastguard Worker 	int err;
689*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cb *cb;
690*4dc78e53SAndroid Build Coastguard Worker 	struct update_xdata x = {
691*4dc78e53SAndroid Build Coastguard Worker 		.ops = cache->c_ops,
692*4dc78e53SAndroid Build Coastguard Worker 		.params = param,
693*4dc78e53SAndroid Build Coastguard Worker 	};
694*4dc78e53SAndroid Build Coastguard Worker 
695*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Picking up answer for cache %p <%s>\n",
696*4dc78e53SAndroid Build Coastguard Worker 	       cache, nl_cache_name(cache));
697*4dc78e53SAndroid Build Coastguard Worker 
698*4dc78e53SAndroid Build Coastguard Worker 	cb = nl_cb_clone(sk->s_cb);
699*4dc78e53SAndroid Build Coastguard Worker 	if (cb == NULL)
700*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
701*4dc78e53SAndroid Build Coastguard Worker 
702*4dc78e53SAndroid Build Coastguard Worker 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
703*4dc78e53SAndroid Build Coastguard Worker 
704*4dc78e53SAndroid Build Coastguard Worker 	err = nl_recvmsgs(sk, cb);
705*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
706*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned %d: %s\n",
707*4dc78e53SAndroid Build Coastguard Worker 		       cache, nl_cache_name(cache), err, nl_geterror(err));
708*4dc78e53SAndroid Build Coastguard Worker 
709*4dc78e53SAndroid Build Coastguard Worker 	nl_cb_put(cb);
710*4dc78e53SAndroid Build Coastguard Worker 
711*4dc78e53SAndroid Build Coastguard Worker 	return err;
712*4dc78e53SAndroid Build Coastguard Worker }
713*4dc78e53SAndroid Build Coastguard Worker 
pickup_checkdup_cb(struct nl_object * c,struct nl_parser_param * p)714*4dc78e53SAndroid Build Coastguard Worker static int pickup_checkdup_cb(struct nl_object *c, struct nl_parser_param *p)
715*4dc78e53SAndroid Build Coastguard Worker {
716*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache = (struct nl_cache *)p->pp_arg;
717*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *old;
718*4dc78e53SAndroid Build Coastguard Worker 
719*4dc78e53SAndroid Build Coastguard Worker 	old = nl_cache_search(cache, c);
720*4dc78e53SAndroid Build Coastguard Worker 	if (old) {
721*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_update(old, c) == 0) {
722*4dc78e53SAndroid Build Coastguard Worker 			nl_object_put(old);
723*4dc78e53SAndroid Build Coastguard Worker 			return 0;
724*4dc78e53SAndroid Build Coastguard Worker 		}
725*4dc78e53SAndroid Build Coastguard Worker 
726*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_remove(old);
727*4dc78e53SAndroid Build Coastguard Worker 		nl_object_put(old);
728*4dc78e53SAndroid Build Coastguard Worker 	}
729*4dc78e53SAndroid Build Coastguard Worker 
730*4dc78e53SAndroid Build Coastguard Worker 	return nl_cache_add(cache, c);
731*4dc78e53SAndroid Build Coastguard Worker }
732*4dc78e53SAndroid Build Coastguard Worker 
pickup_cb(struct nl_object * c,struct nl_parser_param * p)733*4dc78e53SAndroid Build Coastguard Worker static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
734*4dc78e53SAndroid Build Coastguard Worker {
735*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache = p->pp_arg;
736*4dc78e53SAndroid Build Coastguard Worker 
737*4dc78e53SAndroid Build Coastguard Worker 	return nl_cache_add(cache, c);
738*4dc78e53SAndroid Build Coastguard Worker }
739*4dc78e53SAndroid Build Coastguard Worker 
__nl_cache_pickup(struct nl_sock * sk,struct nl_cache * cache,int checkdup)740*4dc78e53SAndroid Build Coastguard Worker static int __nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
741*4dc78e53SAndroid Build Coastguard Worker 			     int checkdup)
742*4dc78e53SAndroid Build Coastguard Worker {
743*4dc78e53SAndroid Build Coastguard Worker 	struct nl_parser_param p;
744*4dc78e53SAndroid Build Coastguard Worker 
745*4dc78e53SAndroid Build Coastguard Worker 	p.pp_cb = checkdup ? pickup_checkdup_cb : pickup_cb;
746*4dc78e53SAndroid Build Coastguard Worker 	p.pp_arg = cache;
747*4dc78e53SAndroid Build Coastguard Worker 
748*4dc78e53SAndroid Build Coastguard Worker 	if (sk->s_proto != cache->c_ops->co_protocol)
749*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_PROTO_MISMATCH;
750*4dc78e53SAndroid Build Coastguard Worker 
751*4dc78e53SAndroid Build Coastguard Worker 	return __cache_pickup(sk, cache, &p);
752*4dc78e53SAndroid Build Coastguard Worker }
753*4dc78e53SAndroid Build Coastguard Worker 
754*4dc78e53SAndroid Build Coastguard Worker /**
755*4dc78e53SAndroid Build Coastguard Worker  * Pickup a netlink dump response and put it into a cache.
756*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netlink socket.
757*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache to put items into.
758*4dc78e53SAndroid Build Coastguard Worker  *
759*4dc78e53SAndroid Build Coastguard Worker  * Waits for netlink messages to arrive, parses them and puts them into
760*4dc78e53SAndroid Build Coastguard Worker  * the specified cache. If an old object with same key attributes is
761*4dc78e53SAndroid Build Coastguard Worker  * present in the cache, it is replaced with the new object.
762*4dc78e53SAndroid Build Coastguard Worker  * If the old object type supports an update operation, an update is
763*4dc78e53SAndroid Build Coastguard Worker  * attempted before a replace.
764*4dc78e53SAndroid Build Coastguard Worker  *
765*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
766*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_pickup_checkdup(struct nl_sock * sk,struct nl_cache * cache)767*4dc78e53SAndroid Build Coastguard Worker int nl_cache_pickup_checkdup(struct nl_sock *sk, struct nl_cache *cache)
768*4dc78e53SAndroid Build Coastguard Worker {
769*4dc78e53SAndroid Build Coastguard Worker 	return __nl_cache_pickup(sk, cache, 1);
770*4dc78e53SAndroid Build Coastguard Worker }
771*4dc78e53SAndroid Build Coastguard Worker 
772*4dc78e53SAndroid Build Coastguard Worker /**
773*4dc78e53SAndroid Build Coastguard Worker  * Pickup a netlink dump response and put it into a cache.
774*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netlink socket.
775*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache to put items into.
776*4dc78e53SAndroid Build Coastguard Worker  *
777*4dc78e53SAndroid Build Coastguard Worker  * Waits for netlink messages to arrive, parses them and puts them into
778*4dc78e53SAndroid Build Coastguard Worker  * the specified cache.
779*4dc78e53SAndroid Build Coastguard Worker  *
780*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
781*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_pickup(struct nl_sock * sk,struct nl_cache * cache)782*4dc78e53SAndroid Build Coastguard Worker int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
783*4dc78e53SAndroid Build Coastguard Worker {
784*4dc78e53SAndroid Build Coastguard Worker 	return __nl_cache_pickup(sk, cache, 0);
785*4dc78e53SAndroid Build Coastguard Worker }
786*4dc78e53SAndroid Build Coastguard Worker 
cache_include(struct nl_cache * cache,struct nl_object * obj,struct nl_msgtype * type,change_func_t cb,change_func_v2_t cb_v2,void * data)787*4dc78e53SAndroid Build Coastguard Worker static int cache_include(struct nl_cache *cache, struct nl_object *obj,
788*4dc78e53SAndroid Build Coastguard Worker 			 struct nl_msgtype *type, change_func_t cb,
789*4dc78e53SAndroid Build Coastguard Worker 			 change_func_v2_t cb_v2, void *data)
790*4dc78e53SAndroid Build Coastguard Worker {
791*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *old;
792*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *clone = NULL;
793*4dc78e53SAndroid Build Coastguard Worker 	uint64_t diff = 0;
794*4dc78e53SAndroid Build Coastguard Worker 
795*4dc78e53SAndroid Build Coastguard Worker 	switch (type->mt_act) {
796*4dc78e53SAndroid Build Coastguard Worker 	case NL_ACT_NEW:
797*4dc78e53SAndroid Build Coastguard Worker 	case NL_ACT_DEL:
798*4dc78e53SAndroid Build Coastguard Worker 		old = nl_cache_search(cache, obj);
799*4dc78e53SAndroid Build Coastguard Worker 		if (old) {
800*4dc78e53SAndroid Build Coastguard Worker 			if (cb_v2 && old->ce_ops->oo_update) {
801*4dc78e53SAndroid Build Coastguard Worker 				clone = nl_object_clone(old);
802*4dc78e53SAndroid Build Coastguard Worker 				diff = nl_object_diff64(old, obj);
803*4dc78e53SAndroid Build Coastguard Worker 			}
804*4dc78e53SAndroid Build Coastguard Worker 			/*
805*4dc78e53SAndroid Build Coastguard Worker 			 * Some objects types might support merging the new
806*4dc78e53SAndroid Build Coastguard Worker 			 * object with the old existing cache object.
807*4dc78e53SAndroid Build Coastguard Worker 			 * Handle them first.
808*4dc78e53SAndroid Build Coastguard Worker 			 */
809*4dc78e53SAndroid Build Coastguard Worker 			if (nl_object_update(old, obj) == 0) {
810*4dc78e53SAndroid Build Coastguard Worker 				if (cb_v2) {
811*4dc78e53SAndroid Build Coastguard Worker 					cb_v2(cache, clone, old, diff,
812*4dc78e53SAndroid Build Coastguard Worker 					      NL_ACT_CHANGE, data);
813*4dc78e53SAndroid Build Coastguard Worker 					nl_object_put(clone);
814*4dc78e53SAndroid Build Coastguard Worker 				} else if (cb)
815*4dc78e53SAndroid Build Coastguard Worker 					cb(cache, old, NL_ACT_CHANGE, data);
816*4dc78e53SAndroid Build Coastguard Worker 				nl_object_put(old);
817*4dc78e53SAndroid Build Coastguard Worker 				return 0;
818*4dc78e53SAndroid Build Coastguard Worker 			}
819*4dc78e53SAndroid Build Coastguard Worker 			nl_object_put(clone);
820*4dc78e53SAndroid Build Coastguard Worker 
821*4dc78e53SAndroid Build Coastguard Worker 			nl_cache_remove(old);
822*4dc78e53SAndroid Build Coastguard Worker 			if (type->mt_act == NL_ACT_DEL) {
823*4dc78e53SAndroid Build Coastguard Worker 				if (cb_v2)
824*4dc78e53SAndroid Build Coastguard Worker 					cb_v2(cache, old, NULL, 0, NL_ACT_DEL,
825*4dc78e53SAndroid Build Coastguard Worker 					      data);
826*4dc78e53SAndroid Build Coastguard Worker 				else if (cb)
827*4dc78e53SAndroid Build Coastguard Worker 					cb(cache, old, NL_ACT_DEL, data);
828*4dc78e53SAndroid Build Coastguard Worker 				nl_object_put(old);
829*4dc78e53SAndroid Build Coastguard Worker 			}
830*4dc78e53SAndroid Build Coastguard Worker 		}
831*4dc78e53SAndroid Build Coastguard Worker 
832*4dc78e53SAndroid Build Coastguard Worker 		if (type->mt_act == NL_ACT_NEW) {
833*4dc78e53SAndroid Build Coastguard Worker 			nl_cache_move(cache, obj);
834*4dc78e53SAndroid Build Coastguard Worker 			if (old == NULL) {
835*4dc78e53SAndroid Build Coastguard Worker 				if (cb_v2) {
836*4dc78e53SAndroid Build Coastguard Worker 					cb_v2(cache, NULL, obj, 0, NL_ACT_NEW,
837*4dc78e53SAndroid Build Coastguard Worker 					      data);
838*4dc78e53SAndroid Build Coastguard Worker 				} else if (cb)
839*4dc78e53SAndroid Build Coastguard Worker 					cb(cache, obj, NL_ACT_NEW, data);
840*4dc78e53SAndroid Build Coastguard Worker 			} else if (old) {
841*4dc78e53SAndroid Build Coastguard Worker 				diff = 0;
842*4dc78e53SAndroid Build Coastguard Worker 				if (cb || cb_v2)
843*4dc78e53SAndroid Build Coastguard Worker 					diff = nl_object_diff64(old, obj);
844*4dc78e53SAndroid Build Coastguard Worker 				if (diff && cb_v2) {
845*4dc78e53SAndroid Build Coastguard Worker 					cb_v2(cache, old, obj, diff, NL_ACT_CHANGE,
846*4dc78e53SAndroid Build Coastguard Worker 					      data);
847*4dc78e53SAndroid Build Coastguard Worker 				} else if (diff && cb)
848*4dc78e53SAndroid Build Coastguard Worker 					cb(cache, obj, NL_ACT_CHANGE, data);
849*4dc78e53SAndroid Build Coastguard Worker 
850*4dc78e53SAndroid Build Coastguard Worker 				nl_object_put(old);
851*4dc78e53SAndroid Build Coastguard Worker 			}
852*4dc78e53SAndroid Build Coastguard Worker 		}
853*4dc78e53SAndroid Build Coastguard Worker 		break;
854*4dc78e53SAndroid Build Coastguard Worker 	default:
855*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "Unknown action associated to object %p\n", obj);
856*4dc78e53SAndroid Build Coastguard Worker 		return 0;
857*4dc78e53SAndroid Build Coastguard Worker 	}
858*4dc78e53SAndroid Build Coastguard Worker 
859*4dc78e53SAndroid Build Coastguard Worker 	return 0;
860*4dc78e53SAndroid Build Coastguard Worker }
861*4dc78e53SAndroid Build Coastguard Worker 
nl_cache_include(struct nl_cache * cache,struct nl_object * obj,change_func_t change_cb,void * data)862*4dc78e53SAndroid Build Coastguard Worker int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
863*4dc78e53SAndroid Build Coastguard Worker 		     change_func_t change_cb, void *data)
864*4dc78e53SAndroid Build Coastguard Worker {
865*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_ops *ops = cache->c_ops;
866*4dc78e53SAndroid Build Coastguard Worker 	int i;
867*4dc78e53SAndroid Build Coastguard Worker 
868*4dc78e53SAndroid Build Coastguard Worker 	if (ops->co_obj_ops != obj->ce_ops)
869*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OBJ_MISMATCH;
870*4dc78e53SAndroid Build Coastguard Worker 
871*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
872*4dc78e53SAndroid Build Coastguard Worker 		if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
873*4dc78e53SAndroid Build Coastguard Worker 			return cache_include(cache, obj, &ops->co_msgtypes[i],
874*4dc78e53SAndroid Build Coastguard Worker 					     change_cb, NULL, data);
875*4dc78e53SAndroid Build Coastguard Worker 
876*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
877*4dc78e53SAndroid Build Coastguard Worker 	       obj, cache, nl_cache_name(cache));
878*4dc78e53SAndroid Build Coastguard Worker 
879*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_MSGTYPE_NOSUPPORT;
880*4dc78e53SAndroid Build Coastguard Worker }
881*4dc78e53SAndroid Build Coastguard Worker 
nl_cache_include_v2(struct nl_cache * cache,struct nl_object * obj,change_func_v2_t change_cb,void * data)882*4dc78e53SAndroid Build Coastguard Worker int nl_cache_include_v2(struct nl_cache *cache, struct nl_object *obj,
883*4dc78e53SAndroid Build Coastguard Worker 			change_func_v2_t change_cb, void *data)
884*4dc78e53SAndroid Build Coastguard Worker {
885*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_ops *ops = cache->c_ops;
886*4dc78e53SAndroid Build Coastguard Worker 	int i;
887*4dc78e53SAndroid Build Coastguard Worker 
888*4dc78e53SAndroid Build Coastguard Worker 	if (ops->co_obj_ops != obj->ce_ops)
889*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OBJ_MISMATCH;
890*4dc78e53SAndroid Build Coastguard Worker 
891*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
892*4dc78e53SAndroid Build Coastguard Worker 		if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
893*4dc78e53SAndroid Build Coastguard Worker 			return cache_include(cache, obj, &ops->co_msgtypes[i],
894*4dc78e53SAndroid Build Coastguard Worker 						NULL, change_cb, data);
895*4dc78e53SAndroid Build Coastguard Worker 
896*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
897*4dc78e53SAndroid Build Coastguard Worker 	       obj, cache, nl_cache_name(cache));
898*4dc78e53SAndroid Build Coastguard Worker 
899*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_MSGTYPE_NOSUPPORT;
900*4dc78e53SAndroid Build Coastguard Worker }
901*4dc78e53SAndroid Build Coastguard Worker 
resync_cb(struct nl_object * c,struct nl_parser_param * p)902*4dc78e53SAndroid Build Coastguard Worker static int resync_cb(struct nl_object *c, struct nl_parser_param *p)
903*4dc78e53SAndroid Build Coastguard Worker {
904*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_assoc *ca = p->pp_arg;
905*4dc78e53SAndroid Build Coastguard Worker 
906*4dc78e53SAndroid Build Coastguard Worker 	if (ca->ca_change_v2)
907*4dc78e53SAndroid Build Coastguard Worker 		return nl_cache_include_v2(ca->ca_cache, c, ca->ca_change_v2,
908*4dc78e53SAndroid Build Coastguard Worker 					   ca->ca_change_data);
909*4dc78e53SAndroid Build Coastguard Worker 	else
910*4dc78e53SAndroid Build Coastguard Worker 		return nl_cache_include(ca->ca_cache, c, ca->ca_change,
911*4dc78e53SAndroid Build Coastguard Worker 					ca->ca_change_data);
912*4dc78e53SAndroid Build Coastguard Worker }
913*4dc78e53SAndroid Build Coastguard Worker 
nl_cache_resync(struct nl_sock * sk,struct nl_cache * cache,change_func_t change_cb,void * data)914*4dc78e53SAndroid Build Coastguard Worker int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
915*4dc78e53SAndroid Build Coastguard Worker 		    change_func_t change_cb, void *data)
916*4dc78e53SAndroid Build Coastguard Worker {
917*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj, *next;
918*4dc78e53SAndroid Build Coastguard Worker 	struct nl_af_group *grp;
919*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache_assoc ca = {
920*4dc78e53SAndroid Build Coastguard Worker 		.ca_cache = cache,
921*4dc78e53SAndroid Build Coastguard Worker 		.ca_change = change_cb,
922*4dc78e53SAndroid Build Coastguard Worker 		.ca_change_data = data,
923*4dc78e53SAndroid Build Coastguard Worker 	};
924*4dc78e53SAndroid Build Coastguard Worker 	struct nl_parser_param p = {
925*4dc78e53SAndroid Build Coastguard Worker 		.pp_cb = resync_cb,
926*4dc78e53SAndroid Build Coastguard Worker 		.pp_arg = &ca,
927*4dc78e53SAndroid Build Coastguard Worker 	};
928*4dc78e53SAndroid Build Coastguard Worker 	int err;
929*4dc78e53SAndroid Build Coastguard Worker 
930*4dc78e53SAndroid Build Coastguard Worker 	if (sk->s_proto != cache->c_ops->co_protocol)
931*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_PROTO_MISMATCH;
932*4dc78e53SAndroid Build Coastguard Worker 
933*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache));
934*4dc78e53SAndroid Build Coastguard Worker 
935*4dc78e53SAndroid Build Coastguard Worker 	/* Mark all objects so we can see if some of them are obsolete */
936*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_mark_all(cache);
937*4dc78e53SAndroid Build Coastguard Worker 
938*4dc78e53SAndroid Build Coastguard Worker 	grp = cache->c_ops->co_groups;
939*4dc78e53SAndroid Build Coastguard Worker 	do {
940*4dc78e53SAndroid Build Coastguard Worker 		if (grp && grp->ag_group &&
941*4dc78e53SAndroid Build Coastguard Worker 			(cache->c_flags & NL_CACHE_AF_ITER))
942*4dc78e53SAndroid Build Coastguard Worker 			nl_cache_set_arg1(cache, grp->ag_family);
943*4dc78e53SAndroid Build Coastguard Worker 
944*4dc78e53SAndroid Build Coastguard Worker restart:
945*4dc78e53SAndroid Build Coastguard Worker 		err = nl_cache_request_full_dump(sk, cache);
946*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
947*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
948*4dc78e53SAndroid Build Coastguard Worker 
949*4dc78e53SAndroid Build Coastguard Worker 		err = __cache_pickup(sk, cache, &p);
950*4dc78e53SAndroid Build Coastguard Worker 		if (err == -NLE_DUMP_INTR)
951*4dc78e53SAndroid Build Coastguard Worker 			goto restart;
952*4dc78e53SAndroid Build Coastguard Worker 		else if (err < 0)
953*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
954*4dc78e53SAndroid Build Coastguard Worker 
955*4dc78e53SAndroid Build Coastguard Worker 		if (grp)
956*4dc78e53SAndroid Build Coastguard Worker 			grp++;
957*4dc78e53SAndroid Build Coastguard Worker 	} while (grp && grp->ag_group &&
958*4dc78e53SAndroid Build Coastguard Worker 		(cache->c_flags & NL_CACHE_AF_ITER));
959*4dc78e53SAndroid Build Coastguard Worker 
960*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) {
961*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_is_marked(obj)) {
962*4dc78e53SAndroid Build Coastguard Worker 			nl_object_get(obj);
963*4dc78e53SAndroid Build Coastguard Worker 			nl_cache_remove(obj);
964*4dc78e53SAndroid Build Coastguard Worker 			if (change_cb)
965*4dc78e53SAndroid Build Coastguard Worker 				change_cb(cache, obj, NL_ACT_DEL, data);
966*4dc78e53SAndroid Build Coastguard Worker 			nl_object_put(obj);
967*4dc78e53SAndroid Build Coastguard Worker 		}
968*4dc78e53SAndroid Build Coastguard Worker 	}
969*4dc78e53SAndroid Build Coastguard Worker 
970*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache));
971*4dc78e53SAndroid Build Coastguard Worker 
972*4dc78e53SAndroid Build Coastguard Worker 	err = 0;
973*4dc78e53SAndroid Build Coastguard Worker errout:
974*4dc78e53SAndroid Build Coastguard Worker 	return err;
975*4dc78e53SAndroid Build Coastguard Worker }
976*4dc78e53SAndroid Build Coastguard Worker 
977*4dc78e53SAndroid Build Coastguard Worker /** @} */
978*4dc78e53SAndroid Build Coastguard Worker 
979*4dc78e53SAndroid Build Coastguard Worker /**
980*4dc78e53SAndroid Build Coastguard Worker  * @name Parsing
981*4dc78e53SAndroid Build Coastguard Worker  * @{
982*4dc78e53SAndroid Build Coastguard Worker  */
983*4dc78e53SAndroid Build Coastguard Worker 
984*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
nl_cache_parse(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * params)985*4dc78e53SAndroid Build Coastguard Worker int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
986*4dc78e53SAndroid Build Coastguard Worker 		   struct nlmsghdr *nlh, struct nl_parser_param *params)
987*4dc78e53SAndroid Build Coastguard Worker {
988*4dc78e53SAndroid Build Coastguard Worker 	int i, err;
989*4dc78e53SAndroid Build Coastguard Worker 
990*4dc78e53SAndroid Build Coastguard Worker 	if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize))
991*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MSG_TOOSHORT;
992*4dc78e53SAndroid Build Coastguard Worker 
993*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) {
994*4dc78e53SAndroid Build Coastguard Worker 		if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) {
995*4dc78e53SAndroid Build Coastguard Worker 			err = ops->co_msg_parser(ops, who, nlh, params);
996*4dc78e53SAndroid Build Coastguard Worker 			if (err != -NLE_OPNOTSUPP)
997*4dc78e53SAndroid Build Coastguard Worker 				goto errout;
998*4dc78e53SAndroid Build Coastguard Worker 		}
999*4dc78e53SAndroid Build Coastguard Worker 	}
1000*4dc78e53SAndroid Build Coastguard Worker 
1001*4dc78e53SAndroid Build Coastguard Worker 
1002*4dc78e53SAndroid Build Coastguard Worker 	err = -NLE_MSGTYPE_NOSUPPORT;
1003*4dc78e53SAndroid Build Coastguard Worker errout:
1004*4dc78e53SAndroid Build Coastguard Worker 	return err;
1005*4dc78e53SAndroid Build Coastguard Worker }
1006*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
1007*4dc78e53SAndroid Build Coastguard Worker 
1008*4dc78e53SAndroid Build Coastguard Worker /**
1009*4dc78e53SAndroid Build Coastguard Worker  * Parse a netlink message and add it to the cache.
1010*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache to add element to
1011*4dc78e53SAndroid Build Coastguard Worker  * @arg msg		netlink message
1012*4dc78e53SAndroid Build Coastguard Worker  *
1013*4dc78e53SAndroid Build Coastguard Worker  * Parses a netlink message by calling the cache specific message parser
1014*4dc78e53SAndroid Build Coastguard Worker  * and adds the new element to the cache. If an old object with same key
1015*4dc78e53SAndroid Build Coastguard Worker  * attributes is present in the cache, it is replaced with the new object.
1016*4dc78e53SAndroid Build Coastguard Worker  * If the old object type supports an update operation, an update is
1017*4dc78e53SAndroid Build Coastguard Worker  * attempted before a replace.
1018*4dc78e53SAndroid Build Coastguard Worker  *
1019*4dc78e53SAndroid Build Coastguard Worker  * @return 0 or a negative error code.
1020*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_parse_and_add(struct nl_cache * cache,struct nl_msg * msg)1021*4dc78e53SAndroid Build Coastguard Worker int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
1022*4dc78e53SAndroid Build Coastguard Worker {
1023*4dc78e53SAndroid Build Coastguard Worker 	struct nl_parser_param p = {
1024*4dc78e53SAndroid Build Coastguard Worker 		.pp_cb = pickup_cb,
1025*4dc78e53SAndroid Build Coastguard Worker 		.pp_arg = cache,
1026*4dc78e53SAndroid Build Coastguard Worker 	};
1027*4dc78e53SAndroid Build Coastguard Worker 
1028*4dc78e53SAndroid Build Coastguard Worker 	return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
1029*4dc78e53SAndroid Build Coastguard Worker }
1030*4dc78e53SAndroid Build Coastguard Worker 
1031*4dc78e53SAndroid Build Coastguard Worker /**
1032*4dc78e53SAndroid Build Coastguard Worker  * (Re)fill a cache with the contents in the kernel.
1033*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netlink socket.
1034*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache to update
1035*4dc78e53SAndroid Build Coastguard Worker  *
1036*4dc78e53SAndroid Build Coastguard Worker  * Clears the specified cache and fills it with the current state in
1037*4dc78e53SAndroid Build Coastguard Worker  * the kernel.
1038*4dc78e53SAndroid Build Coastguard Worker  *
1039*4dc78e53SAndroid Build Coastguard Worker  * @return 0 or a negative error code.
1040*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_refill(struct nl_sock * sk,struct nl_cache * cache)1041*4dc78e53SAndroid Build Coastguard Worker int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
1042*4dc78e53SAndroid Build Coastguard Worker {
1043*4dc78e53SAndroid Build Coastguard Worker 	struct nl_af_group *grp;
1044*4dc78e53SAndroid Build Coastguard Worker 	int err;
1045*4dc78e53SAndroid Build Coastguard Worker 
1046*4dc78e53SAndroid Build Coastguard Worker 	if (sk->s_proto != cache->c_ops->co_protocol)
1047*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_PROTO_MISMATCH;
1048*4dc78e53SAndroid Build Coastguard Worker 
1049*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_clear(cache);
1050*4dc78e53SAndroid Build Coastguard Worker 	grp = cache->c_ops->co_groups;
1051*4dc78e53SAndroid Build Coastguard Worker 	do {
1052*4dc78e53SAndroid Build Coastguard Worker 		if (grp && grp->ag_group &&
1053*4dc78e53SAndroid Build Coastguard Worker 			(cache->c_flags & NL_CACHE_AF_ITER))
1054*4dc78e53SAndroid Build Coastguard Worker 			nl_cache_set_arg1(cache, grp->ag_family);
1055*4dc78e53SAndroid Build Coastguard Worker 
1056*4dc78e53SAndroid Build Coastguard Worker restart:
1057*4dc78e53SAndroid Build Coastguard Worker 		err = nl_cache_request_full_dump(sk, cache);
1058*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
1059*4dc78e53SAndroid Build Coastguard Worker 			return err;
1060*4dc78e53SAndroid Build Coastguard Worker 
1061*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "Updating cache %p <%s> for family %u, request sent, waiting for reply\n",
1062*4dc78e53SAndroid Build Coastguard Worker 		       cache, nl_cache_name(cache), grp ? grp->ag_family : AF_UNSPEC);
1063*4dc78e53SAndroid Build Coastguard Worker 
1064*4dc78e53SAndroid Build Coastguard Worker 		err = nl_cache_pickup(sk, cache);
1065*4dc78e53SAndroid Build Coastguard Worker 		if (err == -NLE_DUMP_INTR) {
1066*4dc78e53SAndroid Build Coastguard Worker 			NL_DBG(2, "Dump interrupted, restarting!\n");
1067*4dc78e53SAndroid Build Coastguard Worker 			goto restart;
1068*4dc78e53SAndroid Build Coastguard Worker 		} else if (err < 0)
1069*4dc78e53SAndroid Build Coastguard Worker 			break;
1070*4dc78e53SAndroid Build Coastguard Worker 
1071*4dc78e53SAndroid Build Coastguard Worker 		if (grp)
1072*4dc78e53SAndroid Build Coastguard Worker 			grp++;
1073*4dc78e53SAndroid Build Coastguard Worker 	} while (grp && grp->ag_group &&
1074*4dc78e53SAndroid Build Coastguard Worker 			(cache->c_flags & NL_CACHE_AF_ITER));
1075*4dc78e53SAndroid Build Coastguard Worker 
1076*4dc78e53SAndroid Build Coastguard Worker 	return err;
1077*4dc78e53SAndroid Build Coastguard Worker }
1078*4dc78e53SAndroid Build Coastguard Worker 
1079*4dc78e53SAndroid Build Coastguard Worker /** @} */
1080*4dc78e53SAndroid Build Coastguard Worker 
1081*4dc78e53SAndroid Build Coastguard Worker /**
1082*4dc78e53SAndroid Build Coastguard Worker  * @name Utillities
1083*4dc78e53SAndroid Build Coastguard Worker  * @{
1084*4dc78e53SAndroid Build Coastguard Worker  */
__cache_fast_lookup(struct nl_cache * cache,struct nl_object * needle)1085*4dc78e53SAndroid Build Coastguard Worker static struct nl_object *__cache_fast_lookup(struct nl_cache *cache,
1086*4dc78e53SAndroid Build Coastguard Worker 					     struct nl_object *needle)
1087*4dc78e53SAndroid Build Coastguard Worker {
1088*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
1089*4dc78e53SAndroid Build Coastguard Worker 
1090*4dc78e53SAndroid Build Coastguard Worker 	obj = nl_hash_table_lookup(cache->hashtable, needle);
1091*4dc78e53SAndroid Build Coastguard Worker 	if (obj) {
1092*4dc78e53SAndroid Build Coastguard Worker 		nl_object_get(obj);
1093*4dc78e53SAndroid Build Coastguard Worker 		return obj;
1094*4dc78e53SAndroid Build Coastguard Worker 	}
1095*4dc78e53SAndroid Build Coastguard Worker 
1096*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
1097*4dc78e53SAndroid Build Coastguard Worker }
1098*4dc78e53SAndroid Build Coastguard Worker 
1099*4dc78e53SAndroid Build Coastguard Worker /**
1100*4dc78e53SAndroid Build Coastguard Worker  * Search object in cache
1101*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
1102*4dc78e53SAndroid Build Coastguard Worker  * @arg needle		Object to look for.
1103*4dc78e53SAndroid Build Coastguard Worker  *
1104*4dc78e53SAndroid Build Coastguard Worker  * Searches the cache for an object which matches the object \p needle.
1105*4dc78e53SAndroid Build Coastguard Worker  * The function nl_object_identical() is used to determine if the
1106*4dc78e53SAndroid Build Coastguard Worker  * objects match. If a matching object is found, the reference counter
1107*4dc78e53SAndroid Build Coastguard Worker  * is incremented and the object is returned.
1108*4dc78e53SAndroid Build Coastguard Worker  *
1109*4dc78e53SAndroid Build Coastguard Worker  * Therefore, if an object is returned, the reference to the object
1110*4dc78e53SAndroid Build Coastguard Worker  * must be returned by calling nl_object_put() after usage.
1111*4dc78e53SAndroid Build Coastguard Worker  *
1112*4dc78e53SAndroid Build Coastguard Worker  * @return Reference to object or NULL if not found.
1113*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_search(struct nl_cache * cache,struct nl_object * needle)1114*4dc78e53SAndroid Build Coastguard Worker struct nl_object *nl_cache_search(struct nl_cache *cache,
1115*4dc78e53SAndroid Build Coastguard Worker 				  struct nl_object *needle)
1116*4dc78e53SAndroid Build Coastguard Worker {
1117*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
1118*4dc78e53SAndroid Build Coastguard Worker 
1119*4dc78e53SAndroid Build Coastguard Worker 	if (cache->hashtable)
1120*4dc78e53SAndroid Build Coastguard Worker 		return __cache_fast_lookup(cache, needle);
1121*4dc78e53SAndroid Build Coastguard Worker 
1122*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
1123*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_identical(obj, needle)) {
1124*4dc78e53SAndroid Build Coastguard Worker 			nl_object_get(obj);
1125*4dc78e53SAndroid Build Coastguard Worker 			return obj;
1126*4dc78e53SAndroid Build Coastguard Worker 		}
1127*4dc78e53SAndroid Build Coastguard Worker 	}
1128*4dc78e53SAndroid Build Coastguard Worker 
1129*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
1130*4dc78e53SAndroid Build Coastguard Worker }
1131*4dc78e53SAndroid Build Coastguard Worker 
1132*4dc78e53SAndroid Build Coastguard Worker /**
1133*4dc78e53SAndroid Build Coastguard Worker  * Find object in cache
1134*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
1135*4dc78e53SAndroid Build Coastguard Worker  * @arg filter		object acting as a filter
1136*4dc78e53SAndroid Build Coastguard Worker  *
1137*4dc78e53SAndroid Build Coastguard Worker  * Searches the cache for an object which matches the object filter.
1138*4dc78e53SAndroid Build Coastguard Worker  * If the filter attributes matches the object type id attributes,
1139*4dc78e53SAndroid Build Coastguard Worker  * and the cache supports hash lookups, a faster hashtable lookup
1140*4dc78e53SAndroid Build Coastguard Worker  * is used to return the object. Else, function nl_object_match_filter() is
1141*4dc78e53SAndroid Build Coastguard Worker  * used to determine if the objects match. If a matching object is
1142*4dc78e53SAndroid Build Coastguard Worker  * found, the reference counter is incremented and the object is returned.
1143*4dc78e53SAndroid Build Coastguard Worker  *
1144*4dc78e53SAndroid Build Coastguard Worker  * Therefore, if an object is returned, the reference to the object
1145*4dc78e53SAndroid Build Coastguard Worker  * must be returned by calling nl_object_put() after usage.
1146*4dc78e53SAndroid Build Coastguard Worker  *
1147*4dc78e53SAndroid Build Coastguard Worker  * @return Reference to object or NULL if not found.
1148*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_find(struct nl_cache * cache,struct nl_object * filter)1149*4dc78e53SAndroid Build Coastguard Worker struct nl_object *nl_cache_find(struct nl_cache *cache,
1150*4dc78e53SAndroid Build Coastguard Worker 				struct nl_object *filter)
1151*4dc78e53SAndroid Build Coastguard Worker {
1152*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
1153*4dc78e53SAndroid Build Coastguard Worker 
1154*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops == NULL)
1155*4dc78e53SAndroid Build Coastguard Worker 		BUG();
1156*4dc78e53SAndroid Build Coastguard Worker 
1157*4dc78e53SAndroid Build Coastguard Worker 	if ((nl_object_get_id_attrs(filter) == filter->ce_mask)
1158*4dc78e53SAndroid Build Coastguard Worker 		&& cache->hashtable)
1159*4dc78e53SAndroid Build Coastguard Worker 		return __cache_fast_lookup(cache, filter);
1160*4dc78e53SAndroid Build Coastguard Worker 
1161*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
1162*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_match_filter(obj, filter)) {
1163*4dc78e53SAndroid Build Coastguard Worker 			nl_object_get(obj);
1164*4dc78e53SAndroid Build Coastguard Worker 			return obj;
1165*4dc78e53SAndroid Build Coastguard Worker 		}
1166*4dc78e53SAndroid Build Coastguard Worker 	}
1167*4dc78e53SAndroid Build Coastguard Worker 
1168*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
1169*4dc78e53SAndroid Build Coastguard Worker }
1170*4dc78e53SAndroid Build Coastguard Worker 
1171*4dc78e53SAndroid Build Coastguard Worker /**
1172*4dc78e53SAndroid Build Coastguard Worker  * Mark all objects of a cache
1173*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		Cache
1174*4dc78e53SAndroid Build Coastguard Worker  *
1175*4dc78e53SAndroid Build Coastguard Worker  * Marks all objects of a cache by calling nl_object_mark() on each
1176*4dc78e53SAndroid Build Coastguard Worker  * object associated with the cache.
1177*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_mark_all(struct nl_cache * cache)1178*4dc78e53SAndroid Build Coastguard Worker void nl_cache_mark_all(struct nl_cache *cache)
1179*4dc78e53SAndroid Build Coastguard Worker {
1180*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
1181*4dc78e53SAndroid Build Coastguard Worker 
1182*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Marking all objects in cache %p <%s>\n",
1183*4dc78e53SAndroid Build Coastguard Worker 	       cache, nl_cache_name(cache));
1184*4dc78e53SAndroid Build Coastguard Worker 
1185*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &cache->c_items, ce_list)
1186*4dc78e53SAndroid Build Coastguard Worker 		nl_object_mark(obj);
1187*4dc78e53SAndroid Build Coastguard Worker }
1188*4dc78e53SAndroid Build Coastguard Worker 
1189*4dc78e53SAndroid Build Coastguard Worker /** @} */
1190*4dc78e53SAndroid Build Coastguard Worker 
1191*4dc78e53SAndroid Build Coastguard Worker /**
1192*4dc78e53SAndroid Build Coastguard Worker  * @name Dumping
1193*4dc78e53SAndroid Build Coastguard Worker  * @{
1194*4dc78e53SAndroid Build Coastguard Worker  */
1195*4dc78e53SAndroid Build Coastguard Worker 
1196*4dc78e53SAndroid Build Coastguard Worker /**
1197*4dc78e53SAndroid Build Coastguard Worker  * Dump all elements of a cache.
1198*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache to dump
1199*4dc78e53SAndroid Build Coastguard Worker  * @arg params		dumping parameters
1200*4dc78e53SAndroid Build Coastguard Worker  *
1201*4dc78e53SAndroid Build Coastguard Worker  * Dumps all elements of the \a cache to the file descriptor \a fd.
1202*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_dump(struct nl_cache * cache,struct nl_dump_params * params)1203*4dc78e53SAndroid Build Coastguard Worker void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
1204*4dc78e53SAndroid Build Coastguard Worker {
1205*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_dump_filter(cache, params, NULL);
1206*4dc78e53SAndroid Build Coastguard Worker }
1207*4dc78e53SAndroid Build Coastguard Worker 
1208*4dc78e53SAndroid Build Coastguard Worker /**
1209*4dc78e53SAndroid Build Coastguard Worker  * Dump all elements of a cache (filtered).
1210*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache to dump
1211*4dc78e53SAndroid Build Coastguard Worker  * @arg params		dumping parameters
1212*4dc78e53SAndroid Build Coastguard Worker  * @arg filter		filter object
1213*4dc78e53SAndroid Build Coastguard Worker  *
1214*4dc78e53SAndroid Build Coastguard Worker  * Dumps all elements of the \a cache to the file descriptor \a fd
1215*4dc78e53SAndroid Build Coastguard Worker  * given they match the given filter \a filter.
1216*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_dump_filter(struct nl_cache * cache,struct nl_dump_params * params,struct nl_object * filter)1217*4dc78e53SAndroid Build Coastguard Worker void nl_cache_dump_filter(struct nl_cache *cache,
1218*4dc78e53SAndroid Build Coastguard Worker 			  struct nl_dump_params *params,
1219*4dc78e53SAndroid Build Coastguard Worker 			  struct nl_object *filter)
1220*4dc78e53SAndroid Build Coastguard Worker {
1221*4dc78e53SAndroid Build Coastguard Worker 	struct nl_dump_params params_copy;
1222*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object_ops *ops;
1223*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj;
1224*4dc78e53SAndroid Build Coastguard Worker 	int type;
1225*4dc78e53SAndroid Build Coastguard Worker 
1226*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Dumping cache %p <%s> with filter %p\n",
1227*4dc78e53SAndroid Build Coastguard Worker 	       cache, nl_cache_name(cache), filter);
1228*4dc78e53SAndroid Build Coastguard Worker 
1229*4dc78e53SAndroid Build Coastguard Worker 	if (!params) {
1230*4dc78e53SAndroid Build Coastguard Worker 		/* It doesn't really make sense that @params is an optional parameter. In the
1231*4dc78e53SAndroid Build Coastguard Worker 		 * past, nl_cache_dump() was documented that the @params would be optional, so
1232*4dc78e53SAndroid Build Coastguard Worker 		 * try to save it.
1233*4dc78e53SAndroid Build Coastguard Worker 		 *
1234*4dc78e53SAndroid Build Coastguard Worker 		 * Note that this still isn't useful, because we don't set any dump option.
1235*4dc78e53SAndroid Build Coastguard Worker 		 * It only exists not to crash applications that wrongly pass %NULL here. */
1236*4dc78e53SAndroid Build Coastguard Worker 		_nl_assert_not_reached ();
1237*4dc78e53SAndroid Build Coastguard Worker 		params_copy = (struct nl_dump_params) {
1238*4dc78e53SAndroid Build Coastguard Worker 			.dp_type = NL_DUMP_DETAILS,
1239*4dc78e53SAndroid Build Coastguard Worker 		};
1240*4dc78e53SAndroid Build Coastguard Worker 		params = &params_copy;
1241*4dc78e53SAndroid Build Coastguard Worker 	}
1242*4dc78e53SAndroid Build Coastguard Worker 
1243*4dc78e53SAndroid Build Coastguard Worker 	type = params->dp_type;
1244*4dc78e53SAndroid Build Coastguard Worker 
1245*4dc78e53SAndroid Build Coastguard Worker 	if (type > NL_DUMP_MAX || type < 0)
1246*4dc78e53SAndroid Build Coastguard Worker 		BUG();
1247*4dc78e53SAndroid Build Coastguard Worker 
1248*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops == NULL)
1249*4dc78e53SAndroid Build Coastguard Worker 		BUG();
1250*4dc78e53SAndroid Build Coastguard Worker 
1251*4dc78e53SAndroid Build Coastguard Worker 	ops = cache->c_ops->co_obj_ops;
1252*4dc78e53SAndroid Build Coastguard Worker 	if (!ops->oo_dump[type])
1253*4dc78e53SAndroid Build Coastguard Worker 		return;
1254*4dc78e53SAndroid Build Coastguard Worker 
1255*4dc78e53SAndroid Build Coastguard Worker 	if (params->dp_buf)
1256*4dc78e53SAndroid Build Coastguard Worker 		memset(params->dp_buf, 0, params->dp_buflen);
1257*4dc78e53SAndroid Build Coastguard Worker 
1258*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
1259*4dc78e53SAndroid Build Coastguard Worker 		if (filter && !nl_object_match_filter(obj, filter))
1260*4dc78e53SAndroid Build Coastguard Worker 			continue;
1261*4dc78e53SAndroid Build Coastguard Worker 
1262*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(4, "Dumping object %p...\n", obj);
1263*4dc78e53SAndroid Build Coastguard Worker 		dump_from_ops(obj, params);
1264*4dc78e53SAndroid Build Coastguard Worker 	}
1265*4dc78e53SAndroid Build Coastguard Worker }
1266*4dc78e53SAndroid Build Coastguard Worker 
1267*4dc78e53SAndroid Build Coastguard Worker /** @} */
1268*4dc78e53SAndroid Build Coastguard Worker 
1269*4dc78e53SAndroid Build Coastguard Worker /**
1270*4dc78e53SAndroid Build Coastguard Worker  * @name Iterators
1271*4dc78e53SAndroid Build Coastguard Worker  * @{
1272*4dc78e53SAndroid Build Coastguard Worker  */
1273*4dc78e53SAndroid Build Coastguard Worker 
1274*4dc78e53SAndroid Build Coastguard Worker /**
1275*4dc78e53SAndroid Build Coastguard Worker  * Call a callback on each element of the cache.
1276*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache to iterate on
1277*4dc78e53SAndroid Build Coastguard Worker  * @arg cb		callback function
1278*4dc78e53SAndroid Build Coastguard Worker  * @arg arg		argument passed to callback function
1279*4dc78e53SAndroid Build Coastguard Worker  *
1280*4dc78e53SAndroid Build Coastguard Worker  * Calls a callback function \a cb on each element of the \a cache.
1281*4dc78e53SAndroid Build Coastguard Worker  * The argument \a arg is passed on the callback function.
1282*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_foreach(struct nl_cache * cache,void (* cb)(struct nl_object *,void *),void * arg)1283*4dc78e53SAndroid Build Coastguard Worker void nl_cache_foreach(struct nl_cache *cache,
1284*4dc78e53SAndroid Build Coastguard Worker 		      void (*cb)(struct nl_object *, void *), void *arg)
1285*4dc78e53SAndroid Build Coastguard Worker {
1286*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_foreach_filter(cache, NULL, cb, arg);
1287*4dc78e53SAndroid Build Coastguard Worker }
1288*4dc78e53SAndroid Build Coastguard Worker 
1289*4dc78e53SAndroid Build Coastguard Worker /**
1290*4dc78e53SAndroid Build Coastguard Worker  * Call a callback on each element of the cache (filtered).
1291*4dc78e53SAndroid Build Coastguard Worker  * @arg cache		cache to iterate on
1292*4dc78e53SAndroid Build Coastguard Worker  * @arg filter		filter object
1293*4dc78e53SAndroid Build Coastguard Worker  * @arg cb		callback function
1294*4dc78e53SAndroid Build Coastguard Worker  * @arg arg		argument passed to callback function
1295*4dc78e53SAndroid Build Coastguard Worker  *
1296*4dc78e53SAndroid Build Coastguard Worker  * Calls a callback function \a cb on each element of the \a cache
1297*4dc78e53SAndroid Build Coastguard Worker  * that matches the \a filter. The argument \a arg is passed on
1298*4dc78e53SAndroid Build Coastguard Worker  * to the callback function.
1299*4dc78e53SAndroid Build Coastguard Worker  */
nl_cache_foreach_filter(struct nl_cache * cache,struct nl_object * filter,void (* cb)(struct nl_object *,void *),void * arg)1300*4dc78e53SAndroid Build Coastguard Worker void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
1301*4dc78e53SAndroid Build Coastguard Worker 			     void (*cb)(struct nl_object *, void *), void *arg)
1302*4dc78e53SAndroid Build Coastguard Worker {
1303*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj, *tmp;
1304*4dc78e53SAndroid Build Coastguard Worker 
1305*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops == NULL)
1306*4dc78e53SAndroid Build Coastguard Worker 		BUG();
1307*4dc78e53SAndroid Build Coastguard Worker 
1308*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
1309*4dc78e53SAndroid Build Coastguard Worker 		if (filter) {
1310*4dc78e53SAndroid Build Coastguard Worker 			int diff = nl_object_match_filter(obj, filter);
1311*4dc78e53SAndroid Build Coastguard Worker 
1312*4dc78e53SAndroid Build Coastguard Worker 			NL_DBG(3, "%p<->%p object difference: %x\n",
1313*4dc78e53SAndroid Build Coastguard Worker 				obj, filter, diff);
1314*4dc78e53SAndroid Build Coastguard Worker 
1315*4dc78e53SAndroid Build Coastguard Worker 			if (!diff)
1316*4dc78e53SAndroid Build Coastguard Worker 				continue;
1317*4dc78e53SAndroid Build Coastguard Worker 		}
1318*4dc78e53SAndroid Build Coastguard Worker 
1319*4dc78e53SAndroid Build Coastguard Worker 		/* Caller may hold obj for a long time */
1320*4dc78e53SAndroid Build Coastguard Worker 		nl_object_get(obj);
1321*4dc78e53SAndroid Build Coastguard Worker 
1322*4dc78e53SAndroid Build Coastguard Worker 		cb(obj, arg);
1323*4dc78e53SAndroid Build Coastguard Worker 
1324*4dc78e53SAndroid Build Coastguard Worker 		nl_object_put(obj);
1325*4dc78e53SAndroid Build Coastguard Worker 	}
1326*4dc78e53SAndroid Build Coastguard Worker }
1327*4dc78e53SAndroid Build Coastguard Worker 
1328*4dc78e53SAndroid Build Coastguard Worker /** @} */
1329*4dc78e53SAndroid Build Coastguard Worker 
1330*4dc78e53SAndroid Build Coastguard Worker /** @} */
1331