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