xref: /aosp_15_r20/external/libnl/lib/object.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2012 Thomas Graf <[email protected]>
4  */
5 
6 /**
7  * @ingroup core_types
8  * @defgroup object Object (Cacheable)
9  *
10  * Generic object data type, for inheritance purposes to implement cacheable
11  * data types.
12  *
13  * Related sections in the development guide:
14  *
15  * @{
16  *
17  * Header
18  * ------
19  * ~~~~{.c}
20  * #include <netlink/object.h>
21  * ~~~~
22  */
23 
24 #include "nl-default.h"
25 
26 #include <netlink/netlink.h>
27 #include <netlink/cache.h>
28 #include <netlink/object.h>
29 #include <netlink/utils.h>
30 
31 #include "nl-core.h"
32 #include "nl-priv-dynamic-core/nl-core.h"
33 #include "nl-priv-dynamic-core/object-api.h"
34 #include "nl-priv-dynamic-core/cache-api.h"
35 #include "nl-aux-core/nl-core.h"
36 
obj_ops(struct nl_object * obj)37 static inline struct nl_object_ops *obj_ops(struct nl_object *obj)
38 {
39 	if (!obj->ce_ops)
40 		BUG();
41 
42 	return obj->ce_ops;
43 }
44 
45 /**
46  * @name Object Creation/Deletion
47  * @{
48  */
49 
50 /**
51  * Allocate a new object of kind specified by the operations handle
52  * @arg ops		cache operations handle
53  * @return The new object or NULL
54  */
nl_object_alloc(struct nl_object_ops * ops)55 struct nl_object *nl_object_alloc(struct nl_object_ops *ops)
56 {
57 	struct nl_object *new;
58 
59 	if (ops->oo_size < sizeof(*new))
60 		BUG();
61 
62 	new = calloc(1, ops->oo_size);
63 	if (!new)
64 		return NULL;
65 
66 	new->ce_refcnt = 1;
67 	nl_init_list_head(&new->ce_list);
68 
69 	new->ce_ops = ops;
70 	if (ops->oo_constructor)
71 		ops->oo_constructor(new);
72 
73 	NL_DBG(4, "Allocated new object %p\n", new);
74 
75 	return new;
76 }
77 
78 /**
79  * Allocate new object of kind specified by the name
80  * @arg kind		name of object type
81  * @arg result		Result pointer
82  *
83  * @return 0 on success or a negative error code.
84  */
nl_object_alloc_name(const char * kind,struct nl_object ** result)85 int nl_object_alloc_name(const char *kind, struct nl_object **result)
86 {
87 	struct nl_cache_ops *ops;
88 
89 	ops = nl_cache_ops_lookup_safe(kind);
90 	if (!ops)
91 		return -NLE_OPNOTSUPP;
92 
93 	*result = nl_object_alloc(ops->co_obj_ops);
94 	nl_cache_ops_put(ops);
95 	if (!*result)
96 		return -NLE_NOMEM;
97 
98 	return 0;
99 }
100 
101 struct nl_derived_object {
102 	NLHDR_COMMON
103 	char data;
104 };
105 
106 /**
107  * Allocate a new object and copy all data from an existing object
108  * @arg obj		object to inherite data from
109  * @return The new object or NULL.
110  */
nl_object_clone(struct nl_object * obj)111 struct nl_object *nl_object_clone(struct nl_object *obj)
112 {
113 	struct nl_object *new;
114 	struct nl_object_ops *ops;
115 	int doff = offsetof(struct nl_derived_object, data);
116 	int size;
117 
118 	if (!obj)
119 		return NULL;
120 
121 	ops = obj_ops(obj);
122 	new = nl_object_alloc(ops);
123 	if (!new)
124 		return NULL;
125 
126 	size = ops->oo_size - doff;
127 	if (size < 0)
128 		BUG();
129 
130 	new->ce_ops = obj->ce_ops;
131 	new->ce_msgtype = obj->ce_msgtype;
132 	new->ce_mask = obj->ce_mask;
133 
134 	if (size)
135 		memcpy((char *)new + doff, (char *)obj + doff, size);
136 
137 	/* Note that the base implementation already initializes @new via memcpy().
138 	 * That means, simple fields don't need to be handled via oo_clone().
139 	 * However, this is only a shallow-copy, so oo_clone() MUST fix all
140 	 * pointer values accordingly. */
141 
142 	if (ops->oo_clone) {
143 		if (ops->oo_clone(new, obj) < 0) {
144 			nl_object_free(new);
145 			return NULL;
146 		}
147 	} else if (size && ops->oo_free_data)
148 		BUG();
149 
150 	return new;
151 }
152 
153 /**
154  * Merge a cacheable object
155  * @arg dst		object to be merged into
156  * @arg src		new object to be merged into dst
157  *
158  * @return 0 or a negative error code.
159  */
nl_object_update(struct nl_object * dst,struct nl_object * src)160 int nl_object_update(struct nl_object *dst, struct nl_object *src)
161 {
162 	struct nl_object_ops *ops = obj_ops(dst);
163 
164 	if (ops->oo_update)
165 		return ops->oo_update(dst, src);
166 
167 	return -NLE_OPNOTSUPP;
168 }
169 
170 /**
171  * Free a cacheable object
172  * @arg obj		object to free
173  *
174  * @return 0 or a negative error code.
175  */
nl_object_free(struct nl_object * obj)176 void nl_object_free(struct nl_object *obj)
177 {
178 	struct nl_object_ops *ops;
179 
180 	if (!obj)
181 		return;
182 
183 	ops = obj_ops(obj);
184 
185 	if (obj->ce_refcnt > 0)
186 		NL_DBG(1, "Warning: Freeing object in use...\n");
187 
188 	if (obj->ce_cache)
189 		nl_cache_remove(obj);
190 
191 	if (ops->oo_free_data)
192 		ops->oo_free_data(obj);
193 
194 	NL_DBG(4, "Freed object %p\n", obj);
195 
196 	free(obj);
197 }
198 
199 /** @} */
200 
201 /**
202  * @name Reference Management
203  * @{
204  */
205 
206 /**
207  * Acquire a reference on a object
208  * @arg obj		object to acquire reference from
209  */
nl_object_get(struct nl_object * obj)210 void nl_object_get(struct nl_object *obj)
211 {
212 	obj->ce_refcnt++;
213 	NL_DBG(4, "New reference to object %p, total %d\n",
214 	       obj, obj->ce_refcnt);
215 }
216 
217 /**
218  * Release a reference from an object
219  * @arg obj		object to release reference from
220  */
nl_object_put(struct nl_object * obj)221 void nl_object_put(struct nl_object *obj)
222 {
223 	if (!obj)
224 		return;
225 
226 	obj->ce_refcnt--;
227 	NL_DBG(4, "Returned object reference %p, %d remaining\n",
228 	       obj, obj->ce_refcnt);
229 
230 	if (obj->ce_refcnt < 0)
231 		BUG();
232 
233 	if (obj->ce_refcnt <= 0)
234 		nl_object_free(obj);
235 }
236 
237 /**
238  * Check whether this object is used by multiple users
239  * @arg obj		object to check
240  * @return true or false
241  */
nl_object_shared(struct nl_object * obj)242 int nl_object_shared(struct nl_object *obj)
243 {
244 	return obj->ce_refcnt > 1;
245 }
246 
247 /** @} */
248 
249 /**
250  * @name Marks
251  * @{
252  */
253 
254 /**
255  * Add mark to object
256  * @arg obj		Object to mark
257  */
nl_object_mark(struct nl_object * obj)258 void nl_object_mark(struct nl_object *obj)
259 {
260 	obj->ce_flags |= NL_OBJ_MARK;
261 }
262 
263 /**
264  * Remove mark from object
265  * @arg obj		Object to unmark
266  */
nl_object_unmark(struct nl_object * obj)267 void nl_object_unmark(struct nl_object *obj)
268 {
269 	obj->ce_flags &= ~NL_OBJ_MARK;
270 }
271 
272 /**
273  * Return true if object is marked
274  * @arg obj		Object to check
275  * @return true if object is marked, otherwise false
276  */
nl_object_is_marked(struct nl_object * obj)277 int nl_object_is_marked(struct nl_object *obj)
278 {
279 	return (obj->ce_flags & NL_OBJ_MARK);
280 }
281 
282 /** @} */
283 
284 /**
285  * @name Utillities
286  * @{
287  */
288 
289 /**
290  * Dump this object according to the specified parameters
291  * @arg obj		object to dump
292  * @arg params		dumping parameters
293  */
nl_object_dump(struct nl_object * obj,struct nl_dump_params * params)294 void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params)
295 {
296 	if (params->dp_buf)
297 		memset(params->dp_buf, 0, params->dp_buflen);
298 
299 	dump_from_ops(obj, params);
300 }
301 
nl_object_dump_buf(struct nl_object * obj,char * buf,size_t len)302 void nl_object_dump_buf(struct nl_object *obj, char *buf, size_t len)
303 {
304 	struct nl_dump_params dp = {
305 		.dp_buf = buf,
306 		.dp_buflen = len,
307 	};
308 
309 	nl_object_dump(obj, &dp);
310 }
311 
312 /**
313  * Check if the identifiers of two objects are identical
314  * @arg a		an object
315  * @arg b		another object of same type
316  *
317  * @return true if both objects have equal identifiers, otherwise false.
318  */
nl_object_identical(struct nl_object * a,struct nl_object * b)319 int nl_object_identical(struct nl_object *a, struct nl_object *b)
320 {
321 	struct nl_object_ops *ops;
322 	uint64_t req_attrs_a;
323 	uint64_t req_attrs_b;
324 
325 	if (a == b)
326 		return 1;
327 
328 	/* Both objects must be of same type */
329 	ops = obj_ops(a);
330 	if (ops != obj_ops(b))
331 		return 0;
332 
333 	/* Can't judge unless we can compare */
334 	if (ops->oo_compare == NULL)
335 		return 0;
336 
337 	if (ops->oo_id_attrs_get) {
338 		req_attrs_a = ops->oo_id_attrs_get(a);
339 		req_attrs_b = ops->oo_id_attrs_get(b);
340 	} else if (ops->oo_id_attrs) {
341 		req_attrs_a = ops->oo_id_attrs;
342 		req_attrs_b = req_attrs_a;
343 	} else {
344 		req_attrs_a = UINT64_MAX;
345 		req_attrs_b = req_attrs_a;
346 	}
347 
348 	req_attrs_a &= a->ce_mask;
349 	req_attrs_b &= b->ce_mask;
350 
351 	/* Both objects must provide all required attributes to uniquely
352 	 * identify an object */
353 	if (req_attrs_a != req_attrs_b)
354 		return 0;
355 
356 	return !(ops->oo_compare(a, b, req_attrs_a, ID_COMPARISON));
357 }
358 
359 /**
360  * Compute bitmask representing difference in attribute values
361  * @arg a		an object
362  * @arg b		another object of same type
363  *
364  * The bitmask returned is specific to an object type, each bit set represents
365  * an attribute which mismatches in either of the two objects. Unavailability
366  * of an attribute in one object and presence in the other is regarded a
367  * mismatch as well.
368  *
369  * @return Bitmask describing differences or 0 if they are completely identical.
370  */
nl_object_diff64(struct nl_object * a,struct nl_object * b)371 uint64_t nl_object_diff64(struct nl_object *a, struct nl_object *b)
372 {
373 	struct nl_object_ops *ops = obj_ops(a);
374 
375 	if (ops != obj_ops(b) || ops->oo_compare == NULL)
376 		return UINT64_MAX;
377 
378 	return ops->oo_compare(a, b, UINT64_MAX, 0);
379 }
380 
381 /**
382  * Compute 32-bit bitmask representing difference in attribute values
383  * @arg a		an object
384  * @arg b		another object of same type
385  *
386  * The bitmask returned is specific to an object type, each bit set represents
387  * an attribute which mismatches in either of the two objects. Unavailability
388  * of an attribute in one object and presence in the other is regarded a
389  * mismatch as well.
390  *
391  * @return Bitmask describing differences or 0 if they are completely identical.
392  *	   32nd bit indicates if higher bits from the 64-bit compare were
393  *	   different.
394  */
nl_object_diff(struct nl_object * a,struct nl_object * b)395 uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
396 {
397 	uint64_t  diff;
398 
399 	diff = nl_object_diff64(a, b);
400 
401 	return (diff & ~((uint64_t) 0xFFFFFFFF))
402 		? (uint32_t) diff | (((uint32_t ) 1u) << 31)
403 		: (uint32_t) diff;
404 }
405 
406 /**
407  * Match a filter against an object
408  * @arg obj		object to check
409  * @arg filter		object of same type acting as filter
410  *
411  * @return 1 if the object matches the filter or 0
412  *           if no filter procedure is available or if the
413  *           filter does not match.
414  */
nl_object_match_filter(struct nl_object * obj,struct nl_object * filter)415 int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
416 {
417 	struct nl_object_ops *ops = obj_ops(obj);
418 
419 	if (ops != obj_ops(filter) || ops->oo_compare == NULL)
420 		return 0;
421 
422 	return !(ops->oo_compare(obj, filter, filter->ce_mask,
423 				 LOOSE_COMPARISON));
424 }
425 
426 /**
427  * Convert bitmask of attributes to a character string
428  * @arg obj		object of same type as attribute bitmask
429  * @arg attrs		bitmask of attribute types
430  * @arg buf		destination buffer
431  * @arg len		length of destination buffer
432  *
433  * Converts the bitmask of attribute types into a list of attribute
434  * names separated by comas.
435  *
436  * @return destination buffer.
437  */
nl_object_attrs2str(struct nl_object * obj,uint32_t attrs,char * buf,size_t len)438 char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs,
439 			  char *buf, size_t len)
440 {
441 	struct nl_object_ops *ops = obj_ops(obj);
442 
443 	if (ops->oo_attrs2str != NULL)
444 		return ops->oo_attrs2str(attrs, buf, len);
445 	else {
446 		memset(buf, 0, len);
447 		return buf;
448 	}
449 }
450 
451 /**
452  * Return list of attributes present in an object
453  * @arg obj		an object
454  * @arg buf		destination buffer
455  * @arg len		length of destination buffer
456  *
457  * @return destination buffer.
458  */
nl_object_attr_list(struct nl_object * obj,char * buf,size_t len)459 char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
460 {
461 	return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
462 }
463 
464 /**
465  * Generate object hash key
466  * @arg obj		the object
467  * @arg hashkey		destination buffer to be used for key stream
468  * @arg hashtbl_sz	hash table size
469  *
470  * @return hash key in destination buffer
471  */
nl_object_keygen(struct nl_object * obj,uint32_t * hashkey,uint32_t hashtbl_sz)472 void nl_object_keygen(struct nl_object *obj, uint32_t *hashkey,
473 		      uint32_t hashtbl_sz)
474 {
475 	struct nl_object_ops *ops = obj_ops(obj);
476 
477 	if (ops->oo_keygen)
478 		ops->oo_keygen(obj, hashkey, hashtbl_sz);
479 	else
480 		*hashkey = 0;
481 
482 	return;
483 }
484 
485 /** @} */
486 
487 /**
488  * @name Attributes
489  * @{
490  */
491 
492 /**
493  * Return number of references held
494  * @arg obj		object
495  *
496  * @return The number of references held to this object
497  */
nl_object_get_refcnt(struct nl_object * obj)498 int nl_object_get_refcnt(struct nl_object *obj)
499 {
500 	return obj->ce_refcnt;
501 }
502 
503 /**
504  * Return cache the object is associated with
505  * @arg obj		object
506  *
507  * @note The returned pointer is not protected with a reference counter,
508  *       it is your responsibility.
509  *
510  * @return Pointer to cache or NULL if not associated with a cache.
511  */
nl_object_get_cache(struct nl_object * obj)512 struct nl_cache *nl_object_get_cache(struct nl_object *obj)
513 {
514 	return obj->ce_cache;
515 }
516 
517 /**
518  * Return the object's type
519  * @arg obj		object
520  *
521  * FIXME: link to list of object types
522  *
523  * @return Name of the object type
524  */
nl_object_get_type(const struct nl_object * obj)525 const char *nl_object_get_type(const struct nl_object *obj)
526 {
527 	if (!obj->ce_ops)
528 		BUG();
529 
530 	return obj->ce_ops->oo_name;
531 }
532 
533 /**
534  * Return the netlink message type the object was derived from
535  * @arg obj		object
536  *
537  * @return Netlink message type or 0.
538  */
nl_object_get_msgtype(const struct nl_object * obj)539 int nl_object_get_msgtype(const struct nl_object *obj)
540 {
541 	return obj->ce_msgtype;
542 }
543 
544 /**
545  * Return object operations structure
546  * @arg obj		object
547  *
548  * @return Pointer to the object operations structure
549  */
nl_object_get_ops(const struct nl_object * obj)550 struct nl_object_ops *nl_object_get_ops(const struct nl_object *obj)
551 {
552 	return obj->ce_ops;
553 }
554 
555 /**
556  * Return object id attribute mask
557  * @arg obj		object
558  *
559  * @return object id attribute mask
560  */
nl_object_get_id_attrs(struct nl_object * obj)561 uint32_t nl_object_get_id_attrs(struct nl_object *obj)
562 {
563 	struct nl_object_ops *ops = obj_ops(obj);
564 	uint32_t id_attrs;
565 
566 	if (!ops)
567 		return 0;
568 
569 	if (ops->oo_id_attrs_get)
570 		id_attrs = ops->oo_id_attrs_get(obj);
571 	else
572 		id_attrs = ops->oo_id_attrs;
573 
574 	return id_attrs;
575 }
576 
577 /** @} */
578 
579 /** @} */
580