addr.c revision 44d362409d5469aed47d19e7908d19bd194493a
193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)/*
293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * lib/addr.c		Abstract Address
393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *
493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *	This library is free software; you can redistribute it and/or
593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *	modify it under the terms of the GNU Lesser General Public
693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *	License as published by the Free Software Foundation version 2.1
793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *	of the License.
893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *
993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
1093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) */
1193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
1293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)/**
1393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * @ingroup utils
1493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * @defgroup addr Abstract Address
1593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) *
1693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * @par 1) Transform character string to abstract address
1793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * @code
1893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC);
1993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
2093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * nl_addr_put(a);
2193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC);
2293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
2393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * nl_addr_put(a);
2493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * @endcode
2593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * @{
2693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) */
2793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <netlink-local.h>
2993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <netlink/netlink.h>
3093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <netlink/utils.h>
31591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include <netlink/addr.h>
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include <linux/socket.h>
3393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
3493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)/* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
3593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) * this, probably Alexey. */
3609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static inline uint16_t dn_ntohs(uint16_t addr)
3709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
38591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch	union {
39591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch		uint8_t byte[2];
40591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch		uint16_t word;
418abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)	} u = {
428abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)		.word = addr,
43591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch	};
44591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
45591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch	return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8);
46591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
47591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
48591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochstatic inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
49591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch			   size_t *pos, size_t len, int *started)
508abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles){
518abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)	uint16_t tmp = *addr / scale;
52591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
53591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch	if (*pos == len)
5493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)		return 1;
55
56	if (((tmp) > 0) || *started || (scale == 1)) {
57		*str = tmp + '0';
58		*started = 1;
59		(*pos)++;
60		*addr -= (tmp * scale);
61	}
62
63	return 0;
64}
65
66static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str,
67			     size_t len)
68{
69	uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf);
70	uint16_t area = addr >> 10;
71	size_t pos = 0;
72	int started = 0;
73
74	if (addrlen != 2)
75		return NULL;
76
77	addr &= 0x03ff;
78
79	if (len == 0)
80		return str;
81
82	if (do_digit(str + pos, &area, 10, &pos, len, &started))
83		return str;
84
85	if (do_digit(str + pos, &area, 1, &pos, len, &started))
86		return str;
87
88	if (pos == len)
89		return str;
90
91	*(str + pos) = '.';
92	pos++;
93	started = 0;
94
95	if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
96		return str;
97
98	if (do_digit(str + pos, &addr, 100, &pos, len, &started))
99		return str;
100
101	if (do_digit(str + pos, &addr, 10, &pos, len, &started))
102		return str;
103
104	if (do_digit(str + pos, &addr, 1, &pos, len, &started))
105		return str;
106
107	if (pos == len)
108		return str;
109
110	*(str + pos) = 0;
111
112	return str;
113}
114
115static int dnet_num(const char *src, uint16_t * dst)
116{
117	int rv = 0;
118	int tmp;
119	*dst = 0;
120
121	while ((tmp = *src++) != 0) {
122		tmp -= '0';
123		if ((tmp < 0) || (tmp > 9))
124			return rv;
125
126		rv++;
127		(*dst) *= 10;
128		(*dst) += tmp;
129	}
130
131	return rv;
132}
133
134static inline int dnet_pton(const char *src, char *addrbuf)
135{
136	uint16_t area = 0;
137	uint16_t node = 0;
138	int pos;
139
140	pos = dnet_num(src, &area);
141	if ((pos == 0) || (area > 63) ||
142	    ((*(src + pos) != '.') && (*(src + pos) != ',')))
143		return -EINVAL;
144
145	pos = dnet_num(src + pos + 1, &node);
146	if ((pos == 0) || (node > 1023))
147		return -EINVAL;
148
149	*(uint16_t *)addrbuf = dn_ntohs((area << 10) | node);
150
151	return 1;
152}
153
154/**
155 * @name Creating Abstract Addresses
156 * @{
157 */
158
159/**
160 * Allocate new abstract address object.
161 * @arg maxsize		Maximum size of the binary address.
162 * @return Newly allocated address object or NULL
163 */
164struct nl_addr *nl_addr_alloc(size_t maxsize)
165{
166	struct nl_addr *addr;
167
168	addr = calloc(1, sizeof(*addr) + maxsize);
169	if (!addr) {
170		nl_errno(ENOMEM);
171		return NULL;
172	}
173
174	addr->a_refcnt = 1;
175	addr->a_maxsize = maxsize;
176
177	return addr;
178}
179
180/**
181 * Allocate new abstract address object based on a binary address.
182 * @arg family		Address family.
183 * @arg buf		Buffer containing the binary address.
184 * @arg size		Length of binary address buffer.
185 * @return Newly allocated address handle or NULL
186 */
187struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
188{
189	struct nl_addr *addr;
190
191	addr = nl_addr_alloc(size);
192	if (!addr)
193		return NULL;
194
195	addr->a_family = family;
196	addr->a_len = size;
197	addr->a_prefixlen = size*8;
198
199	if (size)
200		memcpy(addr->a_addr, buf, size);
201
202	return addr;
203}
204
205/**
206 * Allocate abstract address object based on a character string
207 * @arg addrstr		Address represented as character string.
208 * @arg hint		Address family hint or AF_UNSPEC.
209 *
210 * Regognizes the following address formats:
211 *@code
212 *  Format                      Len                Family
213 *  ----------------------------------------------------------------
214 *  IPv6 address format         16                 AF_INET6
215 *  ddd.ddd.ddd.ddd             4                  AF_INET
216 *  HH:HH:HH:HH:HH:HH           6                  AF_LLC
217 *  AA{.|,}NNNN                 2                  AF_DECnet
218 *  HH:HH:HH:...                variable           AF_UNSPEC
219 * @endcode
220 *
221 *  Special values:
222 *    - none: All bits and length set to 0.
223 *    - {default|all|any}: All bits set to 0, length based on hint or
224 *                         AF_INET if no hint is given.
225 *
226 * The prefix length may be appened at the end prefixed with a
227 * slash, e.g. 10.0.0.0/8.
228 *
229 * @return Newly allocated abstract address object or NULL.
230 */
231struct nl_addr *nl_addr_parse(const char *addrstr, int hint)
232{
233	int err, copy = 0, len = 0, family = AF_UNSPEC;
234	char *str, *prefix, buf[32];
235	struct nl_addr *addr = NULL; /* gcc ain't that smart */
236
237	str = strdup(addrstr);
238	if (!str) {
239		err = nl_errno(ENOMEM);
240		goto errout;
241	}
242
243	prefix = strchr(str, '/');
244	if (prefix)
245		*prefix = '\0';
246
247	if (!strcasecmp(str, "none")) {
248		family = hint;
249		goto prefix;
250	}
251
252	if (!strcasecmp(str, "default") ||
253	    !strcasecmp(str, "all") ||
254	    !strcasecmp(str, "any")) {
255
256		switch (hint) {
257			case AF_INET:
258			case AF_UNSPEC:
259				/* Kind of a hack, we assume that if there is
260				 * no hint given the user wants to have a IPv4
261				 * address given back. */
262				family = AF_INET;
263				len = 4;
264				goto prefix;
265
266			case AF_INET6:
267				family = AF_INET6;
268				len = 16;
269				goto prefix;
270
271			case AF_LLC:
272				family = AF_LLC;
273				len = 6;
274				goto prefix;
275
276			default:
277				err = nl_error(EINVAL, "Unsuported address" \
278				    "family for default address");
279				goto errout;
280		}
281	}
282
283	copy = 1;
284
285	if (hint == AF_INET || hint == AF_UNSPEC) {
286		if (inet_pton(AF_INET, str, buf) > 0) {
287			family = AF_INET;
288			len = 4;
289			goto prefix;
290		}
291		if (hint == AF_INET) {
292			err = nl_error(EINVAL, "Invalid IPv4 address");
293			goto errout;
294		}
295	}
296
297	if (hint == AF_INET6 || hint == AF_UNSPEC) {
298		if (inet_pton(AF_INET6, str, buf) > 0) {
299			family = AF_INET6;
300			len = 16;
301			goto prefix;
302		}
303		if (hint == AF_INET6) {
304			err = nl_error(EINVAL, "Invalid IPv6 address");
305			goto errout;
306		}
307	}
308
309	if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) {
310		unsigned int a, b, c, d, e, f;
311
312		if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
313		    &a, &b, &c, &d, &e, &f) == 6) {
314			family = AF_LLC;
315			len = 6;
316			buf[0] = (unsigned char) a;
317			buf[1] = (unsigned char) b;
318			buf[2] = (unsigned char) c;
319			buf[3] = (unsigned char) d;
320			buf[4] = (unsigned char) e;
321			buf[5] = (unsigned char) f;
322			goto prefix;
323		}
324
325		if (hint == AF_LLC) {
326			err = nl_error(EINVAL, "Invalid link layer address");
327			goto errout;
328		}
329	}
330
331	if ((hint == AF_DECnet || hint == AF_UNSPEC) &&
332	    (strchr(str, '.') || strchr(str, ','))) {
333		if (dnet_pton(str, buf) > 0) {
334			family = AF_DECnet;
335			len = 2;
336			goto prefix;
337		}
338		if (hint == AF_DECnet) {
339			err = nl_error(EINVAL, "Invalid DECnet address");
340			goto errout;
341		}
342	}
343
344	if (hint == AF_UNSPEC && strchr(str, ':')) {
345		int i = 0;
346		char *s = str, *p;
347		for (;;) {
348			long l = strtol(s, &p, 16);
349
350			if (s == p || l > 0xff || i >= sizeof(buf)) {
351				err = -EINVAL;
352				goto errout;
353			}
354
355			buf[i++] = (unsigned char) l;
356			if (*p == '\0')
357				break;
358			s = ++p;
359		}
360
361		len = i;
362		family = AF_UNSPEC;
363		goto prefix;
364	}
365
366	err = nl_error(EINVAL, "Invalid address");
367	goto errout;
368
369prefix:
370	addr = nl_addr_alloc(len);
371	if (!addr) {
372		err = nl_errno(ENOMEM);
373		goto errout;
374	}
375
376	nl_addr_set_family(addr, family);
377
378	if (copy)
379		nl_addr_set_binary_addr(addr, buf, len);
380
381	if (prefix) {
382		char *p;
383		long pl = strtol(++prefix, &p, 0);
384		if (p == prefix) {
385			nl_addr_destroy(addr);
386			err = -EINVAL;
387			goto errout;
388		}
389		nl_addr_set_prefixlen(addr, pl);
390	} else
391		nl_addr_set_prefixlen(addr, len * 8);
392
393	err = 0;
394errout:
395	free(str);
396
397	return err ? NULL : addr;
398}
399
400/**
401 * Clone existing abstract address object.
402 * @arg addr		Abstract address object.
403 * @return Newly allocated abstract address object being a duplicate of the
404 *         specified address object or NULL if a failure occured.
405 */
406struct nl_addr *nl_addr_clone(struct nl_addr *addr)
407{
408	struct nl_addr *new;
409
410	new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len);
411	if (new)
412		new->a_prefixlen = addr->a_prefixlen;
413
414	return new;
415}
416
417/** @} */
418
419/**
420 * @name Destroying Abstract Addresses
421 * @{
422 */
423
424/**
425 * Destroy abstract address object.
426 * @arg addr		Abstract address object.
427 */
428void nl_addr_destroy(struct nl_addr *addr)
429{
430	if (!addr)
431		return;
432
433	if (addr->a_refcnt != 1)
434		BUG();
435
436	free(addr);
437}
438
439/** @} */
440
441/**
442 * @name Managing Usage References
443 * @{
444 */
445
446struct nl_addr *nl_addr_get(struct nl_addr *addr)
447{
448	addr->a_refcnt++;
449
450	return addr;
451}
452
453void nl_addr_put(struct nl_addr *addr)
454{
455	if (!addr)
456		return;
457
458	if (addr->a_refcnt == 1)
459		nl_addr_destroy(addr);
460	else
461		addr->a_refcnt--;
462}
463
464/**
465 * Check whether an abstract address object is shared.
466 * @arg addr		Abstract address object.
467 * @return Non-zero if the abstract address object is shared, otherwise 0.
468 */
469int nl_addr_shared(struct nl_addr *addr)
470{
471	return addr->a_refcnt > 1;
472}
473
474/** @} */
475
476/**
477 * @name Miscellaneous
478 * @{
479 */
480
481/**
482 * Compares two abstract address objects.
483 * @arg a		A abstract address object.
484 * @arg b		Another abstract address object.
485 *
486 * @return Integer less than, equal to or greather than zero if \c is found,
487 *         respectively to be less than, to, or be greater than \c b.
488 */
489int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
490{
491	int d = a->a_family - b->a_family;
492
493	if (d == 0) {
494		d = a->a_len - b->a_len;
495
496		if (a->a_len && d == 0)
497			return memcmp(a->a_addr, b->a_addr, a->a_len);
498	}
499
500	return d;
501}
502
503/**
504 * Compares the prefix of two abstract address objects.
505 * @arg a		A abstract address object.
506 * @arg b		Another abstract address object.
507 *
508 * @return Integer less than, equal to or greather than zero if \c is found,
509 *         respectively to be less than, to, or be greater than \c b.
510 */
511int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
512{
513	int d = a->a_family - b->a_family;
514
515	if (d == 0) {
516		int len = min(a->a_prefixlen, b->a_prefixlen);
517		int bytes = len / 8;
518
519		d = memcmp(a->a_addr, b->a_addr, bytes);
520		if (d == 0) {
521			int mask = (1UL << (len % 8)) - 1UL;
522
523			d = (a->a_addr[bytes] & mask) -
524			    (b->a_addr[bytes] & mask);
525		}
526	}
527
528	return d;
529}
530
531/**
532 * Check if an address matches a certain family.
533 * @arg addr		Address represented as character string.
534 * @arg family		Desired address family.
535 *
536 * @return 1 if the address is of the desired address family,
537 *         otherwise 0 is returned.
538 */
539int nl_addr_valid(char *addr, int family)
540{
541	int ret;
542	char buf[32];
543
544	switch (family) {
545	case AF_INET:
546	case AF_INET6:
547		ret = inet_pton(family, addr, buf);
548		if (ret <= 0)
549			return 0;
550		break;
551
552	case AF_DECnet:
553		ret = dnet_pton(addr, buf);
554		if (ret <= 0)
555			return 0;
556		break;
557
558	case AF_LLC:
559		if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6)
560			return 0;
561		break;
562	}
563
564	return 1;
565}
566
567/**
568 * Guess address family of an abstract address object based on address size.
569 * @arg addr		Abstract address object.
570 * @return Address family or AF_UNSPEC if guessing wasn't successful.
571 */
572int nl_addr_guess_family(struct nl_addr *addr)
573{
574	switch (addr->a_len) {
575		case 4:
576			return AF_INET;
577		case 6:
578			return AF_LLC;
579		case 16:
580			return AF_INET6;
581		default:
582			return AF_UNSPEC;
583	}
584}
585
586/**
587 * Fill out sockaddr structure with values from abstract address object.
588 * @arg addr		Abstract address object.
589 * @arg sa		Destination sockaddr structure buffer.
590 * @arg salen		Length of sockaddr structure buffer.
591 *
592 * Fills out the specified sockaddr structure with the data found in the
593 * specified abstract address. The salen argument needs to be set to the
594 * size of sa but will be modified to the actual size used during before
595 * the function exits.
596 *
597 * @return 0 on success or a negative error code
598 */
599int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
600			  socklen_t *salen)
601{
602	switch (addr->a_family) {
603	case AF_INET: {
604		struct sockaddr_in *sai = (struct sockaddr_in *) sa;
605
606		if (*salen < sizeof(*sai))
607			return -EINVAL;
608
609		sai->sin_family = addr->a_family;
610		memcpy(&sai->sin_addr, addr->a_addr, 4);
611		*salen = sizeof(*sai);
612	}
613		break;
614
615	case AF_INET6: {
616		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
617
618		if (*salen < sizeof(*sa6))
619			return -EINVAL;
620
621		sa6->sin6_family = addr->a_family;
622		memcpy(&sa6->sin6_addr, addr->a_addr, 16);
623		*salen = sizeof(*sa6);
624	}
625		break;
626
627	default:
628		return -EINVAL;
629	}
630
631	return 0;
632}
633
634
635/** @} */
636
637/**
638 * @name Getting Information About Addresses
639 * @{
640 */
641
642/**
643 * Call getaddrinfo() for an abstract address object.
644 * @arg addr		Abstract address object.
645 *
646 * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST
647 * mode.
648 *
649 * @note The caller is responsible for freeing the linked list using the
650 *       interface provided by getaddrinfo(3).
651 *
652 * @return A linked list of addrinfo handles or  NULL with an error message
653 *         associated.
654 */
655struct addrinfo *nl_addr_info(struct nl_addr *addr)
656{
657	int err;
658	struct addrinfo *res;
659	char buf[INET6_ADDRSTRLEN+5];
660	struct addrinfo hint = {
661		.ai_flags = AI_NUMERICHOST,
662		.ai_family = addr->a_family,
663	};
664
665	nl_addr2str(addr, buf, sizeof(buf));
666
667	err = getaddrinfo(buf, NULL, &hint, &res);
668	if (err != 0) {
669		nl_error(err, gai_strerror(err));
670		return NULL;
671	}
672
673	return res;
674}
675
676/**
677 * Resolve abstract address object to a name using getnameinfo().
678 * @arg addr		Abstract address object.
679 * @arg host		Destination buffer for host name.
680 * @arg hostlen		Length of destination buffer.
681 *
682 * Resolves the abstract address to a name and writes the looked up result
683 * into the host buffer. getnameinfo() is used to perform the lookup and
684 * is put into NI_NAMEREQD mode so the function will fail if the lookup
685 * couldn't be performed.
686 *
687 * @return 0 on success or a negative error code.
688 */
689int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
690{
691	int err;
692	struct sockaddr_in6 buf;
693	socklen_t salen = sizeof(buf);
694
695	err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen);
696	if (err < 0)
697		return err;
698
699	return getnameinfo((struct sockaddr *) &buf, salen,
700			   host, hostlen, NULL, 0, NI_NAMEREQD);
701}
702
703/** @} */
704
705/**
706 * @name Attributes
707 * @{
708 */
709
710void nl_addr_set_family(struct nl_addr *addr, int family)
711{
712	addr->a_family = family;
713}
714
715int nl_addr_get_family(struct nl_addr *addr)
716{
717	return addr->a_family;
718}
719
720/**
721 * Set binary address of abstract address object.
722 * @arg addr		Abstract address object.
723 * @arg buf		Buffer containing binary address.
724 * @arg len		Length of buffer containing binary address.
725 */
726int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
727{
728	if (len > addr->a_maxsize)
729		return -ERANGE;
730
731	addr->a_len = len;
732	memcpy(addr->a_addr, buf, len);
733
734	return 0;
735}
736
737/**
738 * Get binary address of abstract address object.
739 * @arg addr		Abstract address object.
740 */
741void *nl_addr_get_binary_addr(struct nl_addr *addr)
742{
743	return addr->a_addr;
744}
745
746/**
747 * Get length of binary address of abstract address object.
748 * @arg addr		Abstract address object.
749 */
750unsigned int nl_addr_get_len(struct nl_addr *addr)
751{
752	return addr->a_len;
753}
754
755void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
756{
757	addr->a_prefixlen = prefixlen;
758}
759
760/**
761 * Get prefix length of abstract address object.
762 * @arg addr		Abstract address object.
763 */
764unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
765{
766	return addr->a_prefixlen;
767}
768
769/** @} */
770
771/**
772 * @name Translations to Strings
773 * @{
774 */
775
776/**
777 * Convert abstract address object to character string.
778 * @arg addr		Abstract address object.
779 * @arg buf		Destination buffer.
780 * @arg size		Size of destination buffer.
781 *
782 * Converts an abstract address to a character string and stores
783 * the result in the specified destination buffer.
784 *
785 * @return Address represented in ASCII stored in destination buffer.
786 */
787char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
788{
789	int i;
790	char tmp[16];
791
792	if (!addr->a_len) {
793		snprintf(buf, size, "none");
794		goto prefix;
795	}
796
797	switch (addr->a_family) {
798		case AF_INET:
799			inet_ntop(AF_INET, addr->a_addr, buf, size);
800			break;
801
802		case AF_INET6:
803			inet_ntop(AF_INET6, addr->a_addr, buf, size);
804			break;
805
806		case AF_DECnet:
807			dnet_ntop(addr->a_addr, addr->a_len, buf, size);
808			break;
809
810		case AF_LLC:
811		default:
812			snprintf(buf, size, "%02x",
813				 (unsigned char) addr->a_addr[0]);
814			for (i = 1; i < addr->a_len; i++) {
815				snprintf(tmp, sizeof(tmp), ":%02x",
816					 (unsigned char) addr->a_addr[i]);
817				strncat(buf, tmp, size - strlen(buf) - 1);
818			}
819			break;
820	}
821
822prefix:
823	if (addr->a_prefixlen != (8 * addr->a_len)) {
824		snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
825		strncat(buf, tmp, size - strlen(buf) - 1);
826	}
827
828	return buf;
829}
830
831/** @} */
832
833/**
834 * @name Address Family Transformations
835 * @{
836 */
837
838static struct trans_tbl afs[] = {
839	__ADD(AF_UNSPEC,unspec)
840	__ADD(AF_UNIX,unix)
841	__ADD(AF_LOCAL,local)
842	__ADD(AF_INET,inet)
843	__ADD(AF_AX25,ax25)
844	__ADD(AF_IPX,ipx)
845	__ADD(AF_APPLETALK,appletalk)
846	__ADD(AF_NETROM,netrom)
847	__ADD(AF_BRIDGE,bridge)
848	__ADD(AF_ATMPVC,atmpvc)
849	__ADD(AF_X25,x25)
850	__ADD(AF_INET6,inet6)
851	__ADD(AF_ROSE,rose)
852	__ADD(AF_DECnet,decnet)
853	__ADD(AF_NETBEUI,netbeui)
854	__ADD(AF_SECURITY,security)
855	__ADD(AF_KEY,key)
856	__ADD(AF_NETLINK,netlink)
857	__ADD(AF_ROUTE,route)
858	__ADD(AF_PACKET,packet)
859	__ADD(AF_ASH,ash)
860	__ADD(AF_ECONET,econet)
861	__ADD(AF_ATMSVC,atmsvc)
862	__ADD(AF_SNA,sna)
863	__ADD(AF_IRDA,irda)
864	__ADD(AF_PPPOX,pppox)
865	__ADD(AF_WANPIPE,wanpipe)
866	__ADD(AF_LLC,llc)
867	__ADD(AF_BLUETOOTH,bluetooth)
868};
869
870char *nl_af2str(int family, char *buf, size_t size)
871{
872	return __type2str(family, buf, size, afs, ARRAY_SIZE(afs));
873}
874
875int nl_str2af(const char *name)
876{
877	int fam = __str2type(name, afs, ARRAY_SIZE(afs));
878	return fam >= 0 ? fam : AF_UNSPEC;
879}
880
881/** @} */
882
883/** @} */
884