utils.c revision 3c56ed5787481a06703ffb25561df3dd56b447bd
11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/*
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * lib/utils.c		Utility Functions
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *	This library is free software; you can redistribute it and/or
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *	modify it under the terms of the GNU Lesser General Public
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *	License as published by the Free Software Foundation version 2.1
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *	of the License.
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @defgroup utils Utilities
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @{
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <netlink-local.h>
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <netlink/netlink.h>
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <netlink/utils.h>
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <linux/socket.h>
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Debug level
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint nl_debug = 0;
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistruct nl_dump_params nl_debug_dp = {
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	.dp_type = NL_DUMP_FULL,
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void __init nl_debug_init(void)
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	char *nldbg, *end;
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if ((nldbg = getenv("NLDBG"))) {
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		long level = strtol(nldbg, &end, 0);
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		if (nldbg != end)
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			nl_debug = level;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	nl_debug_dp.dp_fd = stderr;
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @name Error Code Helpers
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @{
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic char *errbuf;
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic int nlerrno;
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** @cond SKIP */
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint __nl_error(int err, const char *file, unsigned int line, const char *func,
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	       const char *fmt, ...)
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	char *user_err;
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	va_list args;
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (errbuf) {
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		free(errbuf);
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		errbuf = NULL;
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	nlerrno = err;
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (fmt) {
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		va_start(args, fmt);
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		vasprintf(&user_err, fmt, args);
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		va_end(args);
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#ifdef VERBOSE_ERRORS
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	asprintf(&errbuf, "%s:%u:%s: %s (errno = %s)",
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		 file, line, func, fmt ? user_err : "", strerror(err));
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#else
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	asprintf(&errbuf, "%s (errno = %s)",
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		 fmt ? user_err : "", strerror(err));
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (fmt)
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		free(user_err);
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	return -err;
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	FILE *fd;
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	char buf[128];
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	fd = fopen(path, "r");
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (fd == NULL)
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return nl_error(errno, "Unable to open file %s for reading",
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci				path);
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	while (fgets(buf, sizeof(buf), fd)) {
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		int goodlen, err;
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		long num;
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		char *end;
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		if (*buf == '#' || *buf == '\n' || *buf == '\r')
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			continue;
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		num = strtol(buf, &end, 0);
105		if (end == buf)
106			return nl_error(EINVAL, "Parsing error");
107
108		if (num == LONG_MIN || num == LONG_MAX)
109			return nl_error(errno, "Number of out range");
110
111		while (*end == ' ' || *end == '\t')
112			end++;
113
114		goodlen = strcspn(end, "#\r\n\t ");
115		if (goodlen == 0)
116			return nl_error(EINVAL, "Empty string");
117
118		end[goodlen] = '\0';
119
120		err = cb(num, end);
121		if (err < 0)
122			return err;
123	}
124
125	fclose(fd);
126
127	return 0;
128}
129
130/** @endcond */
131
132int nl_get_errno(void)
133{
134	return nlerrno;
135}
136
137
138/**
139 * Return error message for an error code
140 * @return error message
141 */
142char *nl_geterror(void)
143{
144	if (errbuf)
145		return errbuf;
146
147	if (nlerrno)
148		return strerror(nlerrno);
149
150	return "Sucess\n";
151}
152
153/**
154 * Print a libnl error message
155 * @arg s		error message prefix
156 *
157 * Prints the error message of the call that failed last.
158 *
159 * If s is not NULL and *s is not a null byte the argument
160 * string is printed, followed by a colon and a blank. Then
161 * the error message and a new-line.
162 */
163void nl_perror(const char *s)
164{
165	if (s && *s)
166		fprintf(stderr, "%s: %s\n", s, nl_geterror());
167	else
168		fprintf(stderr, "%s\n", nl_geterror());
169}
170
171/** @} */
172
173/**
174 * @name Unit Pretty-Printing
175 * @{
176 */
177
178/**
179 * Cancel down a byte counter
180 * @arg	l		byte counter
181 * @arg	unit		destination unit pointer
182 *
183 * Cancels down a byte counter until it reaches a reasonable
184 * unit. The chosen unit is assigned to \a unit.
185 *
186 * @return The cancelled down byte counter in the new unit.
187 */
188double nl_cancel_down_bytes(unsigned long long l, char **unit)
189{
190	if (l >= 1099511627776LL) {
191		*unit = "TiB";
192		return ((double) l) / 1099511627776LL;
193	} else if (l >= 1073741824) {
194		*unit = "GiB";
195		return ((double) l) / 1073741824;
196	} else if (l >= 1048576) {
197		*unit = "MiB";
198		return ((double) l) / 1048576;
199	} else if (l >= 1024) {
200		*unit = "KiB";
201		return ((double) l) / 1024;
202	} else {
203		*unit = "B";
204		return (double) l;
205	}
206}
207
208/**
209 * Cancel down a bit counter
210 * @arg	l		bit counter
211 * @arg unit		destination unit pointer
212 *
213 * Cancels downa bit counter until it reaches a reasonable
214 * unit. The chosen unit is assigned to \a unit.
215 *
216 * @return The cancelled down bit counter in the new unit.
217 */
218double nl_cancel_down_bits(unsigned long long l, char **unit)
219{
220	if (l >= 1099511627776ULL) {
221		*unit = "Tbit";
222		return ((double) l) / 1099511627776ULL;
223	} else if (l >= 1073741824) {
224		*unit = "Gbit";
225		return ((double) l) / 1073741824;
226	} else if (l >= 1048576) {
227		*unit = "Mbit";
228		return ((double) l) / 1048576;
229	} else if (l >= 1024) {
230		*unit = "Kbit";
231		return ((double) l) / 1024;
232	} else {
233		*unit = "bit";
234		return (double) l;
235	}
236
237}
238
239/**
240 * Cancel down a micro second value
241 * @arg	l		micro seconds
242 * @arg unit		destination unit pointer
243 *
244 * Cancels down a microsecond counter until it reaches a
245 * reasonable unit. The chosen unit is assigned to \a unit.
246 *
247 * @return The cancelled down microsecond in the new unit
248 */
249double nl_cancel_down_us(uint32_t l, char **unit)
250{
251	if (l >= 1000000) {
252		*unit = "s";
253		return ((double) l) / 1000000;
254	} else if (l >= 1000) {
255		*unit = "ms";
256		return ((double) l) / 1000;
257	} else {
258		*unit = "us";
259		return (double) l;
260	}
261}
262
263/** @} */
264
265/**
266 * @name Generic Unit Translations
267 * @{
268 */
269
270/**
271 * Convert a character string to a size
272 * @arg str		size encoded as character string
273 *
274 * Converts the specified size as character to the corresponding
275 * number of bytes.
276 *
277 * Supported formats are:
278 *  - b,kb/k,m/mb,gb/g for bytes
279 *  - bit,kbit/mbit/gbit
280 *
281 * @return The number of bytes or -1 if the string is unparseable
282 */
283long nl_size2int(const char *str)
284{
285	char *p;
286	long l = strtol(str, &p, 0);
287	if (p == str)
288		return -1;
289
290	if (*p) {
291		if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
292			l *= 1024;
293		else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
294			l *= 1024*1024*1024;
295		else if (!strcasecmp(p, "gbit"))
296			l *= 1024*1024*1024/8;
297		else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
298			l *= 1024*1024;
299		else if (!strcasecmp(p, "mbit"))
300			l *= 1024*1024/8;
301		else if (!strcasecmp(p, "kbit"))
302			l *= 1024/8;
303		else if (!strcasecmp(p, "bit"))
304			l /= 8;
305		else if (strcasecmp(p, "b") != 0)
306			return -1;
307	}
308
309	return l;
310}
311
312/**
313 * Convert a character string to a probability
314 * @arg str		probability encoded as character string
315 *
316 * Converts the specified probability as character to the
317 * corresponding probability number.
318 *
319 * Supported formats are:
320 *  - 0.0-1.0
321 *  - 0%-100%
322 *
323 * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
324 */
325long nl_prob2int(const char *str)
326{
327	char *p;
328	double d = strtod(str, &p);
329
330	if (p == str)
331		return -1;
332
333	if (d > 1.0)
334		d /= 100.0f;
335
336	if (d > 1.0f || d < 0.0f)
337		return -1;
338
339	if (*p && strcmp(p, "%") != 0)
340		return -1;
341
342	return rint(d * NL_PROB_MAX);
343}
344
345/** @} */
346
347/**
348 * @name Time Translations
349 * @{
350 */
351
352#ifdef USER_HZ
353static uint32_t user_hz = USER_HZ;
354#else
355static uint32_t user_hz = 100;
356#endif
357
358static double ticks_per_usec = 1.0f;
359
360/* Retrieves the configured HZ and ticks/us value in the kernel.
361 * The value is cached. Supported ways of getting it:
362 *
363 * 1) environment variable
364 * 2) /proc/net/psched and sysconf
365 *
366 * Supports the environment variables:
367 *   PROC_NET_PSCHED  - may point to psched file in /proc
368 *   PROC_ROOT        - may point to /proc fs */
369static void __init get_psched_settings(void)
370{
371	char name[FILENAME_MAX];
372	FILE *fd;
373	int got_hz = 0, got_tick = 0;
374
375	if (getenv("HZ")) {
376		long hz = strtol(getenv("HZ"), NULL, 0);
377
378		if (LONG_MIN != hz && LONG_MAX != hz) {
379			user_hz = hz;
380			got_hz = 1;
381		}
382	}
383
384	if (!got_hz)
385		user_hz = sysconf(_SC_CLK_TCK);
386
387	if (getenv("TICKS_PER_USEC")) {
388		double t = strtod(getenv("TICKS_PER_USEC"), NULL);
389
390		ticks_per_usec = t;
391		got_tick = 1;
392	}
393
394
395	if (getenv("PROC_NET_PSCHED"))
396		snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
397	else if (getenv("PROC_ROOT"))
398		snprintf(name, sizeof(name), "%s/net/psched",
399			 getenv("PROC_ROOT"));
400	else
401		strncpy(name, "/proc/net/psched", sizeof(name) - 1);
402
403	if ((fd = fopen(name, "r"))) {
404		uint32_t tick, us, nom;
405		int r = fscanf(fd, "%08x%08x%08x%*08x", &tick, &us, &nom);
406
407		if (4 == r && nom == 1000000 && !got_tick)
408			ticks_per_usec = (double)tick/(double)us;
409
410		fclose(fd);
411	}
412}
413
414
415/**
416 * Return the value of HZ
417 */
418int nl_get_hz(void)
419{
420	return user_hz;
421}
422
423
424/**
425 * Convert micro seconds to ticks
426 * @arg us		micro seconds
427 * @return number of ticks
428 */
429uint32_t nl_us2ticks(uint32_t us)
430{
431	return us * ticks_per_usec;
432}
433
434
435/**
436 * Convert ticks to micro seconds
437 * @arg ticks		number of ticks
438 * @return microseconds
439 */
440uint32_t nl_ticks2us(uint32_t ticks)
441{
442	return ticks / ticks_per_usec;
443}
444
445long nl_time2int(const char *str)
446{
447	char *p;
448	long l = strtol(str, &p, 0);
449	if (p == str)
450		return -1;
451
452	if (*p) {
453		if (!strcasecmp(p, "min") == 0 || !strcasecmp(p, "m"))
454			l *= 60;
455		else if (!strcasecmp(p, "hour") || !strcasecmp(p, "h"))
456			l *= 60*60;
457		else if (!strcasecmp(p, "day") || !strcasecmp(p, "d"))
458			l *= 60*60*24;
459		else if (strcasecmp(p, "s") != 0)
460			return -1;
461	}
462
463	return l;
464}
465
466/**
467 * Convert milliseconds to a character string
468 * @arg msec		number of milliseconds
469 * @arg buf		destination buffer
470 * @arg len		buffer length
471 *
472 * Converts milliseconds to a character string split up in days, hours,
473 * minutes, seconds, and milliseconds and stores it in the specified
474 * destination buffer.
475 *
476 * @return The destination buffer.
477 */
478char * nl_msec2str(uint64_t msec, char *buf, size_t len)
479{
480	int i, split[5];
481	char *units[] = {"d", "h", "m", "s", "msec"};
482
483#define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit
484	_SPLIT(0, 86400000);	/* days */
485	_SPLIT(1, 3600000);	/* hours */
486	_SPLIT(2, 60000);	/* minutes */
487	_SPLIT(3, 1000);	/* seconds */
488#undef  _SPLIT
489	split[4] = msec;
490
491	memset(buf, 0, len);
492
493	for (i = 0; i < ARRAY_SIZE(split); i++) {
494		if (split[i] > 0) {
495			char t[64];
496			snprintf(t, sizeof(t), "%s%d%s",
497				 strlen(buf) ? " " : "", split[i], units[i]);
498			strncat(buf, t, len - strlen(buf) - 1);
499		}
500	}
501
502	return buf;
503}
504
505/** @} */
506
507/**
508 * @name Link Layer Protocol Translations
509 * @{
510 */
511
512static struct trans_tbl llprotos[] = {
513	{0, "generic"},
514	__ADD(ARPHRD_ETHER,ether)
515	__ADD(ARPHRD_EETHER,eether)
516	__ADD(ARPHRD_AX25,ax25)
517	__ADD(ARPHRD_PRONET,pronet)
518	__ADD(ARPHRD_CHAOS,chaos)
519	__ADD(ARPHRD_IEEE802,ieee802)
520	__ADD(ARPHRD_ARCNET,arcnet)
521	__ADD(ARPHRD_APPLETLK,atalk)
522	__ADD(ARPHRD_DLCI,dlci)
523	__ADD(ARPHRD_ATM,atm)
524	__ADD(ARPHRD_METRICOM,metricom)
525	__ADD(ARPHRD_IEEE1394,ieee1394)
526#ifdef ARPHRD_EUI64
527	__ADD(ARPHRD_EUI64,eui64)
528#endif
529	__ADD(ARPHRD_INFINIBAND,infiniband)
530	__ADD(ARPHRD_SLIP,slip)
531	__ADD(ARPHRD_CSLIP,cslip)
532	__ADD(ARPHRD_SLIP6,slip6)
533	__ADD(ARPHRD_CSLIP6,cslip6)
534	__ADD(ARPHRD_RSRVD,rsrvd)
535	__ADD(ARPHRD_ADAPT,adapt)
536	__ADD(ARPHRD_ROSE,rose)
537	__ADD(ARPHRD_X25,x25)
538#ifdef ARPHRD_HWX25
539	__ADD(ARPHRD_HWX25,hwx25)
540#endif
541	__ADD(ARPHRD_PPP,ppp)
542	__ADD(ARPHRD_HDLC,hdlc)
543	__ADD(ARPHRD_LAPB,lapb)
544	__ADD(ARPHRD_DDCMP,ddcmp)
545	__ADD(ARPHRD_RAWHDLC,rawhdlc)
546	__ADD(ARPHRD_TUNNEL,ipip)
547	__ADD(ARPHRD_TUNNEL6,tunnel6)
548	__ADD(ARPHRD_FRAD,frad)
549	__ADD(ARPHRD_SKIP,skip)
550	__ADD(ARPHRD_LOOPBACK,loopback)
551	__ADD(ARPHRD_LOCALTLK,localtlk)
552	__ADD(ARPHRD_FDDI,fddi)
553	__ADD(ARPHRD_BIF,bif)
554	__ADD(ARPHRD_SIT,sit)
555	__ADD(ARPHRD_IPDDP,ip/ddp)
556	__ADD(ARPHRD_IPGRE,gre)
557	__ADD(ARPHRD_PIMREG,pimreg)
558	__ADD(ARPHRD_HIPPI,hippi)
559	__ADD(ARPHRD_ASH,ash)
560	__ADD(ARPHRD_ECONET,econet)
561	__ADD(ARPHRD_IRDA,irda)
562	__ADD(ARPHRD_FCPP,fcpp)
563	__ADD(ARPHRD_FCAL,fcal)
564	__ADD(ARPHRD_FCPL,fcpl)
565	__ADD(ARPHRD_FCFABRIC,fcfb_0)
566	__ADD(ARPHRD_FCFABRIC+1,fcfb_1)
567	__ADD(ARPHRD_FCFABRIC+2,fcfb_2)
568	__ADD(ARPHRD_FCFABRIC+3,fcfb_3)
569	__ADD(ARPHRD_FCFABRIC+4,fcfb_4)
570	__ADD(ARPHRD_FCFABRIC+5,fcfb_5)
571	__ADD(ARPHRD_FCFABRIC+6,fcfb_6)
572	__ADD(ARPHRD_FCFABRIC+7,fcfb_7)
573	__ADD(ARPHRD_FCFABRIC+8,fcfb_8)
574	__ADD(ARPHRD_FCFABRIC+9,fcfb_9)
575	__ADD(ARPHRD_FCFABRIC+10,fcfb_10)
576	__ADD(ARPHRD_FCFABRIC+11,fcfb_11)
577	__ADD(ARPHRD_FCFABRIC+12,fcfb_12)
578	__ADD(ARPHRD_IEEE802_TR,tr)
579	__ADD(ARPHRD_IEEE80211,ieee802.11)
580#ifdef ARPHRD_IEEE80211_PRISM
581	__ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
582#endif
583#ifdef ARPHRD_VOID
584	__ADD(ARPHRD_VOID,void)
585#endif
586};
587
588char * nl_llproto2str(int llproto, char *buf, size_t len)
589{
590	return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
591}
592
593int nl_str2llproto(const char *name)
594{
595	return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
596}
597
598/** @} */
599
600
601/**
602 * @name Ethernet Protocol Translations
603 * @{
604 */
605
606static struct trans_tbl ether_protos[] = {
607	__ADD(ETH_P_LOOP,loop)
608	__ADD(ETH_P_PUP,pup)
609	__ADD(ETH_P_PUPAT,pupat)
610	__ADD(ETH_P_IP,ip)
611	__ADD(ETH_P_X25,x25)
612	__ADD(ETH_P_ARP,arp)
613	__ADD(ETH_P_BPQ,bpq)
614	__ADD(ETH_P_IEEEPUP,ieeepup)
615	__ADD(ETH_P_IEEEPUPAT,ieeepupat)
616	__ADD(ETH_P_DEC,dec)
617	__ADD(ETH_P_DNA_DL,dna_dl)
618	__ADD(ETH_P_DNA_RC,dna_rc)
619	__ADD(ETH_P_DNA_RT,dna_rt)
620	__ADD(ETH_P_LAT,lat)
621	__ADD(ETH_P_DIAG,diag)
622	__ADD(ETH_P_CUST,cust)
623	__ADD(ETH_P_SCA,sca)
624	__ADD(ETH_P_RARP,rarp)
625	__ADD(ETH_P_ATALK,atalk)
626	__ADD(ETH_P_AARP,aarp)
627#ifdef ETH_P_8021Q
628	__ADD(ETH_P_8021Q,802.1q)
629#endif
630	__ADD(ETH_P_IPX,ipx)
631	__ADD(ETH_P_IPV6,ipv6)
632#ifdef ETH_P_WCCP
633	__ADD(ETH_P_WCCP,wccp)
634#endif
635	__ADD(ETH_P_PPP_DISC,ppp_disc)
636	__ADD(ETH_P_PPP_SES,ppp_ses)
637	__ADD(ETH_P_MPLS_UC,mpls_uc)
638	__ADD(ETH_P_MPLS_MC,mpls_mc)
639	__ADD(ETH_P_ATMMPOA,atmmpoa)
640	__ADD(ETH_P_ATMFATE,atmfate)
641	__ADD(ETH_P_EDP2,edp2)
642	__ADD(ETH_P_802_3,802.3)
643	__ADD(ETH_P_AX25,ax25)
644	__ADD(ETH_P_ALL,all)
645	__ADD(ETH_P_802_2,802.2)
646	__ADD(ETH_P_SNAP,snap)
647	__ADD(ETH_P_DDCMP,ddcmp)
648	__ADD(ETH_P_WAN_PPP,wan_ppp)
649	__ADD(ETH_P_PPP_MP,ppp_mp)
650	__ADD(ETH_P_LOCALTALK,localtalk)
651	__ADD(ETH_P_PPPTALK,ppptalk)
652	__ADD(ETH_P_TR_802_2,tr_802.2)
653	__ADD(ETH_P_MOBITEX,mobitex)
654	__ADD(ETH_P_CONTROL,control)
655	__ADD(ETH_P_IRDA,irda)
656	__ADD(ETH_P_ECONET,econet)
657	__ADD(ETH_P_HDLC,hdlc)
658};
659
660char *nl_ether_proto2str(int eproto, char *buf, size_t len)
661{
662	return __type2str(eproto, buf, len, ether_protos,
663			    ARRAY_SIZE(ether_protos));
664}
665
666int nl_str2ether_proto(const char *name)
667{
668	return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
669}
670
671/** @} */
672
673/**
674 * @name IP Protocol Translations
675 * @{
676 */
677
678char *nl_ip_proto2str(int proto, char *buf, size_t len)
679{
680	struct protoent *p = getprotobynumber(proto);
681
682	if (p) {
683		snprintf(buf, len, "%s", p->p_name);
684		return buf;
685	}
686
687	snprintf(buf, len, "0x%x", proto);
688	return buf;
689}
690
691int nl_str2ip_proto(const char *name)
692{
693	struct protoent *p = getprotobyname(name);
694	unsigned long l;
695	char *end;
696
697	if (p)
698		return p->p_proto;
699
700	l = strtoul(name, &end, 0);
701	if (l == ULONG_MAX || *end != '\0')
702		return -1;
703
704	return (int) l;
705}
706
707/** @} */
708
709/**
710 * @name Dumping Helpers
711 * @{
712 */
713
714/**
715 * Handle a new line while dumping
716 * @arg params		Dumping parameters
717 * @arg line		Number of lines dumped already.
718 *
719 * This function must be called before dumping any onto a
720 * new line. It will ensure proper prefixing as specified
721 * by the dumping parameters.
722 *
723 * @note This function will NOT dump any newlines itself
724 */
725void nl_new_line(struct nl_dump_params *params, int line)
726{
727	if (params->dp_prefix) {
728		int i;
729		for (i = 0; i < params->dp_prefix; i++) {
730			if (params->dp_fd)
731				fprintf(params->dp_fd, " ");
732			else if (params->dp_buf)
733				strncat(params->dp_buf, " ",
734					params->dp_buflen -
735					sizeof(params->dp_buf) - 1);
736		}
737	}
738
739	if (params->dp_nl_cb)
740		params->dp_nl_cb(params, line);
741}
742
743/**
744 * Dump a formatted character string
745 * @arg params		Dumping parameters
746 * @arg fmt		printf style formatting string
747 * @arg ...		Arguments to formatting string
748 *
749 * Dumps a printf style formatting string to the output device
750 * as specified by the dumping parameters.
751 */
752void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
753{
754	va_list args;
755
756	va_start(args, fmt);
757	__dp_dump(params, fmt, args);
758	va_end(args);
759}
760
761/** @} */
762
763/** @} */
764