Home | History | Annotate | Download | only in lib
      1 /*
      2  * lib/addr.c		Abstract Address
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup core
     14  * @defgroup addr Abstract Address
     15  *
     16  * @par 1) Transform character string to abstract address
     17  * @code
     18  * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC);
     19  * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
     20  * nl_addr_put(a);
     21  * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC);
     22  * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
     23  * nl_addr_put(a);
     24  * @endcode
     25  * @{
     26  */
     27 
     28 #include <netlink-local.h>
     29 #include <netlink/netlink.h>
     30 #include <netlink/utils.h>
     31 #include <netlink/addr.h>
     32 #include <linux/socket.h>
     33 
     34 /* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
     35  * this, probably Alexey. */
     36 static inline uint16_t dn_ntohs(uint16_t addr)
     37 {
     38 	union {
     39 		uint8_t byte[2];
     40 		uint16_t word;
     41 	} u = {
     42 		.word = addr,
     43 	};
     44 
     45 	return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8);
     46 }
     47 
     48 static inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
     49 			   size_t *pos, size_t len, int *started)
     50 {
     51 	uint16_t tmp = *addr / scale;
     52 
     53 	if (*pos == len)
     54 		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 
     66 static 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 
    115 static 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 
    134 static 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 -NLE_INVAL;
    144 
    145 	pos = dnet_num(src + pos + 1, &node);
    146 	if ((pos == 0) || (node > 1023))
    147 		return -NLE_INVAL;
    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  */
    164 struct 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 		return NULL;
    171 
    172 	addr->a_refcnt = 1;
    173 	addr->a_maxsize = maxsize;
    174 
    175 	return addr;
    176 }
    177 
    178 /**
    179  * Allocate new abstract address object based on a binary address.
    180  * @arg family		Address family.
    181  * @arg buf		Buffer containing the binary address.
    182  * @arg size		Length of binary address buffer.
    183  * @return Newly allocated address handle or NULL
    184  */
    185 struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
    186 {
    187 	struct nl_addr *addr;
    188 
    189 	addr = nl_addr_alloc(size);
    190 	if (!addr)
    191 		return NULL;
    192 
    193 	addr->a_family = family;
    194 	addr->a_len = size;
    195 	addr->a_prefixlen = size*8;
    196 
    197 	if (size)
    198 		memcpy(addr->a_addr, buf, size);
    199 
    200 	return addr;
    201 }
    202 
    203 /**
    204  * Allocate abstract address based on netlink attribute.
    205  * @arg nla		Netlink attribute of unspecific type.
    206  * @arg family		Address family.
    207  *
    208  * Considers the netlink attribute payload a address of the specified
    209  * family and allocates a new abstract address based on it.
    210  *
    211  * @return Newly allocated address handle or NULL.
    212  */
    213 struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
    214 {
    215 	return nl_addr_build(family, nla_data(nla), nla_len(nla));
    216 }
    217 
    218 /**
    219  * Allocate abstract address object based on a character string
    220  * @arg addrstr		Address represented as character string.
    221  * @arg hint		Address family hint or AF_UNSPEC.
    222  * @arg result		Pointer to store resulting address.
    223  *
    224  * Regognizes the following address formats:
    225  *@code
    226  *  Format                      Len                Family
    227  *  ----------------------------------------------------------------
    228  *  IPv6 address format         16                 AF_INET6
    229  *  ddd.ddd.ddd.ddd             4                  AF_INET
    230  *  HH:HH:HH:HH:HH:HH           6                  AF_LLC
    231  *  AA{.|,}NNNN                 2                  AF_DECnet
    232  *  HH:HH:HH:...                variable           AF_UNSPEC
    233  * @endcode
    234  *
    235  *  Special values:
    236  *    - none: All bits and length set to 0.
    237  *    - {default|all|any}: All bits set to 0, length based on hint or
    238  *                         AF_INET if no hint is given.
    239  *
    240  * The prefix length may be appened at the end prefixed with a
    241  * slash, e.g. 10.0.0.0/8.
    242  *
    243  * @return 0 on success or a negative error code.
    244  */
    245 int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
    246 {
    247 	int err, copy = 0, len = 0, family = AF_UNSPEC;
    248 	char *str, *prefix, buf[32];
    249 	struct nl_addr *addr = NULL; /* gcc ain't that smart */
    250 
    251 	str = strdup(addrstr);
    252 	if (!str) {
    253 		err = -NLE_NOMEM;
    254 		goto errout;
    255 	}
    256 
    257 	prefix = strchr(str, '/');
    258 	if (prefix)
    259 		*prefix = '\0';
    260 
    261 	if (!strcasecmp(str, "none")) {
    262 		family = hint;
    263 		goto prefix;
    264 	}
    265 
    266 	if (!strcasecmp(str, "default") ||
    267 	    !strcasecmp(str, "all") ||
    268 	    !strcasecmp(str, "any")) {
    269 
    270 		switch (hint) {
    271 			case AF_INET:
    272 			case AF_UNSPEC:
    273 				/* Kind of a hack, we assume that if there is
    274 				 * no hint given the user wants to have a IPv4
    275 				 * address given back. */
    276 				family = AF_INET;
    277 				len = 4;
    278 				goto prefix;
    279 
    280 			case AF_INET6:
    281 				family = AF_INET6;
    282 				len = 16;
    283 				goto prefix;
    284 
    285 			case AF_LLC:
    286 				family = AF_LLC;
    287 				len = 6;
    288 				goto prefix;
    289 
    290 			default:
    291 				err = -NLE_AF_NOSUPPORT;
    292 				goto errout;
    293 		}
    294 	}
    295 
    296 	copy = 1;
    297 
    298 	if (hint == AF_INET || hint == AF_UNSPEC) {
    299 		if (inet_pton(AF_INET, str, buf) > 0) {
    300 			family = AF_INET;
    301 			len = 4;
    302 			goto prefix;
    303 		}
    304 		if (hint == AF_INET) {
    305 			err = -NLE_NOADDR;
    306 			goto errout;
    307 		}
    308 	}
    309 
    310 	if (hint == AF_INET6 || hint == AF_UNSPEC) {
    311 		if (inet_pton(AF_INET6, str, buf) > 0) {
    312 			family = AF_INET6;
    313 			len = 16;
    314 			goto prefix;
    315 		}
    316 		if (hint == AF_INET6) {
    317 			err = -NLE_NOADDR;
    318 			goto errout;
    319 		}
    320 	}
    321 
    322 	if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) {
    323 		unsigned int a, b, c, d, e, f;
    324 
    325 		if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
    326 		    &a, &b, &c, &d, &e, &f) == 6) {
    327 			family = AF_LLC;
    328 			len = 6;
    329 			buf[0] = (unsigned char) a;
    330 			buf[1] = (unsigned char) b;
    331 			buf[2] = (unsigned char) c;
    332 			buf[3] = (unsigned char) d;
    333 			buf[4] = (unsigned char) e;
    334 			buf[5] = (unsigned char) f;
    335 			goto prefix;
    336 		}
    337 
    338 		if (hint == AF_LLC) {
    339 			err = -NLE_NOADDR;
    340 			goto errout;
    341 		}
    342 	}
    343 
    344 	if ((hint == AF_DECnet || hint == AF_UNSPEC) &&
    345 	    (strchr(str, '.') || strchr(str, ','))) {
    346 		if (dnet_pton(str, buf) > 0) {
    347 			family = AF_DECnet;
    348 			len = 2;
    349 			goto prefix;
    350 		}
    351 		if (hint == AF_DECnet) {
    352 			err = -NLE_NOADDR;
    353 			goto errout;
    354 		}
    355 	}
    356 
    357 	if (hint == AF_UNSPEC && strchr(str, ':')) {
    358 		int i = 0;
    359 		char *s = str, *p;
    360 		for (;;) {
    361 			long l = strtol(s, &p, 16);
    362 
    363 			if (s == p || l > 0xff || i >= sizeof(buf)) {
    364 				err = -NLE_INVAL;
    365 				goto errout;
    366 			}
    367 
    368 			buf[i++] = (unsigned char) l;
    369 			if (*p == '\0')
    370 				break;
    371 			s = ++p;
    372 		}
    373 
    374 		len = i;
    375 		family = AF_UNSPEC;
    376 		goto prefix;
    377 	}
    378 
    379 	err = -NLE_NOADDR;
    380 	goto errout;
    381 
    382 prefix:
    383 	addr = nl_addr_alloc(len);
    384 	if (!addr) {
    385 		err = -NLE_NOMEM;
    386 		goto errout;
    387 	}
    388 
    389 	nl_addr_set_family(addr, family);
    390 
    391 	if (copy)
    392 		nl_addr_set_binary_addr(addr, buf, len);
    393 
    394 	if (prefix) {
    395 		char *p;
    396 		long pl = strtol(++prefix, &p, 0);
    397 		if (p == prefix) {
    398 			nl_addr_destroy(addr);
    399 			err = -NLE_INVAL;
    400 			goto errout;
    401 		}
    402 		nl_addr_set_prefixlen(addr, pl);
    403 	} else
    404 		nl_addr_set_prefixlen(addr, len * 8);
    405 
    406 	*result = addr;
    407 	err = 0;
    408 errout:
    409 	free(str);
    410 
    411 	return err;
    412 }
    413 
    414 /**
    415  * Clone existing abstract address object.
    416  * @arg addr		Abstract address object.
    417  * @return Newly allocated abstract address object being a duplicate of the
    418  *         specified address object or NULL if a failure occured.
    419  */
    420 struct nl_addr *nl_addr_clone(struct nl_addr *addr)
    421 {
    422 	struct nl_addr *new;
    423 
    424 	new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len);
    425 	if (new)
    426 		new->a_prefixlen = addr->a_prefixlen;
    427 
    428 	return new;
    429 }
    430 
    431 /** @} */
    432 
    433 /**
    434  * @name Destroying Abstract Addresses
    435  * @{
    436  */
    437 
    438 /**
    439  * Destroy abstract address object.
    440  * @arg addr		Abstract address object.
    441  */
    442 void nl_addr_destroy(struct nl_addr *addr)
    443 {
    444 	if (!addr)
    445 		return;
    446 
    447 	if (addr->a_refcnt != 1)
    448 		BUG();
    449 
    450 	free(addr);
    451 }
    452 
    453 /** @} */
    454 
    455 /**
    456  * @name Managing Usage References
    457  * @{
    458  */
    459 
    460 struct nl_addr *nl_addr_get(struct nl_addr *addr)
    461 {
    462 	addr->a_refcnt++;
    463 
    464 	return addr;
    465 }
    466 
    467 void nl_addr_put(struct nl_addr *addr)
    468 {
    469 	if (!addr)
    470 		return;
    471 
    472 	if (addr->a_refcnt == 1)
    473 		nl_addr_destroy(addr);
    474 	else
    475 		addr->a_refcnt--;
    476 }
    477 
    478 /**
    479  * Check whether an abstract address object is shared.
    480  * @arg addr		Abstract address object.
    481  * @return Non-zero if the abstract address object is shared, otherwise 0.
    482  */
    483 int nl_addr_shared(struct nl_addr *addr)
    484 {
    485 	return addr->a_refcnt > 1;
    486 }
    487 
    488 /** @} */
    489 
    490 /**
    491  * @name Miscellaneous
    492  * @{
    493  */
    494 
    495 /**
    496  * Compares two abstract address objects.
    497  * @arg a		A abstract address object.
    498  * @arg b		Another abstract address object.
    499  *
    500  * @return Integer less than, equal to or greather than zero if \c is found,
    501  *         respectively to be less than, to, or be greater than \c b.
    502  */
    503 int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
    504 {
    505 	int d = a->a_family - b->a_family;
    506 
    507 	if (d == 0) {
    508 		d = a->a_len - b->a_len;
    509 
    510 		if (a->a_len && d == 0)
    511 			return memcmp(a->a_addr, b->a_addr, a->a_len);
    512 	}
    513 
    514 	return d;
    515 }
    516 
    517 /**
    518  * Compares the prefix of two abstract address objects.
    519  * @arg a		A abstract address object.
    520  * @arg b		Another abstract address object.
    521  *
    522  * @return Integer less than, equal to or greather than zero if \c is found,
    523  *         respectively to be less than, to, or be greater than \c b.
    524  */
    525 int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
    526 {
    527 	int d = a->a_family - b->a_family;
    528 
    529 	if (d == 0) {
    530 		int len = min(a->a_prefixlen, b->a_prefixlen);
    531 		int bytes = len / 8;
    532 
    533 		d = memcmp(a->a_addr, b->a_addr, bytes);
    534 		if (d == 0) {
    535 			int mask = (1UL << (len % 8)) - 1UL;
    536 
    537 			d = (a->a_addr[bytes] & mask) -
    538 			    (b->a_addr[bytes] & mask);
    539 		}
    540 	}
    541 
    542 	return d;
    543 }
    544 
    545 /**
    546  * Returns true if the address consists of all zeros
    547  * @arg addr		Address to look at.
    548  */
    549 int nl_addr_iszero(struct nl_addr *addr)
    550 {
    551 	int i;
    552 
    553 	for (i = 0; i < addr->a_len; i++)
    554 		if (addr->a_addr[i])
    555 			return 0;
    556 
    557 	return 1;
    558 }
    559 
    560 /**
    561  * Check if an address matches a certain family.
    562  * @arg addr		Address represented as character string.
    563  * @arg family		Desired address family.
    564  *
    565  * @return 1 if the address is of the desired address family,
    566  *         otherwise 0 is returned.
    567  */
    568 int nl_addr_valid(char *addr, int family)
    569 {
    570 	int ret;
    571 	char buf[32];
    572 
    573 	switch (family) {
    574 	case AF_INET:
    575 	case AF_INET6:
    576 		ret = inet_pton(family, addr, buf);
    577 		if (ret <= 0)
    578 			return 0;
    579 		break;
    580 
    581 	case AF_DECnet:
    582 		ret = dnet_pton(addr, buf);
    583 		if (ret <= 0)
    584 			return 0;
    585 		break;
    586 
    587 	case AF_LLC:
    588 		if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6)
    589 			return 0;
    590 		break;
    591 	}
    592 
    593 	return 1;
    594 }
    595 
    596 /**
    597  * Guess address family of an abstract address object based on address size.
    598  * @arg addr		Abstract address object.
    599  * @return Address family or AF_UNSPEC if guessing wasn't successful.
    600  */
    601 int nl_addr_guess_family(struct nl_addr *addr)
    602 {
    603 	switch (addr->a_len) {
    604 		case 4:
    605 			return AF_INET;
    606 		case 6:
    607 			return AF_LLC;
    608 		case 16:
    609 			return AF_INET6;
    610 		default:
    611 			return AF_UNSPEC;
    612 	}
    613 }
    614 
    615 /**
    616  * Fill out sockaddr structure with values from abstract address object.
    617  * @arg addr		Abstract address object.
    618  * @arg sa		Destination sockaddr structure buffer.
    619  * @arg salen		Length of sockaddr structure buffer.
    620  *
    621  * Fills out the specified sockaddr structure with the data found in the
    622  * specified abstract address. The salen argument needs to be set to the
    623  * size of sa but will be modified to the actual size used during before
    624  * the function exits.
    625  *
    626  * @return 0 on success or a negative error code
    627  */
    628 int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
    629 			  socklen_t *salen)
    630 {
    631 	switch (addr->a_family) {
    632 	case AF_INET: {
    633 		struct sockaddr_in *sai = (struct sockaddr_in *) sa;
    634 
    635 		if (*salen < sizeof(*sai))
    636 			return -NLE_INVAL;
    637 
    638 		sai->sin_family = addr->a_family;
    639 		memcpy(&sai->sin_addr, addr->a_addr, 4);
    640 		*salen = sizeof(*sai);
    641 	}
    642 		break;
    643 
    644 	case AF_INET6: {
    645 		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
    646 
    647 		if (*salen < sizeof(*sa6))
    648 			return -NLE_INVAL;
    649 
    650 		sa6->sin6_family = addr->a_family;
    651 		memcpy(&sa6->sin6_addr, addr->a_addr, 16);
    652 		*salen = sizeof(*sa6);
    653 	}
    654 		break;
    655 
    656 	default:
    657 		return -NLE_INVAL;
    658 	}
    659 
    660 	return 0;
    661 }
    662 
    663 
    664 /** @} */
    665 
    666 /**
    667  * @name Getting Information About Addresses
    668  * @{
    669  */
    670 
    671 /**
    672  * Call getaddrinfo() for an abstract address object.
    673  * @arg addr		Abstract address object.
    674  * @arg result		Pointer to store resulting address list.
    675  *
    676  * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST
    677  * mode.
    678  *
    679  * @note The caller is responsible for freeing the linked list using the
    680  *       interface provided by getaddrinfo(3).
    681  *
    682  * @return 0 on success or a negative error code.
    683  */
    684 int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
    685 {
    686 	int err;
    687 	char buf[INET6_ADDRSTRLEN+5];
    688 	struct addrinfo hint = {
    689 		.ai_flags = AI_NUMERICHOST,
    690 		.ai_family = addr->a_family,
    691 	};
    692 
    693 	nl_addr2str(addr, buf, sizeof(buf));
    694 
    695 	err = getaddrinfo(buf, NULL, &hint, result);
    696 	if (err != 0) {
    697 		switch (err) {
    698 		case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT;
    699 		case EAI_AGAIN: return -NLE_AGAIN;
    700 		case EAI_BADFLAGS: return -NLE_INVAL;
    701 		case EAI_FAIL: return -NLE_NOADDR;
    702 		case EAI_FAMILY: return -NLE_AF_NOSUPPORT;
    703 		case EAI_MEMORY: return -NLE_NOMEM;
    704 		case EAI_NODATA: return -NLE_NOADDR;
    705 		case EAI_NONAME: return -NLE_OBJ_NOTFOUND;
    706 		case EAI_SERVICE: return -NLE_OPNOTSUPP;
    707 		case EAI_SOCKTYPE: return -NLE_BAD_SOCK;
    708 		default: return -NLE_FAILURE;
    709 		}
    710 	}
    711 
    712 	return 0;
    713 }
    714 
    715 /**
    716  * Resolve abstract address object to a name using getnameinfo().
    717  * @arg addr		Abstract address object.
    718  * @arg host		Destination buffer for host name.
    719  * @arg hostlen		Length of destination buffer.
    720  *
    721  * Resolves the abstract address to a name and writes the looked up result
    722  * into the host buffer. getnameinfo() is used to perform the lookup and
    723  * is put into NI_NAMEREQD mode so the function will fail if the lookup
    724  * couldn't be performed.
    725  *
    726  * @return 0 on success or a negative error code.
    727  */
    728 int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
    729 {
    730 	int err;
    731 	struct sockaddr_in6 buf;
    732 	socklen_t salen = sizeof(buf);
    733 
    734 	err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen);
    735 	if (err < 0)
    736 		return err;
    737 
    738 	err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen,
    739 			  NULL, 0, NI_NAMEREQD);
    740 	if (err < 0)
    741 		return nl_syserr2nlerr(err);
    742 
    743 	return 0;
    744 }
    745 
    746 /** @} */
    747 
    748 /**
    749  * @name Attributes
    750  * @{
    751  */
    752 
    753 void nl_addr_set_family(struct nl_addr *addr, int family)
    754 {
    755 	addr->a_family = family;
    756 }
    757 
    758 int nl_addr_get_family(struct nl_addr *addr)
    759 {
    760 	return addr->a_family;
    761 }
    762 
    763 /**
    764  * Set binary address of abstract address object.
    765  * @arg addr		Abstract address object.
    766  * @arg buf		Buffer containing binary address.
    767  * @arg len		Length of buffer containing binary address.
    768  */
    769 int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
    770 {
    771 	if (len > addr->a_maxsize)
    772 		return -NLE_RANGE;
    773 
    774 	addr->a_len = len;
    775 	memcpy(addr->a_addr, buf, len);
    776 
    777 	return 0;
    778 }
    779 
    780 /**
    781  * Get binary address of abstract address object.
    782  * @arg addr		Abstract address object.
    783  */
    784 void *nl_addr_get_binary_addr(struct nl_addr *addr)
    785 {
    786 	return addr->a_addr;
    787 }
    788 
    789 /**
    790  * Get length of binary address of abstract address object.
    791  * @arg addr		Abstract address object.
    792  */
    793 unsigned int nl_addr_get_len(struct nl_addr *addr)
    794 {
    795 	return addr->a_len;
    796 }
    797 
    798 void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
    799 {
    800 	addr->a_prefixlen = prefixlen;
    801 }
    802 
    803 /**
    804  * Get prefix length of abstract address object.
    805  * @arg addr		Abstract address object.
    806  */
    807 unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
    808 {
    809 	return addr->a_prefixlen;
    810 }
    811 
    812 /** @} */
    813 
    814 /**
    815  * @name Translations to Strings
    816  * @{
    817  */
    818 
    819 /**
    820  * Convert abstract address object to character string.
    821  * @arg addr		Abstract address object.
    822  * @arg buf		Destination buffer.
    823  * @arg size		Size of destination buffer.
    824  *
    825  * Converts an abstract address to a character string and stores
    826  * the result in the specified destination buffer.
    827  *
    828  * @return Address represented in ASCII stored in destination buffer.
    829  */
    830 char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
    831 {
    832 	int i;
    833 	char tmp[16];
    834 
    835 	if (!addr || !addr->a_len) {
    836 		snprintf(buf, size, "none");
    837 		if (addr)
    838 			goto prefix;
    839 		else
    840 			return buf;
    841 	}
    842 
    843 	switch (addr->a_family) {
    844 		case AF_INET:
    845 			inet_ntop(AF_INET, addr->a_addr, buf, size);
    846 			break;
    847 
    848 		case AF_INET6:
    849 			inet_ntop(AF_INET6, addr->a_addr, buf, size);
    850 			break;
    851 
    852 		case AF_DECnet:
    853 			dnet_ntop(addr->a_addr, addr->a_len, buf, size);
    854 			break;
    855 
    856 		case AF_LLC:
    857 		default:
    858 			snprintf(buf, size, "%02x",
    859 				 (unsigned char) addr->a_addr[0]);
    860 			for (i = 1; i < addr->a_len; i++) {
    861 				snprintf(tmp, sizeof(tmp), ":%02x",
    862 					 (unsigned char) addr->a_addr[i]);
    863 				strncat(buf, tmp, size - strlen(buf) - 1);
    864 			}
    865 			break;
    866 	}
    867 
    868 prefix:
    869 	if (addr->a_prefixlen != (8 * addr->a_len)) {
    870 		snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
    871 		strncat(buf, tmp, size - strlen(buf) - 1);
    872 	}
    873 
    874 	return buf;
    875 }
    876 
    877 /** @} */
    878 
    879 /**
    880  * @name Address Family Transformations
    881  * @{
    882  */
    883 
    884 static struct trans_tbl afs[] = {
    885 	__ADD(AF_UNSPEC,unspec)
    886 	__ADD(AF_UNIX,unix)
    887 	__ADD(AF_LOCAL,local)
    888 	__ADD(AF_INET,inet)
    889 	__ADD(AF_AX25,ax25)
    890 	__ADD(AF_IPX,ipx)
    891 	__ADD(AF_APPLETALK,appletalk)
    892 	__ADD(AF_NETROM,netrom)
    893 	__ADD(AF_BRIDGE,bridge)
    894 	__ADD(AF_ATMPVC,atmpvc)
    895 	__ADD(AF_X25,x25)
    896 	__ADD(AF_INET6,inet6)
    897 	__ADD(AF_ROSE,rose)
    898 	__ADD(AF_DECnet,decnet)
    899 	__ADD(AF_NETBEUI,netbeui)
    900 	__ADD(AF_SECURITY,security)
    901 	__ADD(AF_KEY,key)
    902 	__ADD(AF_NETLINK,netlink)
    903 	__ADD(AF_ROUTE,route)
    904 	__ADD(AF_PACKET,packet)
    905 	__ADD(AF_ASH,ash)
    906 	__ADD(AF_ECONET,econet)
    907 	__ADD(AF_ATMSVC,atmsvc)
    908 	__ADD(AF_SNA,sna)
    909 	__ADD(AF_IRDA,irda)
    910 	__ADD(AF_PPPOX,pppox)
    911 	__ADD(AF_WANPIPE,wanpipe)
    912 	__ADD(AF_LLC,llc)
    913 	__ADD(AF_BLUETOOTH,bluetooth)
    914 };
    915 
    916 char *nl_af2str(int family, char *buf, size_t size)
    917 {
    918 	return __type2str(family, buf, size, afs, ARRAY_SIZE(afs));
    919 }
    920 
    921 int nl_str2af(const char *name)
    922 {
    923 	int fam = __str2type(name, afs, ARRAY_SIZE(afs));
    924 	return fam >= 0 ? fam : AF_UNSPEC;
    925 }
    926 
    927 /** @} */
    928 
    929 /** @} */
    930