xref: /aosp_15_r20/external/libnl/lib/utils.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
8  * @defgroup utils Utilities
9  *
10  * Collection of helper functions
11  *
12  * @{
13  *
14  * Header
15  * ------
16  * ~~~~{.c}
17  * #include <netlink/utils.h>
18  * ~~~~
19  */
20 
21 #include "nl-default.h"
22 
23 #include <locale.h>
24 
25 #include <linux/socket.h>
26 #include <linux/if_arp.h>
27 
28 #include <netlink/netlink.h>
29 #include <netlink/utils.h>
30 
31 #include "nl-core.h"
32 #include "nl-priv-dynamic-core/object-api.h"
33 #include "nl-priv-dynamic-core/nl-core.h"
34 #include "nl-aux-core/nl-core.h"
35 
36 /**
37  * Global variable indicating the desired level of debugging output.
38  *
39  * Level | Messages Printed
40  * ----- | ---------------------------------------------------------
41  *     0 | Debugging output disabled
42  *     1 | Warnings, important events and notifications
43  *     2 | More or less important debugging messages
44  *     3 | Repetitive events causing a flood of debugging messages
45  *     4 | Even less important messages
46  *
47  * If available, the variable will be initialized to the value of the
48  * environment variable `NLDBG`. The default value is 0 (disabled).
49  *
50  * For more information, see section @core_doc{_debugging, Debugging}.
51  */
52 int nl_debug = 0;
53 
54 /** @cond SKIP */
55 struct nl_dump_params nl_debug_dp = {
56 	.dp_type = NL_DUMP_DETAILS,
57 };
58 
nl_debug_init(void)59 static void _nl_init nl_debug_init(void)
60 {
61 	char *nldbg, *end;
62 
63 	if (NL_DEBUG && (nldbg = getenv("NLDBG"))) {
64 		long level = strtol(nldbg, &end, 0);
65 		if (nldbg != end)
66 			nl_debug = level;
67 	}
68 
69 	nl_debug_dp.dp_fd = stderr;
70 }
71 
__nl_read_num_str_file(const char * path,int (* cb)(long,const char *))72 int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
73 {
74 	FILE *fd;
75 	char buf[128];
76 
77 	fd = fopen(path, "re");
78 	if (fd == NULL)
79 		return -nl_syserr2nlerr(errno);
80 
81 	while (fgets(buf, sizeof(buf), fd)) {
82 		int goodlen, err;
83 		long num;
84 		char *end;
85 
86 		if (*buf == '#' || *buf == '\n' || *buf == '\r')
87 			continue;
88 
89 		num = strtol(buf, &end, 0);
90 		if (end == buf) {
91 			fclose(fd);
92 			return -NLE_INVAL;
93 		}
94 
95 		if (num == LONG_MIN || num == LONG_MAX) {
96 			fclose(fd);
97 			return -NLE_RANGE;
98 		}
99 
100 		while (*end == ' ' || *end == '\t')
101 			end++;
102 
103 		goodlen = strcspn(end, "#\r\n\t ");
104 		if (goodlen == 0) {
105 			fclose(fd);
106 			return -NLE_INVAL;
107 		}
108 
109 		end[goodlen] = '\0';
110 
111 		err = cb(num, end);
112 		if (err < 0) {
113 			fclose(fd);
114 			return err;
115 		}
116 	}
117 
118 	fclose(fd);
119 
120 	return 0;
121 }
122 
123 struct trans_list {
124 	int i;
125 	char *a;
126 	struct nl_list_head list;
127 };
128 
nl_getprotobyname(const char * name)129 int nl_getprotobyname(const char *name)
130 {
131 	const struct protoent *result;
132 
133 #if HAVE_DECL_GETPROTOBYNAME_R
134 	struct protoent result_buf;
135 	char buf[2048];
136 	int r;
137 
138 	r = getprotobyname_r(name, &result_buf, buf, sizeof(buf),
139 			     (struct protoent **)&result);
140 	if (r != 0 || result != &result_buf)
141 		result = NULL;
142 #else
143 	result = getprotobyname(name);
144 #endif
145 
146 	if (!result)
147 		return -1;
148 
149 	if (result->p_proto < 0 || result->p_proto > UINT8_MAX)
150 		return -1;
151 	return (uint8_t)result->p_proto;
152 }
153 
nl_getprotobynumber(int proto,char * out_name,size_t name_len)154 bool nl_getprotobynumber(int proto, char *out_name, size_t name_len)
155 {
156 	const struct protoent *result;
157 
158 #if HAVE_DECL_GETPROTOBYNUMBER_R
159 	struct protoent result_buf;
160 	char buf[2048];
161 	int r;
162 
163 	r = getprotobynumber_r(proto, &result_buf, buf, sizeof(buf),
164 			       (struct protoent **)&result);
165 	if (r != 0 || result != &result_buf)
166 		result = NULL;
167 #else
168 	result = getprotobynumber(proto);
169 #endif
170 
171 	if (!result)
172 		return false;
173 
174 	if (strlen(result->p_name) >= name_len)
175 		return false;
176 	strcpy(out_name, result->p_name);
177 	return true;
178 }
179 
nl_strerror_l(int err)180 const char *nl_strerror_l(int err)
181 {
182 	const char *buf;
183 #ifdef HAVE_STRERROR_L
184 	int errno_save = errno;
185 	locale_t loc = newlocale(LC_MESSAGES_MASK, "", (locale_t)0);
186 
187 	if (loc == (locale_t)0) {
188 		if (errno == ENOENT)
189 			loc = newlocale(LC_MESSAGES_MASK,
190 					"POSIX", (locale_t)0);
191 	}
192 	if (loc != (locale_t)0) {
193 		buf = strerror_l(err, loc);
194 		freelocale(loc);
195 	} else {
196 		buf = "newlocale() failed";
197 	}
198 
199 	errno = errno_save;
200 #else
201 	buf = strerror(err);
202 #endif
203 	return buf;
204 }
205 /** @endcond */
206 
207 /**
208  * @name Pretty Printing of Numbers
209  * @{
210  */
211 
212 /**
213  * Cancel down a byte counter
214  * @arg	l		byte counter
215  * @arg	unit		destination unit pointer
216  *
217  * Cancels down a byte counter until it reaches a reasonable
218  * unit. The chosen unit is assigned to \a unit.
219  * This function assume 1024 bytes in one kilobyte
220  *
221  * @return The cancelled down byte counter in the new unit.
222  */
nl_cancel_down_bytes(unsigned long long l,char ** unit)223 double nl_cancel_down_bytes(unsigned long long l, char **unit)
224 {
225 	if (l >= 1099511627776LL) {
226 		*unit = "TiB";
227 		return ((double) l) / 1099511627776LL;
228 	} else if (l >= 1073741824) {
229 		*unit = "GiB";
230 		return ((double) l) / 1073741824;
231 	} else if (l >= 1048576) {
232 		*unit = "MiB";
233 		return ((double) l) / 1048576;
234 	} else if (l >= 1024) {
235 		*unit = "KiB";
236 		return ((double) l) / 1024;
237 	} else {
238 		*unit = "B";
239 		return (double) l;
240 	}
241 }
242 
243 /**
244  * Cancel down a bit counter
245  * @arg	l		bit counter
246  * @arg unit		destination unit pointer
247  *
248  * Cancels down bit counter until it reaches a reasonable
249  * unit. The chosen unit is assigned to \a unit.
250  * This function assume 1000 bits in one kilobit
251  *
252  * @return The cancelled down bit counter in the new unit.
253  */
nl_cancel_down_bits(unsigned long long l,char ** unit)254 double nl_cancel_down_bits(unsigned long long l, char **unit)
255 {
256 	if (l >= 1000000000000ULL) {
257 		*unit = "Tbit";
258 		return ((double) l) / 1000000000000ULL;
259 	}
260 
261 	if (l >= 1000000000) {
262 		*unit = "Gbit";
263 		return ((double) l) / 1000000000;
264 	}
265 
266 	if (l >= 1000000) {
267 		*unit = "Mbit";
268 		return ((double) l) / 1000000;
269 	}
270 
271 	if (l >= 1000) {
272 		*unit = "Kbit";
273 		return ((double) l) / 1000;
274 	}
275 
276 	*unit = "bit";
277 	return (double) l;
278 }
279 
nl_rate2str(unsigned long long rate,int type,char * buf,size_t len)280 int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len)
281 {
282 	char *unit;
283 	double frac;
284 
285 	switch (type) {
286 	case NL_BYTE_RATE:
287 		frac = nl_cancel_down_bytes(rate, &unit);
288 		break;
289 
290 	case NL_BIT_RATE:
291 		frac = nl_cancel_down_bits(rate, &unit);
292 		break;
293 
294 	default:
295 		BUG();
296 	}
297 
298 	return snprintf(buf, len, "%.2f%s/s", frac, unit);
299 }
300 
301 /**
302  * Cancel down a micro second value
303  * @arg	l		micro seconds
304  * @arg unit		destination unit pointer
305  *
306  * Cancels down a microsecond counter until it reaches a
307  * reasonable unit. The chosen unit is assigned to \a unit.
308  *
309  * @return The cancelled down microsecond in the new unit
310  */
nl_cancel_down_us(uint32_t l,char ** unit)311 double nl_cancel_down_us(uint32_t l, char **unit)
312 {
313 	if (l >= 1000000) {
314 		*unit = "s";
315 		return ((double) l) / 1000000;
316 	} else if (l >= 1000) {
317 		*unit = "ms";
318 		return ((double) l) / 1000;
319 	} else {
320 		*unit = "us";
321 		return (double) l;
322 	}
323 }
324 
325 /** @} */
326 
327 /**
328  * @name Generic Unit Translations
329  * @{
330  */
331 
332 /**
333  * Convert a character string to a size
334  * @arg str		size encoded as character string
335  *
336  * Converts the specified size as character to the corresponding
337  * number of bytes.
338  *
339  * Supported formats are:
340  *  - b,kb/k,m/mb,gb/g for bytes
341  *  - bit,kbit/mbit/gbit
342  *
343  * This function assume 1000 bits in one kilobit and
344  * 1024 bytes in one kilobyte
345  *
346  * @return The number of bytes or -1 if the string is unparseable
347  */
nl_size2int(const char * str)348 long nl_size2int(const char *str)
349 {
350 	char *p;
351 	long l = strtol(str, &p, 0);
352 	if (p == str)
353 		return -NLE_INVAL;
354 
355 	if (*p) {
356 		if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
357 			l *= 1024;
358 		else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
359 			l *= 1024*1024*1024;
360 		else if (!strcasecmp(p, "gbit"))
361 			l *= 1000000000L/8;
362 		else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
363 			l *= 1024*1024;
364 		else if (!strcasecmp(p, "mbit"))
365 			l *= 1000000/8;
366 		else if (!strcasecmp(p, "kbit"))
367 			l *= 1000/8;
368 		else if (!strcasecmp(p, "bit"))
369 			l /= 8;
370 		else if (strcasecmp(p, "b") != 0)
371 			return -NLE_INVAL;
372 	}
373 
374 	return l;
375 }
376 
377 static const struct {
378 	double limit;
379 	const char *unit;
380 } size_units[] = {
381 	{ 1024. * 1024. * 1024. * 1024. * 1024., "EiB" },
382 	{ 1024. * 1024. * 1024. * 1024., "TiB" },
383 	{ 1024. * 1024. * 1024., "GiB" },
384 	{ 1024. * 1024., "MiB" },
385 	{ 1024., "KiB" },
386 	{ 0., "B" },
387 };
388 
389 /**
390  * Convert a size toa character string
391  * @arg size		Size in number of bytes
392  * @arg buf		Buffer to write character string to
393  * @arg len		Size of buf
394  *
395  * This function converts a value in bytes to a human readable representation
396  * of it. The function uses IEC prefixes:
397  *
398  * @code
399  * 1024 bytes => 1 KiB
400  * 1048576 bytes => 1 MiB
401  * @endcode
402  *
403  * The highest prefix is used which ensures a result of >= 1.0, the result
404  * is provided as floating point number with a maximum precision of 2 digits:
405  * @code
406  * 965176 bytes => 942.55 KiB
407  * @endcode
408  *
409  * @return pointer to buf
410  */
nl_size2str(const size_t size,char * buf,const size_t len)411 char *nl_size2str(const size_t size, char *buf, const size_t len)
412 {
413 	size_t i;
414 
415 	if (size == 0) {
416 		snprintf(buf, len, "0B");
417 		return buf;
418 	}
419 
420 	for (i = 0; i < ARRAY_SIZE(size_units); i++) {
421 		if (size >= size_units[i].limit) {
422 			snprintf(buf, len, "%.2g%s",
423 				(double) size / size_units[i].limit,
424 				size_units[i].unit);
425 			return buf;
426 		}
427 	}
428 
429 	BUG();
430 }
431 
432 /**
433  * Convert a character string to a probability
434  * @arg str		probability encoded as character string
435  *
436  * Converts the specified probability as character to the
437  * corresponding probability number.
438  *
439  * Supported formats are:
440  *  - 0.0-1.0
441  *  - 0%-100%
442  *
443  * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
444  */
nl_prob2int(const char * str)445 long nl_prob2int(const char *str)
446 {
447 	char *p;
448 	double d = strtod(str, &p);
449 
450 	if (p == str)
451 		return -NLE_INVAL;
452 
453 	if (d > 1.0)
454 		d /= 100.0f;
455 
456 	if (d > 1.0f || d < 0.0f)
457 		return -NLE_RANGE;
458 
459 	if (*p && strcmp(p, "%") != 0)
460 		return -NLE_INVAL;
461 
462 	return (long) (((d * NL_PROB_MAX) + 0.5));
463 }
464 
465 /** @} */
466 
467 /**
468  * @name Time Translations
469  * @{
470  */
471 
472 #ifndef USER_HZ
473 #define USER_HZ 100
474 #endif
475 
476 static uint32_t user_hz = USER_HZ;
477 static uint32_t psched_hz = USER_HZ;
478 
479 static double ticks_per_usec = 1.0f;
480 
481 /* Retrieves the configured HZ and ticks/us value in the kernel.
482  * The value is cached. Supported ways of getting it:
483  *
484  * 1) environment variable
485  * 2) /proc/net/psched and sysconf
486  *
487  * Supports the environment variables:
488  *   PROC_NET_PSCHED  - may point to psched file in /proc
489  *   PROC_ROOT        - may point to /proc fs */
get_psched_settings(void)490 static void get_psched_settings(void)
491 {
492 	char name[FILENAME_MAX];
493 	FILE *fd;
494 	int got_hz = 0;
495 	static volatile int initialized = 0;
496 	const char *ev;
497 	NL_LOCK(mutex);
498 
499 	if (initialized == 1)
500 		return;
501 
502 	nl_lock(&mutex);
503 
504 	if (initialized == 1)
505 		return;
506 
507 	if ((ev = getenv("HZ"))) {
508 		long hz = strtol(ev, NULL, 0);
509 
510 		if (LONG_MIN != hz && LONG_MAX != hz) {
511 			user_hz = hz;
512 			got_hz = 1;
513 		}
514 	}
515 
516 	if (!got_hz)
517 		user_hz = sysconf(_SC_CLK_TCK);
518 
519 	psched_hz = user_hz;
520 
521 	if ((ev = getenv("TICKS_PER_USEC"))) {
522 		double t = strtod(ev, NULL);
523 		ticks_per_usec = t;
524 	}
525 	else {
526 		if ((ev = getenv("PROC_NET_PSCHED")))
527 			snprintf(name, sizeof(name), "%s", ev);
528 		else if ((ev = getenv("PROC_ROOT")))
529 			snprintf(name, sizeof(name), "%s/net/psched", ev);
530 		else
531 			_nl_strncpy_assert(name, "/proc/net/psched", sizeof(name));
532 
533 		if ((fd = fopen(name, "re"))) {
534 			unsigned int ns_per_usec, ns_per_tick, nom, denom;
535 
536 			if (fscanf(fd, "%08x %08x %08x %08x",
537 			       &ns_per_usec, &ns_per_tick, &nom, &denom) != 4) {
538 				NL_DBG(1, "Fatal error: can not read psched settings from \"%s\". " \
539 				          "Try to set TICKS_PER_USEC, PROC_NET_PSCHED or PROC_ROOT " \
540 				          "environment variables\n", name);
541 				exit(1);
542 			}
543 
544 			ticks_per_usec = (double) ns_per_usec /
545 					 (double) ns_per_tick;
546 
547 			if (nom == 1000000)
548 				psched_hz = denom;
549 
550 			fclose(fd);
551 		}
552 	}
553 	initialized = 1;
554 
555 	nl_unlock(&mutex);
556 }
557 
558 
559 /**
560  * Return the value of HZ
561  */
nl_get_user_hz(void)562 int nl_get_user_hz(void)
563 {
564 	get_psched_settings();
565 	return user_hz;
566 }
567 
568 /**
569  * Return the value of packet scheduler HZ
570  */
nl_get_psched_hz(void)571 int nl_get_psched_hz(void)
572 {
573 	get_psched_settings();
574 	return psched_hz;
575 }
576 
577 /**
578  * Convert micro seconds to ticks
579  * @arg us		micro seconds
580  * @return number of ticks
581  */
nl_us2ticks(uint32_t us)582 uint32_t nl_us2ticks(uint32_t us)
583 {
584 	get_psched_settings();
585 	return us * ticks_per_usec;
586 }
587 
588 
589 /**
590  * Convert ticks to micro seconds
591  * @arg ticks		number of ticks
592  * @return microseconds
593  */
nl_ticks2us(uint32_t ticks)594 uint32_t nl_ticks2us(uint32_t ticks)
595 {
596 	get_psched_settings();
597 	return ticks / ticks_per_usec;
598 }
599 
nl_str2msec(const char * str,uint64_t * result)600 int nl_str2msec(const char *str, uint64_t *result)
601 {
602 	uint64_t total = 0, l;
603 	int plen;
604 	char *p;
605 
606 	do {
607 		l = strtoul(str, &p, 0);
608 		if (p == str)
609 			return -NLE_INVAL;
610 		else if (*p) {
611 			plen = strcspn(p, " \t");
612 
613 			if (!plen)
614 				total += l;
615 			else if (!strncasecmp(p, "sec", plen))
616 				total += (l * 1000);
617 			else if (!strncasecmp(p, "min", plen))
618 				total += (l * 1000*60);
619 			else if (!strncasecmp(p, "hour", plen))
620 				total += (l * 1000*60*60);
621 			else if (!strncasecmp(p, "day", plen))
622 				total += (l * 1000*60*60*24);
623 			else
624 				return -NLE_INVAL;
625 
626 			str = p + plen;
627 		} else
628 			total += l;
629 	} while (*str && *p);
630 
631 	*result = total;
632 
633 	return 0;
634 }
635 
636 /**
637  * Convert milliseconds to a character string
638  * @arg msec		number of milliseconds
639  * @arg buf		destination buffer
640  * @arg len		buffer length
641  *
642  * Converts milliseconds to a character string split up in days, hours,
643  * minutes, seconds, and milliseconds and stores it in the specified
644  * destination buffer.
645  *
646  * @return The destination buffer.
647  */
nl_msec2str(uint64_t msec,char * buf,size_t len)648 char * nl_msec2str(uint64_t msec, char *buf, size_t len)
649 {
650 	uint64_t split[5];
651 	size_t i;
652 	static const char *units[5] = {"d", "h", "m", "s", "msec"};
653 	char * const buf_orig = buf;
654 
655 	if (msec == 0) {
656 		snprintf(buf, len, "0msec");
657 		return buf_orig;
658 	}
659 
660 #define _SPLIT(idx, unit) if ((split[idx] = msec / unit)) msec %= unit
661 	_SPLIT(0, 86400000);	/* days */
662 	_SPLIT(1, 3600000);	/* hours */
663 	_SPLIT(2, 60000);	/* minutes */
664 	_SPLIT(3, 1000);	/* seconds */
665 #undef  _SPLIT
666 	split[4] = msec;
667 
668 	for (i = 0; i < ARRAY_SIZE(split) && len; i++) {
669 		int l;
670 		if (split[i] == 0)
671 			continue;
672 		l = snprintf(buf, len, "%s%" PRIu64 "%s",
673 			(buf==buf_orig) ? "" : " ", split[i], units[i]);
674 		buf += l;
675 		len -= l;
676 	}
677 
678 	return buf_orig;
679 }
680 
681 /** @} */
682 
683 /**
684  * @name Netlink Family Translations
685  * @{
686  */
687 
688 static const struct trans_tbl nlfamilies[] = {
689 	__ADD(NETLINK_ROUTE,route),
690 	__ADD(NETLINK_USERSOCK,usersock),
691 	__ADD(NETLINK_FIREWALL,firewall),
692 	__ADD(NETLINK_INET_DIAG,inetdiag),
693 	__ADD(NETLINK_NFLOG,nflog),
694 	__ADD(NETLINK_XFRM,xfrm),
695 	__ADD(NETLINK_SELINUX,selinux),
696 	__ADD(NETLINK_ISCSI,iscsi),
697 	__ADD(NETLINK_AUDIT,audit),
698 	__ADD(NETLINK_FIB_LOOKUP,fib_lookup),
699 	__ADD(NETLINK_CONNECTOR,connector),
700 	__ADD(NETLINK_NETFILTER,netfilter),
701 	__ADD(NETLINK_IP6_FW,ip6_fw),
702 	__ADD(NETLINK_DNRTMSG,dnrtmsg),
703 	__ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent),
704 	__ADD(NETLINK_GENERIC,generic),
705 	__ADD(NETLINK_SCSITRANSPORT,scsitransport),
706 	__ADD(NETLINK_ECRYPTFS,ecryptfs),
707 	__ADD(NETLINK_RDMA,rdma),
708 	__ADD(NETLINK_CRYPTO,crypto),
709 };
710 
nl_nlfamily2str(int family,char * buf,size_t size)711 char * nl_nlfamily2str(int family, char *buf, size_t size)
712 {
713 	return __type2str(family, buf, size, nlfamilies,
714 			  ARRAY_SIZE(nlfamilies));
715 }
716 
nl_str2nlfamily(const char * name)717 int nl_str2nlfamily(const char *name)
718 {
719 	return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies));
720 }
721 
722 /**
723  * @}
724  */
725 
726 /**
727  * @name Link Layer Protocol Translations
728  * @{
729  */
730 
731 static const struct trans_tbl llprotos[] = {
732 	{0, "generic"},
733 	__ADD(ARPHRD_NETROM,netrom),
734 	__ADD(ARPHRD_ETHER,ether),
735 	__ADD(ARPHRD_EETHER,eether),
736 	__ADD(ARPHRD_AX25,ax25),
737 	__ADD(ARPHRD_PRONET,pronet),
738 	__ADD(ARPHRD_CHAOS,chaos),
739 	__ADD(ARPHRD_IEEE802,ieee802),
740 	__ADD(ARPHRD_ARCNET,arcnet),
741 	__ADD(ARPHRD_APPLETLK,atalk),
742 	__ADD(ARPHRD_DLCI,dlci),
743 	__ADD(ARPHRD_ATM,atm),
744 	__ADD(ARPHRD_METRICOM,metricom),
745 	__ADD(ARPHRD_IEEE1394,ieee1394),
746 	__ADD(ARPHRD_EUI64,eui64),
747 	__ADD(ARPHRD_INFINIBAND,infiniband),
748 	__ADD(ARPHRD_SLIP,slip),
749 	__ADD(ARPHRD_CSLIP,cslip),
750 	__ADD(ARPHRD_SLIP6,slip6),
751 	__ADD(ARPHRD_CSLIP6,cslip6),
752 	__ADD(ARPHRD_RSRVD,rsrvd),
753 	__ADD(ARPHRD_ADAPT,adapt),
754 	__ADD(ARPHRD_ROSE,rose),
755 	__ADD(ARPHRD_X25,x25),
756 	__ADD(ARPHRD_HWX25,hwx25),
757 	__ADD(ARPHRD_CAN,can),
758 	__ADD(ARPHRD_PPP,ppp),
759 	__ADD(ARPHRD_CISCO,cisco),
760 	__ADD(ARPHRD_HDLC,hdlc),
761 	__ADD(ARPHRD_LAPB,lapb),
762 	__ADD(ARPHRD_DDCMP,ddcmp),
763 	__ADD(ARPHRD_RAWHDLC,rawhdlc),
764 	__ADD(ARPHRD_TUNNEL,ipip),
765 	__ADD(ARPHRD_TUNNEL6,tunnel6),
766 	__ADD(ARPHRD_FRAD,frad),
767 	__ADD(ARPHRD_SKIP,skip),
768 	__ADD(ARPHRD_LOOPBACK,loopback),
769 	__ADD(ARPHRD_LOCALTLK,localtlk),
770 	__ADD(ARPHRD_FDDI,fddi),
771 	__ADD(ARPHRD_BIF,bif),
772 	__ADD(ARPHRD_SIT,sit),
773 	__ADD(ARPHRD_IPDDP,ip/ddp),
774 	__ADD(ARPHRD_IPGRE,gre),
775 	__ADD(ARPHRD_PIMREG,pimreg),
776 	__ADD(ARPHRD_HIPPI,hippi),
777 	__ADD(ARPHRD_ASH,ash),
778 	__ADD(ARPHRD_ECONET,econet),
779 	__ADD(ARPHRD_IRDA,irda),
780 	__ADD(ARPHRD_FCPP,fcpp),
781 	__ADD(ARPHRD_FCAL,fcal),
782 	__ADD(ARPHRD_FCPL,fcpl),
783 	__ADD(ARPHRD_FCFABRIC,fcfb_0),
784 	__ADD(ARPHRD_FCFABRIC+1,fcfb_1),
785 	__ADD(ARPHRD_FCFABRIC+2,fcfb_2),
786 	__ADD(ARPHRD_FCFABRIC+3,fcfb_3),
787 	__ADD(ARPHRD_FCFABRIC+4,fcfb_4),
788 	__ADD(ARPHRD_FCFABRIC+5,fcfb_5),
789 	__ADD(ARPHRD_FCFABRIC+6,fcfb_6),
790 	__ADD(ARPHRD_FCFABRIC+7,fcfb_7),
791 	__ADD(ARPHRD_FCFABRIC+8,fcfb_8),
792 	__ADD(ARPHRD_FCFABRIC+9,fcfb_9),
793 	__ADD(ARPHRD_FCFABRIC+10,fcfb_10),
794 	__ADD(ARPHRD_FCFABRIC+11,fcfb_11),
795 	__ADD(ARPHRD_FCFABRIC+12,fcfb_12),
796 	__ADD(ARPHRD_IEEE802_TR,tr),
797 	__ADD(ARPHRD_IEEE80211,ieee802.11),
798 	__ADD(ARPHRD_IEEE80211_PRISM,ieee802.11_prism),
799 	__ADD(ARPHRD_IEEE80211_RADIOTAP,ieee802.11_radiotap),
800 	__ADD(ARPHRD_IEEE802154,ieee802.15.4),
801 	__ADD(ARPHRD_IEEE802154_MONITOR,ieee802.15.4_monitor),
802 	__ADD(ARPHRD_PHONET,phonet),
803 	__ADD(ARPHRD_PHONET_PIPE,phonet_pipe),
804 	__ADD(ARPHRD_CAIF,caif),
805 	__ADD(ARPHRD_IP6GRE,ip6gre),
806 	__ADD(ARPHRD_NETLINK,netlink),
807 	__ADD(ARPHRD_6LOWPAN,6lowpan),
808 	__ADD(ARPHRD_VOID,void),
809 	__ADD(ARPHRD_NONE,nohdr),
810 };
811 
nl_llproto2str(int llproto,char * buf,size_t len)812 char * nl_llproto2str(int llproto, char *buf, size_t len)
813 {
814 	return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
815 }
816 
nl_str2llproto(const char * name)817 int nl_str2llproto(const char *name)
818 {
819 	return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
820 }
821 
822 /** @} */
823 
824 
825 /**
826  * @name Ethernet Protocol Translations
827  * @{
828  */
829 
830 static const struct trans_tbl ether_protos[] = {
831 	__ADD(ETH_P_LOOP,loop),
832 	__ADD(ETH_P_PUP,pup),
833 	__ADD(ETH_P_PUPAT,pupat),
834 	__ADD(ETH_P_IP,ip),
835 	__ADD(ETH_P_X25,x25),
836 	__ADD(ETH_P_ARP,arp),
837 	__ADD(ETH_P_BPQ,bpq),
838 	__ADD(ETH_P_IEEEPUP,ieeepup),
839 	__ADD(ETH_P_IEEEPUPAT,ieeepupat),
840 	__ADD(ETH_P_DEC,dec),
841 	__ADD(ETH_P_DNA_DL,dna_dl),
842 	__ADD(ETH_P_DNA_RC,dna_rc),
843 	__ADD(ETH_P_DNA_RT,dna_rt),
844 	__ADD(ETH_P_LAT,lat),
845 	__ADD(ETH_P_DIAG,diag),
846 	__ADD(ETH_P_CUST,cust),
847 	__ADD(ETH_P_SCA,sca),
848 	__ADD(ETH_P_TEB,teb),
849 	__ADD(ETH_P_RARP,rarp),
850 	__ADD(ETH_P_ATALK,atalk),
851 	__ADD(ETH_P_AARP,aarp),
852 #ifdef ETH_P_8021Q
853 	__ADD(ETH_P_8021Q,802.1q),
854 #endif
855 	__ADD(ETH_P_IPX,ipx),
856 	__ADD(ETH_P_IPV6,ipv6),
857 	__ADD(ETH_P_PAUSE,pause),
858 	__ADD(ETH_P_SLOW,slow),
859 #ifdef ETH_P_WCCP
860 	__ADD(ETH_P_WCCP,wccp),
861 #endif
862 	__ADD(ETH_P_PPP_DISC,ppp_disc),
863 	__ADD(ETH_P_PPP_SES,ppp_ses),
864 	__ADD(ETH_P_MPLS_UC,mpls_uc),
865 	__ADD(ETH_P_MPLS_MC,mpls_mc),
866 	__ADD(ETH_P_ATMMPOA,atmmpoa),
867 	__ADD(ETH_P_LINK_CTL,link_ctl),
868 	__ADD(ETH_P_ATMFATE,atmfate),
869 	__ADD(ETH_P_PAE,pae),
870 	__ADD(ETH_P_AOE,aoe),
871 	__ADD(ETH_P_TIPC,tipc),
872 	__ADD(ETH_P_1588,ieee1588),
873 	__ADD(ETH_P_FCOE,fcoe),
874 	__ADD(ETH_P_FIP,fip),
875 	__ADD(ETH_P_EDSA,edsa),
876 	__ADD(ETH_P_EDP2,edp2),
877 	__ADD(ETH_P_802_3,802.3),
878 	__ADD(ETH_P_AX25,ax25),
879 	__ADD(ETH_P_ALL,all),
880 	__ADD(ETH_P_802_2,802.2),
881 	__ADD(ETH_P_SNAP,snap),
882 	__ADD(ETH_P_DDCMP,ddcmp),
883 	__ADD(ETH_P_WAN_PPP,wan_ppp),
884 	__ADD(ETH_P_PPP_MP,ppp_mp),
885 	__ADD(ETH_P_LOCALTALK,localtalk),
886 	__ADD(ETH_P_CAN,can),
887 	__ADD(ETH_P_PPPTALK,ppptalk),
888 	__ADD(ETH_P_TR_802_2,tr_802.2),
889 	__ADD(ETH_P_MOBITEX,mobitex),
890 	__ADD(ETH_P_CONTROL,control),
891 	__ADD(ETH_P_IRDA,irda),
892 	__ADD(ETH_P_ECONET,econet),
893 	__ADD(ETH_P_HDLC,hdlc),
894 	__ADD(ETH_P_ARCNET,arcnet),
895 	__ADD(ETH_P_DSA,dsa),
896 	__ADD(ETH_P_TRAILER,trailer),
897 	__ADD(ETH_P_PHONET,phonet),
898 	__ADD(ETH_P_IEEE802154,ieee802154),
899 	__ADD(ETH_P_CAIF,caif),
900 };
901 
nl_ether_proto2str(int eproto,char * buf,size_t len)902 char *nl_ether_proto2str(int eproto, char *buf, size_t len)
903 {
904 	return __type2str(eproto, buf, len, ether_protos,
905 			    ARRAY_SIZE(ether_protos));
906 }
907 
nl_str2ether_proto(const char * name)908 int nl_str2ether_proto(const char *name)
909 {
910 	return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
911 }
912 
913 /** @} */
914 
915 /**
916  * @name IP Protocol Translations
917  * @{
918  */
919 
nl_ip_proto2str(int proto,char * buf,size_t len)920 char *nl_ip_proto2str(int proto, char *buf, size_t len)
921 {
922 	if (nl_getprotobynumber(proto, buf, len))
923 		return buf;
924 
925 	snprintf(buf, len, "0x%x", proto);
926 	return buf;
927 }
928 
nl_str2ip_proto(const char * name)929 int nl_str2ip_proto(const char *name)
930 {
931 	unsigned long l;
932 	char *end;
933 	int p;
934 
935 	if (!name)
936 		return -NLE_INVAL;
937 
938 	p = nl_getprotobyname(name);
939 	if (p >= 0)
940 		return p;
941 
942 	l = strtoul(name, &end, 0);
943 	if (name == end || *end != '\0' || l > (unsigned long)INT_MAX)
944 		return -NLE_OBJ_NOTFOUND;
945 
946 	return (int) l;
947 }
948 
949 /** @} */
950 
951 /**
952  * @name Dumping Helpers
953  * @{
954  */
955 
956 /**
957  * Handle a new line while dumping
958  * @arg params		Dumping parameters
959  *
960  * This function must be called before dumping any onto a
961  * new line. It will ensure proper prefixing as specified
962  * by the dumping parameters.
963  *
964  * @note This function will NOT dump any newlines itself
965  */
nl_new_line(struct nl_dump_params * params)966 void nl_new_line(struct nl_dump_params *params)
967 {
968 	params->dp_line++;
969 
970 	if (params->dp_prefix) {
971 		int i;
972 		for (i = 0; i < params->dp_prefix; i++) {
973 			if (params->dp_fd)
974 				fprintf(params->dp_fd, " ");
975 			else if (params->dp_buf)
976 				strncat(params->dp_buf, " ",
977 					params->dp_buflen -
978 					strlen(params->dp_buf) - 1);
979 		}
980 	}
981 
982 	if (params->dp_nl_cb)
983 		params->dp_nl_cb(params, params->dp_line);
984 }
985 
dump_one(struct nl_dump_params * parms,const char * fmt,va_list args)986 static void dump_one(struct nl_dump_params *parms, const char *fmt,
987 		     va_list args)
988 {
989 	if (parms->dp_fd)
990 		vfprintf(parms->dp_fd, fmt, args);
991 	else if (parms->dp_buf || parms->dp_cb) {
992 		char *buf = NULL;
993 		if (vasprintf(&buf, fmt, args) >= 0) {
994 			if (parms->dp_cb)
995 				parms->dp_cb(parms, buf);
996 			else
997 				strncat(parms->dp_buf, buf,
998 					parms->dp_buflen -
999 					strlen(parms->dp_buf) - 1);
1000 			free(buf);
1001 		}
1002 	}
1003 }
1004 
1005 
1006 /**
1007  * Dump a formatted character string
1008  * @arg params		Dumping parameters
1009  * @arg fmt		printf style formatting string
1010  * @arg ...		Arguments to formatting string
1011  *
1012  * Dumps a printf style formatting string to the output device
1013  * as specified by the dumping parameters.
1014  */
nl_dump(struct nl_dump_params * params,const char * fmt,...)1015 void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
1016 {
1017 	va_list args;
1018 
1019 	va_start(args, fmt);
1020 	dump_one(params, fmt, args);
1021 	va_end(args);
1022 }
1023 
nl_dump_line(struct nl_dump_params * parms,const char * fmt,...)1024 void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...)
1025 {
1026 	va_list args;
1027 
1028 	nl_new_line(parms);
1029 
1030 	va_start(args, fmt);
1031 	dump_one(parms, fmt, args);
1032 	va_end(args);
1033 }
1034 
1035 
1036 /** @} */
1037 
1038 /** @cond SKIP */
1039 
__trans_list_add(int i,const char * a,struct nl_list_head * head)1040 int __trans_list_add(int i, const char *a, struct nl_list_head *head)
1041 {
1042 	struct trans_list *tl;
1043 
1044 	tl = calloc(1, sizeof(*tl));
1045 	if (!tl)
1046 		return -NLE_NOMEM;
1047 
1048 	tl->i = i;
1049 	tl->a = strdup(a);
1050 
1051 	nl_list_add_tail(&tl->list, head);
1052 
1053 	return 0;
1054 }
1055 
__trans_list_clear(struct nl_list_head * head)1056 void __trans_list_clear(struct nl_list_head *head)
1057 {
1058 	struct trans_list *tl, *next;
1059 
1060 	nl_list_for_each_entry_safe(tl, next, head, list) {
1061 		free(tl->a);
1062 		free(tl);
1063 	}
1064 
1065 	nl_init_list_head(head);
1066 }
1067 
__type2str(int type,char * buf,size_t len,const struct trans_tbl * tbl,size_t tbl_len)1068 char *__type2str(int type, char *buf, size_t len,
1069 		 const struct trans_tbl *tbl, size_t tbl_len)
1070 {
1071 	size_t i;
1072 
1073 	for (i = 0; i < tbl_len; i++) {
1074 		if (tbl[i].i == ((uint64_t)type)) {
1075 			snprintf(buf, len, "%s", tbl[i].a);
1076 			return buf;
1077 		}
1078 	}
1079 
1080 	snprintf(buf, len, "0x%x", (unsigned)type);
1081 	return buf;
1082 }
1083 
__list_type2str(int type,char * buf,size_t len,struct nl_list_head * head)1084 char *__list_type2str(int type, char *buf, size_t len,
1085 		      struct nl_list_head *head)
1086 {
1087 	struct trans_list *tl;
1088 
1089 	nl_list_for_each_entry(tl, head, list) {
1090 		if (tl->i == type) {
1091 			snprintf(buf, len, "%s", tl->a);
1092 			return buf;
1093 		}
1094 	}
1095 
1096 	snprintf(buf, len, "0x%x", type);
1097 	return buf;
1098 }
1099 
__flags2str(int flags,char * buf,size_t len,const struct trans_tbl * tbl,size_t tbl_len)1100 char *__flags2str(int flags, char *buf, size_t len,
1101 		  const struct trans_tbl *tbl, size_t tbl_len)
1102 {
1103 	size_t i;
1104 	int tmp = flags;
1105 
1106 	memset(buf, 0, len);
1107 
1108 	for (i = 0; i < tbl_len; i++) {
1109 		if (tbl[i].i & tmp) {
1110 			tmp &= ~tbl[i].i;
1111 			strncat(buf, tbl[i].a, len - strlen(buf) - 1);
1112 			if ((tmp & flags))
1113 				strncat(buf, ",", len - strlen(buf) - 1);
1114 		}
1115 	}
1116 
1117 	return buf;
1118 }
1119 
__str2type(const char * buf,const struct trans_tbl * tbl,size_t tbl_len)1120 int __str2type(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
1121 {
1122 	unsigned long l;
1123 	char *end;
1124 	size_t i;
1125 
1126 	if (*buf == '\0')
1127 		return -NLE_INVAL;
1128 
1129 	for (i = 0; i < tbl_len; i++)
1130 		if (!strcasecmp(tbl[i].a, buf))
1131 			return tbl[i].i;
1132 
1133 	l = strtoul(buf, &end, 0);
1134 	if (l == ULONG_MAX || *end != '\0')
1135 		return -NLE_OBJ_NOTFOUND;
1136 
1137 	return (int) l;
1138 }
1139 
__list_str2type(const char * buf,struct nl_list_head * head)1140 int __list_str2type(const char *buf, struct nl_list_head *head)
1141 {
1142 	struct trans_list *tl;
1143 	unsigned long l;
1144 	char *end;
1145 
1146 	if (*buf == '\0')
1147 		return -NLE_INVAL;
1148 
1149 	nl_list_for_each_entry(tl, head, list) {
1150 		if (!strcasecmp(tl->a, buf))
1151 			return tl->i;
1152 	}
1153 
1154 	l = strtoul(buf, &end, 0);
1155 	if (l == ULONG_MAX || *end != '\0')
1156 		return -NLE_OBJ_NOTFOUND;
1157 
1158 	return (int) l;
1159 }
1160 
__str2flags(const char * buf,const struct trans_tbl * tbl,size_t tbl_len)1161 int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
1162 {
1163 	int flags = 0;
1164 	size_t i;
1165 	size_t len; /* ptrdiff_t ? */
1166 	char *p = (char *) buf, *t;
1167 
1168 	for (;;) {
1169 		if (*p == ' ')
1170 			p++;
1171 
1172 		t = strchr(p, ',');
1173 		len = t ? ((size_t)(t - p)) : strlen(p);
1174 		for (i = 0; i < tbl_len; i++)
1175 			if (len == strlen(tbl[i].a) &&
1176 			    !strncasecmp(tbl[i].a, p, len))
1177 				flags |= tbl[i].i;
1178 
1179 		if (!t)
1180 			return flags;
1181 
1182 		p = ++t;
1183 	}
1184 
1185 	return 0;
1186 }
1187 
dump_from_ops(struct nl_object * obj,struct nl_dump_params * params)1188 void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params)
1189 {
1190 	int type = params->dp_type;
1191 
1192 	if (type < 0 || type > NL_DUMP_MAX)
1193 		BUG();
1194 
1195 	params->dp_line = 0;
1196 
1197 	if (params->dp_dump_msgtype) {
1198 #if 0
1199 		/* XXX */
1200 		char buf[64];
1201 
1202 		dp_dump_line(params, 0, "%s ",
1203 			     nl_cache_mngt_type2name(obj->ce_ops,
1204 			     			     obj->ce_ops->co_protocol,
1205 						     obj->ce_msgtype,
1206 						     buf, sizeof(buf)));
1207 #endif
1208 		params->dp_pre_dump = 1;
1209 	}
1210 
1211 	if (obj->ce_ops->oo_dump[type])
1212 		obj->ce_ops->oo_dump[type](obj, params);
1213 }
1214 
1215 /**
1216  * Check for library capabilities
1217  *
1218  * @arg	capability	capability identifier
1219  *
1220  * Check whether the loaded libnl library supports a certain capability.
1221  * This is useful so that applications can workaround known issues of
1222  * libnl that are fixed in newer library versions, without
1223  * having a hard dependency on the new version. It is also useful, for
1224  * capabilities that cannot easily be detected using autoconf tests.
1225  * The capabilities are integer constants with name NL_CAPABILITY_*.
1226  *
1227  * As this function is intended to detect capabilities at runtime,
1228  * you might not want to depend during compile time on the NL_CAPABILITY_*
1229  * names. Instead you can use their numeric values which are guaranteed not to
1230  * change meaning.
1231  *
1232  * @return non zero if libnl supports a certain capability, 0 otherwise.
1233  **/
nl_has_capability(int capability)1234 int nl_has_capability (int capability)
1235 {
1236 	static const uint8_t caps[ ( NL_CAPABILITY_MAX + 7 ) / 8  ] = {
1237 #define _NL_ASSERT(expr) ( 0 * sizeof(struct { unsigned int x: ( (!!(expr)) ? 1 : -1 ); }) )
1238 #define _NL_SETV(i, r, v) \
1239 		( _NL_ASSERT( (v) == 0 || (i) * 8 + (r) == (v) - 1 ) + \
1240 		  ( (v) == 0 ? 0 : (1 << (r)) ) )
1241 #define _NL_SET(i, v0, v1, v2, v3, v4, v5, v6, v7) \
1242 		[(i)] = ( \
1243 			_NL_SETV((i), 0, (v0)) | _NL_SETV((i), 4, (v4)) | \
1244 			_NL_SETV((i), 1, (v1)) | _NL_SETV((i), 5, (v5)) | \
1245 			_NL_SETV((i), 2, (v2)) | _NL_SETV((i), 6, (v6)) | \
1246 			_NL_SETV((i), 3, (v3)) | _NL_SETV((i), 7, (v7)) )
1247 		_NL_SET(0,
1248 			NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE,
1249 			NL_CAPABILITY_ROUTE_LINK_VETH_GET_PEER_OWN_REFERENCE,
1250 			NL_CAPABILITY_ROUTE_LINK_CLS_ADD_ACT_OWN_REFERENCE,
1251 			NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE,
1252 			NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP,
1253 			NL_CAPABILITY_ROUTE_ADDR_COMPARE_CACHEINFO,
1254 			NL_CAPABILITY_VERSION_3_2_26,
1255 			NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK),
1256 		_NL_SET(1,
1257 			NL_CAPABILITY_LINK_BUILD_CHANGE_REQUEST_SET_CHANGE,
1258 			NL_CAPABILITY_RTNL_NEIGH_GET_FILTER_AF_UNSPEC_FIX,
1259 			NL_CAPABILITY_VERSION_3_2_27,
1260 			NL_CAPABILITY_RTNL_LINK_VLAN_PROTOCOL_SERIALZE,
1261 			NL_CAPABILITY_RTNL_LINK_PARSE_GRE_REMOTE,
1262 			NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR,
1263 			NL_CAPABILITY_RTNL_LINK_VXLAN_IO_COMPARE,
1264 			NL_CAPABILITY_NL_OBJECT_DIFF64),
1265 		_NL_SET (2,
1266 			NL_CAPABILITY_XFRM_SA_KEY_SIZE,
1267 			NL_CAPABILITY_RTNL_ADDR_PEER_FIX,
1268 			NL_CAPABILITY_VERSION_3_2_28,
1269 			NL_CAPABILITY_RTNL_ADDR_PEER_ID_FIX,
1270 			NL_CAPABILITY_NL_ADDR_FILL_SOCKADDR,
1271 			NL_CAPABILITY_XFRM_SEC_CTX_LEN,
1272 			NL_CAPABILITY_LINK_BUILD_ADD_REQUEST_SET_CHANGE,
1273 			NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT),
1274 		_NL_SET (3,
1275 			NL_CAPABILITY_VERSION_3_2_29,
1276 			NL_CAPABILITY_XFRM_SP_SEC_CTX_LEN,
1277 			NL_CAPABILITY_VERSION_3_3_0,
1278 			NL_CAPABILITY_VERSION_3_4_0,
1279 			NL_CAPABILITY_ROUTE_FIX_VLAN_SET_EGRESS_MAP,
1280 			NL_CAPABILITY_VERSION_3_5_0,
1281 			NL_CAPABILITY_NL_OBJECT_IDENTICAL_PARTIAL,
1282 			NL_CAPABILITY_VERSION_3_6_0),
1283 		_NL_SET (4,
1284 			NL_CAPABILITY_VERSION_3_7_0,
1285 			NL_CAPABILITY_VERSION_3_8_0,
1286 			NL_CAPABILITY_VERSION_3_9_0,
1287 			NL_CAPABILITY_VERSION_3_10_0,
1288 			0, /* NL_CAPABILITY_VERSION_3_11_0 */
1289 			0, /* NL_CAPABILITY_VERSION_3_12_0 */
1290 			0, /* NL_CAPABILITY_VERSION_3_13_0 */
1291 			0),
1292 		/* IMPORTANT: these capability numbers are intended to be universal and stable
1293 		 * for libnl3. Don't allocate new numbers on your own that differ from upstream
1294 		 * libnl3.
1295 		 *
1296 		 * Instead register a capability number upstream too. We will take patches
1297 		 * for that. We especially take patches to register a capability number that is
1298 		 * only implemented in your fork of libnl3.
1299 		 *
1300 		 * If you really don't want that, use capabilities in the range 0x7000 to 0x7FFF.
1301 		 * (NL_CAPABILITY_IS_USER_RESERVED). Upstream libnl3 will not register conflicting
1302 		 * capabilities in that range.
1303 		 *
1304 		 * Obviously, only backport capability numbers to libnl versions that actually
1305 		 * implement that capability as well. */
1306 #undef _NL_SET
1307 #undef _NL_SETV
1308 #undef _NL_ASSERT
1309 	};
1310 
1311 	if (capability <= 0 || capability > NL_CAPABILITY_MAX)
1312 		return 0;
1313 	capability--;
1314 	return (caps[capability / 8] & (1 << (capability % 8))) != 0;
1315 }
1316 
1317 /** @endcond */
1318 
1319 /** @} */
1320