addr.c revision 5ab9421111f6473af871f4678d5b93b21f50028d
144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/addr.c		Abstract Address
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup utils
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup addr Abstract Address
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 1) Transform character string to abstract address
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC);
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * nl_addr_put(a);
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC);
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * nl_addr_put(a);
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/addr.h>
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/socket.h>
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf/* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf * this, probably Alexey. */
3644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline uint16_t dn_ntohs(uint16_t addr)
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf	union {
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf		uint8_t byte[2];
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf		uint16_t word;
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf	} u = {
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf		.word = addr,
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8);
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf
4844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf			   size_t *pos, size_t len, int *started)
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint16_t tmp = *addr / scale;
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*pos == len)
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 1;
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (((tmp) > 0) || *started || (scale == 1)) {
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf		*str = tmp + '0';
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf		*started = 1;
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf		(*pos)++;
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf		*addr -= (tmp * scale);
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf
6644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str,
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     size_t len)
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf);
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint16_t area = addr >> 10;
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf	size_t pos = 0;
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int started = 0;
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (addrlen != 2)
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr &= 0x03ff;
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (len == 0)
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (do_digit(str + pos, &area, 10, &pos, len, &started))
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (do_digit(str + pos, &area, 1, &pos, len, &started))
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (pos == len)
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf	*(str + pos) = '.';
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf	pos++;
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf	started = 0;
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (do_digit(str + pos, &addr, 100, &pos, len, &started))
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (do_digit(str + pos, &addr, 10, &pos, len, &started))
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (do_digit(str + pos, &addr, 1, &pos, len, &started))
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (pos == len)
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return str;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf	*(str + pos) = 0;
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return str;
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf
11544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int dnet_num(const char *src, uint16_t * dst)
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int rv = 0;
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int tmp;
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf	*dst = 0;
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf	while ((tmp = *src++) != 0) {
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf		tmp -= '0';
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if ((tmp < 0) || (tmp > 9))
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf			return rv;
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf		rv++;
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf		(*dst) *= 10;
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf		(*dst) += tmp;
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rv;
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf
13444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int dnet_pton(const char *src, char *addrbuf)
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint16_t area = 0;
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint16_t node = 0;
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int pos;
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf	pos = dnet_num(src, &area);
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if ((pos == 0) || (area > 63) ||
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf	    ((*(src + pos) != '.') && (*(src + pos) != ',')))
1438a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_INVAL;
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf	pos = dnet_num(src + pos + 1, &node);
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if ((pos == 0) || (node > 1023))
1478a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_INVAL;
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf	*(uint16_t *)addrbuf = dn_ntohs((area << 10) | node);
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 1;
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Creating Abstract Addresses
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocate new abstract address object.
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg maxsize		Maximum size of the binary address.
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Newly allocated address object or NULL
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
16444d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *nl_addr_alloc(size_t maxsize)
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_addr *addr;
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr = calloc(1, sizeof(*addr) + maxsize);
1698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if (!addr)
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_refcnt = 1;
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_maxsize = maxsize;
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr;
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocate new abstract address object based on a binary address.
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg family		Address family.
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		Buffer containing the binary address.
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg size		Length of binary address buffer.
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Newly allocated address handle or NULL
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
18544d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *nl_addr_build(int family, void *buf, size_t size)
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_addr *addr;
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr = nl_addr_alloc(size);
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!addr)
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_family = family;
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_len = size;
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_prefixlen = size*8;
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (size)
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf		memcpy(addr->a_addr, buf, size);
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr;
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
2040fa6756cca2444ddf665cc140585822d6c04507aThomas Graf * Allocate abstract address based on netlink attribute.
2050fa6756cca2444ddf665cc140585822d6c04507aThomas Graf * @arg nla		Netlink attribute of unspecific type.
2060fa6756cca2444ddf665cc140585822d6c04507aThomas Graf * @arg family		Address family.
2070fa6756cca2444ddf665cc140585822d6c04507aThomas Graf *
2080fa6756cca2444ddf665cc140585822d6c04507aThomas Graf * Considers the netlink attribute payload a address of the specified
2090fa6756cca2444ddf665cc140585822d6c04507aThomas Graf * family and allocates a new abstract address based on it.
2100fa6756cca2444ddf665cc140585822d6c04507aThomas Graf *
2110fa6756cca2444ddf665cc140585822d6c04507aThomas Graf * @return Newly allocated address handle or NULL.
2120fa6756cca2444ddf665cc140585822d6c04507aThomas Graf */
213eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Grafstruct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
2140fa6756cca2444ddf665cc140585822d6c04507aThomas Graf{
2150fa6756cca2444ddf665cc140585822d6c04507aThomas Graf	return nl_addr_build(family, nla_data(nla), nla_len(nla));
2160fa6756cca2444ddf665cc140585822d6c04507aThomas Graf}
2170fa6756cca2444ddf665cc140585822d6c04507aThomas Graf
2180fa6756cca2444ddf665cc140585822d6c04507aThomas Graf/**
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocate abstract address object based on a character string
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addrstr		Address represented as character string.
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg hint		Address family hint or AF_UNSPEC.
2228a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting address.
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Regognizes the following address formats:
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf *@code
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf *  Format                      Len                Family
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf *  ----------------------------------------------------------------
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf *  IPv6 address format         16                 AF_INET6
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf *  ddd.ddd.ddd.ddd             4                  AF_INET
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf *  HH:HH:HH:HH:HH:HH           6                  AF_LLC
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf *  AA{.|,}NNNN                 2                  AF_DECnet
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf *  HH:HH:HH:...                variable           AF_UNSPEC
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf *  Special values:
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - none: All bits and length set to 0.
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - {default|all|any}: All bits set to 0, length based on hint or
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf *                         AF_INET if no hint is given.
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf * The prefix length may be appened at the end prefixed with a
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf * slash, e.g. 10.0.0.0/8.
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
2438a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
2458a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err, copy = 0, len = 0, family = AF_UNSPEC;
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *str, *prefix, buf[32];
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_addr *addr = NULL; /* gcc ain't that smart */
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf	str = strdup(addrstr);
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!str) {
2538a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_NOMEM;
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf	prefix = strchr(str, '/');
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (prefix)
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf		*prefix = '\0';
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!strcasecmp(str, "none")) {
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf		family = hint;
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto prefix;
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!strcasecmp(str, "default") ||
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf	    !strcasecmp(str, "all") ||
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf	    !strcasecmp(str, "any")) {
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf		switch (hint) {
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf			case AF_INET:
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf			case AF_UNSPEC:
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf				/* Kind of a hack, we assume that if there is
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf				 * no hint given the user wants to have a IPv4
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf				 * address given back. */
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf				family = AF_INET;
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf				len = 4;
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto prefix;
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf			case AF_INET6:
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf				family = AF_INET6;
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf				len = 16;
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto prefix;
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf			case AF_LLC:
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf				family = AF_LLC;
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf				len = 6;
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto prefix;
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf			default:
2918a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				err = -NLE_AF_NOSUPPORT;
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto errout;
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf	copy = 1;
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (hint == AF_INET || hint == AF_UNSPEC) {
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (inet_pton(AF_INET, str, buf) > 0) {
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf			family = AF_INET;
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf			len = 4;
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto prefix;
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hint == AF_INET) {
3058a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_NOADDR;
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (hint == AF_INET6 || hint == AF_UNSPEC) {
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (inet_pton(AF_INET6, str, buf) > 0) {
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf			family = AF_INET6;
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf			len = 16;
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto prefix;
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hint == AF_INET6) {
3178a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_NOADDR;
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) {
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf		unsigned int a, b, c, d, e, f;
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf		    &a, &b, &c, &d, &e, &f) == 6) {
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf			family = AF_LLC;
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf			len = 6;
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[0] = (unsigned char) a;
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[1] = (unsigned char) b;
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[2] = (unsigned char) c;
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[3] = (unsigned char) d;
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[4] = (unsigned char) e;
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[5] = (unsigned char) f;
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto prefix;
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hint == AF_LLC) {
3398a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_NOADDR;
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if ((hint == AF_DECnet || hint == AF_UNSPEC) &&
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf	    (strchr(str, '.') || strchr(str, ','))) {
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (dnet_pton(str, buf) > 0) {
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf			family = AF_DECnet;
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf			len = 2;
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto prefix;
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hint == AF_DECnet) {
3528a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_NOADDR;
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (hint == AF_UNSPEC && strchr(str, ':')) {
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf		int i = 0;
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf		char *s = str, *p;
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (;;) {
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf			long l = strtol(s, &p, 16);
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (s == p || l > 0xff || i >= sizeof(buf)) {
3648a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				err = -NLE_INVAL;
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto errout;
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf			buf[i++] = (unsigned char) l;
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (*p == '\0')
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf				break;
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf			s = ++p;
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf		len = i;
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf		family = AF_UNSPEC;
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto prefix;
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf
3798a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	err = -NLE_NOADDR;
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf	goto errout;
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf
38244d362409d5469aed47d19e7908d19bd194493aThomas Grafprefix:
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr = nl_addr_alloc(len);
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!addr) {
3858a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_NOMEM;
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_set_family(addr, family);
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (copy)
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_set_binary_addr(addr, buf, len);
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (prefix) {
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf		char *p;
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf		long pl = strtol(++prefix, &p, 0);
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (p == prefix) {
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_addr_destroy(addr);
3998a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_INVAL;
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_set_prefixlen(addr, pl);
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_set_prefixlen(addr, len * 8);
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf
4068a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = addr;
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = 0;
40844d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(str);
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf
4118a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return err;
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Clone existing abstract address object.
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Newly allocated abstract address object being a duplicate of the
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf *         specified address object or NULL if a failure occured.
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
42044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *nl_addr_clone(struct nl_addr *addr)
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_addr *new;
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf	new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len);
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (new)
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf		new->a_prefixlen = addr->a_prefixlen;
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return new;
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Destroying Abstract Addresses
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Destroy abstract address object.
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
44244d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_addr_destroy(struct nl_addr *addr)
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!addr)
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (addr->a_refcnt != 1)
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf		BUG();
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(addr);
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Managing Usage References
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf
46044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *nl_addr_get(struct nl_addr *addr)
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_refcnt++;
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr;
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf
46744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_addr_put(struct nl_addr *addr)
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!addr)
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (addr->a_refcnt == 1)
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_destroy(addr);
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf		addr->a_refcnt--;
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Check whether an abstract address object is shared.
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Non-zero if the abstract address object is shared, otherwise 0.
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
48344d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_shared(struct nl_addr *addr)
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr->a_refcnt > 1;
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Miscellaneous
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Compares two abstract address objects.
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg a		A abstract address object.
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg b		Another abstract address object.
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Integer less than, equal to or greather than zero if \c is found,
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf *         respectively to be less than, to, or be greater than \c b.
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
50344d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf	int d = a->a_family - b->a_family;
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (d == 0) {
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf		d = a->a_len - b->a_len;
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (a->a_len && d == 0)
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf			return memcmp(a->a_addr, b->a_addr, a->a_len);
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return d;
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
51844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Compares the prefix of two abstract address objects.
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg a		A abstract address object.
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg b		Another abstract address object.
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Integer less than, equal to or greather than zero if \c is found,
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf *         respectively to be less than, to, or be greater than \c b.
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
52544d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int d = a->a_family - b->a_family;
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (d == 0) {
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf		int len = min(a->a_prefixlen, b->a_prefixlen);
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf		int bytes = len / 8;
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf		d = memcmp(a->a_addr, b->a_addr, bytes);
53444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (d == 0) {
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf			int mask = (1UL << (len % 8)) - 1UL;
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf			d = (a->a_addr[bytes] & mask) -
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf			    (b->a_addr[bytes] & mask);
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return d;
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
5463ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * Returns true if the address consists of all zeros
5473ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @arg addr		Address to look at.
5483ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf */
5493ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafint nl_addr_iszero(struct nl_addr *addr)
5503ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
5513ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	int i;
5523ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
5533ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	for (i = 0; i < addr->a_len; i++)
5543ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		if (addr->a_addr[i])
5553ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf			return 0;
5563ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
5573ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return 1;
5583ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
5593ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
5603ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/**
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Check if an address matches a certain family.
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Address represented as character string.
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg family		Desired address family.
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 1 if the address is of the desired address family,
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf *         otherwise 0 is returned.
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
56844d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_valid(char *addr, int family)
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf	int ret;
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[32];
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf	switch (family) {
57444d362409d5469aed47d19e7908d19bd194493aThomas Graf	case AF_INET:
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf	case AF_INET6:
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf		ret = inet_pton(family, addr, buf);
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (ret <= 0)
57844d362409d5469aed47d19e7908d19bd194493aThomas Graf			return 0;
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf		break;
58044d362409d5469aed47d19e7908d19bd194493aThomas Graf
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf	case AF_DECnet:
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf		ret = dnet_pton(addr, buf);
58344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (ret <= 0)
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf			return 0;
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf		break;
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf
58744d362409d5469aed47d19e7908d19bd194493aThomas Graf	case AF_LLC:
58844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6)
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf			return 0;
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf		break;
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 1;
59444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Guess address family of an abstract address object based on address size.
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Address family or AF_UNSPEC if guessing wasn't successful.
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
60144d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_guess_family(struct nl_addr *addr)
60244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf	switch (addr->a_len) {
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf		case 4:
60544d362409d5469aed47d19e7908d19bd194493aThomas Graf			return AF_INET;
60644d362409d5469aed47d19e7908d19bd194493aThomas Graf		case 6:
60744d362409d5469aed47d19e7908d19bd194493aThomas Graf			return AF_LLC;
60844d362409d5469aed47d19e7908d19bd194493aThomas Graf		case 16:
60944d362409d5469aed47d19e7908d19bd194493aThomas Graf			return AF_INET6;
61044d362409d5469aed47d19e7908d19bd194493aThomas Graf		default:
61144d362409d5469aed47d19e7908d19bd194493aThomas Graf			return AF_UNSPEC;
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
61444d362409d5469aed47d19e7908d19bd194493aThomas Graf
61544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
61644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Fill out sockaddr structure with values from abstract address object.
61744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg sa		Destination sockaddr structure buffer.
61944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg salen		Length of sockaddr structure buffer.
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Fills out the specified sockaddr structure with the data found in the
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf * specified abstract address. The salen argument needs to be set to the
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf * size of sa but will be modified to the actual size used during before
62444d362409d5469aed47d19e7908d19bd194493aThomas Graf * the function exits.
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
62844d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf			  socklen_t *salen)
63044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
63144d362409d5469aed47d19e7908d19bd194493aThomas Graf	switch (addr->a_family) {
63244d362409d5469aed47d19e7908d19bd194493aThomas Graf	case AF_INET: {
63344d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct sockaddr_in *sai = (struct sockaddr_in *) sa;
63444d362409d5469aed47d19e7908d19bd194493aThomas Graf
63544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (*salen < sizeof(*sai))
6368a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_INVAL;
63744d362409d5469aed47d19e7908d19bd194493aThomas Graf
63844d362409d5469aed47d19e7908d19bd194493aThomas Graf		sai->sin_family = addr->a_family;
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf		memcpy(&sai->sin_addr, addr->a_addr, 4);
64044d362409d5469aed47d19e7908d19bd194493aThomas Graf		*salen = sizeof(*sai);
64144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf		break;
64344d362409d5469aed47d19e7908d19bd194493aThomas Graf
64444d362409d5469aed47d19e7908d19bd194493aThomas Graf	case AF_INET6: {
64544d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
64644d362409d5469aed47d19e7908d19bd194493aThomas Graf
64744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (*salen < sizeof(*sa6))
6488a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_INVAL;
64944d362409d5469aed47d19e7908d19bd194493aThomas Graf
65044d362409d5469aed47d19e7908d19bd194493aThomas Graf		sa6->sin6_family = addr->a_family;
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf		memcpy(&sa6->sin6_addr, addr->a_addr, 16);
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf		*salen = sizeof(*sa6);
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf		break;
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf
65644d362409d5469aed47d19e7908d19bd194493aThomas Graf	default:
6578a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_INVAL;
65844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf
66044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
66144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf
66344d362409d5469aed47d19e7908d19bd194493aThomas Graf
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
66544d362409d5469aed47d19e7908d19bd194493aThomas Graf
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Getting Information About Addresses
66844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
66944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf
67144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Call getaddrinfo() for an abstract address object.
67344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
6748a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting address list.
67544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
67644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST
67744d362409d5469aed47d19e7908d19bd194493aThomas Graf * mode.
67844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
67944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @note The caller is responsible for freeing the linked list using the
68044d362409d5469aed47d19e7908d19bd194493aThomas Graf *       interface provided by getaddrinfo(3).
68144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6828a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
6848a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
68544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
68744d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[INET6_ADDRSTRLEN+5];
68844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct addrinfo hint = {
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ai_flags = AI_NUMERICHOST,
69044d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ai_family = addr->a_family,
69144d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
69244d362409d5469aed47d19e7908d19bd194493aThomas Graf
69344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr2str(addr, buf, sizeof(buf));
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf
6958a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	err = getaddrinfo(buf, NULL, &hint, result);
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err != 0) {
6978a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		switch (err) {
6988a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT;
6998a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_AGAIN: return -NLE_AGAIN;
7008a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_BADFLAGS: return -NLE_INVAL;
7018a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_FAIL: return -NLE_NOADDR;
7028a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_FAMILY: return -NLE_AF_NOSUPPORT;
7038a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_MEMORY: return -NLE_NOMEM;
7048a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_NODATA: return -NLE_NOADDR;
7058a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_NONAME: return -NLE_OBJ_NOTFOUND;
7068a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_SERVICE: return -NLE_OPNOTSUPP;
7078a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		case EAI_SOCKTYPE: return -NLE_BAD_SOCK;
7088a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		default: return -NLE_FAILURE;
7098a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		}
71044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
71144d362409d5469aed47d19e7908d19bd194493aThomas Graf
7128a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
71344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
71444d362409d5469aed47d19e7908d19bd194493aThomas Graf
71544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
71644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Resolve abstract address object to a name using getnameinfo().
71744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg host		Destination buffer for host name.
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg hostlen		Length of destination buffer.
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
72144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Resolves the abstract address to a name and writes the looked up result
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf * into the host buffer. getnameinfo() is used to perform the lookup and
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf * is put into NI_NAMEREQD mode so the function will fail if the lookup
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf * couldn't be performed.
72544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
72644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
72744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
72844d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73044d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct sockaddr_in6 buf;
73244d362409d5469aed47d19e7908d19bd194493aThomas Graf	socklen_t salen = sizeof(buf);
73344d362409d5469aed47d19e7908d19bd194493aThomas Graf
73444d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen);
73544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
73744d362409d5469aed47d19e7908d19bd194493aThomas Graf
738304746f8d06a14bc911a2b58cf1c2398b02ead0aThomas Graf	err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen,
739304746f8d06a14bc911a2b58cf1c2398b02ead0aThomas Graf			  NULL, 0, NI_NAMEREQD);
740304746f8d06a14bc911a2b58cf1c2398b02ead0aThomas Graf	if (err < 0)
741304746f8d06a14bc911a2b58cf1c2398b02ead0aThomas Graf		return nl_syserr2nlerr(err);
742304746f8d06a14bc911a2b58cf1c2398b02ead0aThomas Graf
743304746f8d06a14bc911a2b58cf1c2398b02ead0aThomas Graf	return 0;
74444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf
74644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf
74844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
74944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
75144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf
75344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_addr_set_family(struct nl_addr *addr, int family)
75444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
75544d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_family = family;
75644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75744d362409d5469aed47d19e7908d19bd194493aThomas Graf
75844d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_get_family(struct nl_addr *addr)
75944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
76044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr->a_family;
76144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
76244d362409d5469aed47d19e7908d19bd194493aThomas Graf
76344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
76444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set binary address of abstract address object.
76544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
76644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		Buffer containing binary address.
76744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg len		Length of buffer containing binary address.
76844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
76944d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
77044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
77144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (len > addr->a_maxsize)
7728a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
77344d362409d5469aed47d19e7908d19bd194493aThomas Graf
77444d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_len = len;
77544d362409d5469aed47d19e7908d19bd194493aThomas Graf	memcpy(addr->a_addr, buf, len);
77644d362409d5469aed47d19e7908d19bd194493aThomas Graf
77744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
77844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
77944d362409d5469aed47d19e7908d19bd194493aThomas Graf
78044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
78144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get binary address of abstract address object.
78244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
78344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
78444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid *nl_addr_get_binary_addr(struct nl_addr *addr)
78544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
78644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr->a_addr;
78744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
78844d362409d5469aed47d19e7908d19bd194493aThomas Graf
78944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
79044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get length of binary address of abstract address object.
79144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
79244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
79344d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int nl_addr_get_len(struct nl_addr *addr)
79444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
79544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr->a_len;
79644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
79744d362409d5469aed47d19e7908d19bd194493aThomas Graf
79844d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
79944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
80044d362409d5469aed47d19e7908d19bd194493aThomas Graf	addr->a_prefixlen = prefixlen;
80144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
80244d362409d5469aed47d19e7908d19bd194493aThomas Graf
80344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
80444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get prefix length of abstract address object.
80544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
80644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
80744d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
80844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
80944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return addr->a_prefixlen;
81044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
81144d362409d5469aed47d19e7908d19bd194493aThomas Graf
81244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
81344d362409d5469aed47d19e7908d19bd194493aThomas Graf
81444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
81544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Translations to Strings
81644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
81744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
81844d362409d5469aed47d19e7908d19bd194493aThomas Graf
81944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
82044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Convert abstract address object to character string.
82144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg addr		Abstract address object.
82244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		Destination buffer.
82344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg size		Size of destination buffer.
82444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
82544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Converts an abstract address to a character string and stores
82644d362409d5469aed47d19e7908d19bd194493aThomas Graf * the result in the specified destination buffer.
82744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
82844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Address represented in ASCII stored in destination buffer.
82944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
83044d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
83144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
83244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
83344d362409d5469aed47d19e7908d19bd194493aThomas Graf	char tmp[16];
83444d362409d5469aed47d19e7908d19bd194493aThomas Graf
8355ab9421111f6473af871f4678d5b93b21f50028dThomas Graf	if (!addr || !addr->a_len) {
83644d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(buf, size, "none");
8375ab9421111f6473af871f4678d5b93b21f50028dThomas Graf		if (addr)
8385ab9421111f6473af871f4678d5b93b21f50028dThomas Graf			goto prefix;
8395ab9421111f6473af871f4678d5b93b21f50028dThomas Graf		else
8405ab9421111f6473af871f4678d5b93b21f50028dThomas Graf			return buf;
84144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
84244d362409d5469aed47d19e7908d19bd194493aThomas Graf
84344d362409d5469aed47d19e7908d19bd194493aThomas Graf	switch (addr->a_family) {
84444d362409d5469aed47d19e7908d19bd194493aThomas Graf		case AF_INET:
84544d362409d5469aed47d19e7908d19bd194493aThomas Graf			inet_ntop(AF_INET, addr->a_addr, buf, size);
84644d362409d5469aed47d19e7908d19bd194493aThomas Graf			break;
84744d362409d5469aed47d19e7908d19bd194493aThomas Graf
84844d362409d5469aed47d19e7908d19bd194493aThomas Graf		case AF_INET6:
84944d362409d5469aed47d19e7908d19bd194493aThomas Graf			inet_ntop(AF_INET6, addr->a_addr, buf, size);
85044d362409d5469aed47d19e7908d19bd194493aThomas Graf			break;
85144d362409d5469aed47d19e7908d19bd194493aThomas Graf
85244d362409d5469aed47d19e7908d19bd194493aThomas Graf		case AF_DECnet:
85344d362409d5469aed47d19e7908d19bd194493aThomas Graf			dnet_ntop(addr->a_addr, addr->a_len, buf, size);
85444d362409d5469aed47d19e7908d19bd194493aThomas Graf			break;
85544d362409d5469aed47d19e7908d19bd194493aThomas Graf
85644d362409d5469aed47d19e7908d19bd194493aThomas Graf		case AF_LLC:
85744d362409d5469aed47d19e7908d19bd194493aThomas Graf		default:
85844d362409d5469aed47d19e7908d19bd194493aThomas Graf			snprintf(buf, size, "%02x",
85944d362409d5469aed47d19e7908d19bd194493aThomas Graf				 (unsigned char) addr->a_addr[0]);
86044d362409d5469aed47d19e7908d19bd194493aThomas Graf			for (i = 1; i < addr->a_len; i++) {
86144d362409d5469aed47d19e7908d19bd194493aThomas Graf				snprintf(tmp, sizeof(tmp), ":%02x",
86244d362409d5469aed47d19e7908d19bd194493aThomas Graf					 (unsigned char) addr->a_addr[i]);
86344d362409d5469aed47d19e7908d19bd194493aThomas Graf				strncat(buf, tmp, size - strlen(buf) - 1);
86444d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
86544d362409d5469aed47d19e7908d19bd194493aThomas Graf			break;
86644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
86744d362409d5469aed47d19e7908d19bd194493aThomas Graf
86844d362409d5469aed47d19e7908d19bd194493aThomas Grafprefix:
86944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (addr->a_prefixlen != (8 * addr->a_len)) {
87044d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
87144d362409d5469aed47d19e7908d19bd194493aThomas Graf		strncat(buf, tmp, size - strlen(buf) - 1);
87244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
87344d362409d5469aed47d19e7908d19bd194493aThomas Graf
87444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return buf;
87544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
87644d362409d5469aed47d19e7908d19bd194493aThomas Graf
87744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
87844d362409d5469aed47d19e7908d19bd194493aThomas Graf
87944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
88044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Address Family Transformations
88144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
88244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
88344d362409d5469aed47d19e7908d19bd194493aThomas Graf
88444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl afs[] = {
88544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_UNSPEC,unspec)
88644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_UNIX,unix)
88744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_LOCAL,local)
88844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_INET,inet)
88944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_AX25,ax25)
89044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_IPX,ipx)
89144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_APPLETALK,appletalk)
89244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_NETROM,netrom)
89344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_BRIDGE,bridge)
89444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_ATMPVC,atmpvc)
89544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_X25,x25)
89644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_INET6,inet6)
89744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_ROSE,rose)
89844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_DECnet,decnet)
89944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_NETBEUI,netbeui)
90044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_SECURITY,security)
90144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_KEY,key)
90244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_NETLINK,netlink)
90344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_ROUTE,route)
90444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_PACKET,packet)
90544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_ASH,ash)
90644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_ECONET,econet)
90744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_ATMSVC,atmsvc)
90844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_SNA,sna)
90944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_IRDA,irda)
91044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_PPPOX,pppox)
91144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_WANPIPE,wanpipe)
91244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_LLC,llc)
91344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(AF_BLUETOOTH,bluetooth)
91444d362409d5469aed47d19e7908d19bd194493aThomas Graf};
91544d362409d5469aed47d19e7908d19bd194493aThomas Graf
91644d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *nl_af2str(int family, char *buf, size_t size)
91744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
91844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __type2str(family, buf, size, afs, ARRAY_SIZE(afs));
91944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
92044d362409d5469aed47d19e7908d19bd194493aThomas Graf
92144d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_str2af(const char *name)
92244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
92344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int fam = __str2type(name, afs, ARRAY_SIZE(afs));
92444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return fam >= 0 ? fam : AF_UNSPEC;
92544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
92644d362409d5469aed47d19e7908d19bd194493aThomas Graf
92744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
92844d362409d5469aed47d19e7908d19bd194493aThomas Graf
92944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
930