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