libnl 2.0

/build/buildd/libnl2-2.0/lib/addr.c

00001 /*
00002  * lib/addr.c           Abstract Address
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup core
00014  * @defgroup addr Abstract Address
00015  *
00016  * @par 1) Transform character string to abstract address
00017  * @code
00018  * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC);
00019  * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
00020  * nl_addr_put(a);
00021  * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC);
00022  * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a)));
00023  * nl_addr_put(a);
00024  * @endcode
00025  * @{
00026  */
00027 
00028 #include <netlink-local.h>
00029 #include <netlink/netlink.h>
00030 #include <netlink/utils.h>
00031 #include <netlink/addr.h>
00032 #include <linux/socket.h>
00033 
00034 /* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
00035  * this, probably Alexey. */
00036 static inline uint16_t dn_ntohs(uint16_t addr)
00037 {
00038         union {
00039                 uint8_t byte[2];
00040                 uint16_t word;
00041         } u = {
00042                 .word = addr,
00043         };
00044 
00045         return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8);
00046 }
00047 
00048 static inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
00049                            size_t *pos, size_t len, int *started)
00050 {
00051         uint16_t tmp = *addr / scale;
00052 
00053         if (*pos == len)
00054                 return 1;
00055 
00056         if (((tmp) > 0) || *started || (scale == 1)) {
00057                 *str = tmp + '0';
00058                 *started = 1;
00059                 (*pos)++;
00060                 *addr -= (tmp * scale);
00061         }
00062 
00063         return 0;
00064 }
00065 
00066 static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str,
00067                              size_t len)
00068 {
00069         uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf);
00070         uint16_t area = addr >> 10;
00071         size_t pos = 0;
00072         int started = 0;
00073 
00074         if (addrlen != 2)
00075                 return NULL;
00076 
00077         addr &= 0x03ff;
00078 
00079         if (len == 0)
00080                 return str;
00081 
00082         if (do_digit(str + pos, &area, 10, &pos, len, &started))
00083                 return str;
00084 
00085         if (do_digit(str + pos, &area, 1, &pos, len, &started))
00086                 return str;
00087 
00088         if (pos == len)
00089                 return str;
00090 
00091         *(str + pos) = '.';
00092         pos++;
00093         started = 0;
00094 
00095         if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
00096                 return str;
00097 
00098         if (do_digit(str + pos, &addr, 100, &pos, len, &started))
00099                 return str;
00100 
00101         if (do_digit(str + pos, &addr, 10, &pos, len, &started))
00102                 return str;
00103 
00104         if (do_digit(str + pos, &addr, 1, &pos, len, &started))
00105                 return str;
00106 
00107         if (pos == len)
00108                 return str;
00109 
00110         *(str + pos) = 0;
00111 
00112         return str;
00113 }
00114 
00115 static int dnet_num(const char *src, uint16_t * dst)
00116 {
00117         int rv = 0;
00118         int tmp;
00119         *dst = 0;
00120 
00121         while ((tmp = *src++) != 0) {
00122                 tmp -= '0';
00123                 if ((tmp < 0) || (tmp > 9))
00124                         return rv;
00125 
00126                 rv++;
00127                 (*dst) *= 10;
00128                 (*dst) += tmp;
00129         }
00130 
00131         return rv;
00132 }
00133 
00134 static inline int dnet_pton(const char *src, char *addrbuf)
00135 {
00136         uint16_t area = 0;
00137         uint16_t node = 0;
00138         int pos;
00139 
00140         pos = dnet_num(src, &area);
00141         if ((pos == 0) || (area > 63) ||
00142             ((*(src + pos) != '.') && (*(src + pos) != ',')))
00143                 return -NLE_INVAL;
00144 
00145         pos = dnet_num(src + pos + 1, &node);
00146         if ((pos == 0) || (node > 1023))
00147                 return -NLE_INVAL;
00148 
00149         *(uint16_t *)addrbuf = dn_ntohs((area << 10) | node);
00150 
00151         return 1;
00152 }
00153 
00154 /**
00155  * @name Creating Abstract Addresses
00156  * @{
00157  */
00158 
00159 /**
00160  * Allocate new abstract address object.
00161  * @arg maxsize         Maximum size of the binary address.
00162  * @return Newly allocated address object or NULL
00163  */
00164 struct nl_addr *nl_addr_alloc(size_t maxsize)
00165 {
00166         struct nl_addr *addr;
00167         
00168         addr = calloc(1, sizeof(*addr) + maxsize);
00169         if (!addr)
00170                 return NULL;
00171 
00172         addr->a_refcnt = 1;
00173         addr->a_maxsize = maxsize;
00174 
00175         return addr;
00176 }
00177 
00178 /**
00179  * Allocate new abstract address object based on a binary address.
00180  * @arg family          Address family.
00181  * @arg buf             Buffer containing the binary address.
00182  * @arg size            Length of binary address buffer.
00183  * @return Newly allocated address handle or NULL
00184  */
00185 struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
00186 {
00187         struct nl_addr *addr;
00188 
00189         addr = nl_addr_alloc(size);
00190         if (!addr)
00191                 return NULL;
00192 
00193         addr->a_family = family;
00194         addr->a_len = size;
00195         addr->a_prefixlen = size*8;
00196 
00197         if (size)
00198                 memcpy(addr->a_addr, buf, size);
00199 
00200         return addr;
00201 }
00202 
00203 /**
00204  * Allocate abstract address based on netlink attribute.
00205  * @arg nla             Netlink attribute of unspecific type.
00206  * @arg family          Address family.
00207  *
00208  * Considers the netlink attribute payload a address of the specified
00209  * family and allocates a new abstract address based on it.
00210  *
00211  * @return Newly allocated address handle or NULL.
00212  */
00213 struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
00214 {
00215         return nl_addr_build(family, nla_data(nla), nla_len(nla));
00216 }
00217 
00218 /**
00219  * Allocate abstract address object based on a character string
00220  * @arg addrstr         Address represented as character string.
00221  * @arg hint            Address family hint or AF_UNSPEC.
00222  * @arg result          Pointer to store resulting address.
00223  *
00224  * Regognizes the following address formats:
00225  *@code
00226  *  Format                      Len                Family
00227  *  ----------------------------------------------------------------
00228  *  IPv6 address format         16                 AF_INET6
00229  *  ddd.ddd.ddd.ddd             4                  AF_INET
00230  *  HH:HH:HH:HH:HH:HH           6                  AF_LLC
00231  *  AA{.|,}NNNN                 2                  AF_DECnet
00232  *  HH:HH:HH:...                variable           AF_UNSPEC
00233  * @endcode
00234  *
00235  *  Special values:
00236  *    - none: All bits and length set to 0.
00237  *    - {default|all|any}: All bits set to 0, length based on hint or
00238  *                         AF_INET if no hint is given.
00239  *
00240  * The prefix length may be appened at the end prefixed with a
00241  * slash, e.g. 10.0.0.0/8.
00242  *
00243  * @return 0 on success or a negative error code.
00244  */
00245 int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
00246 {
00247         int err, copy = 0, len = 0, family = AF_UNSPEC;
00248         char *str, *prefix, buf[32];
00249         struct nl_addr *addr = NULL; /* gcc ain't that smart */
00250 
00251         str = strdup(addrstr);
00252         if (!str) {
00253                 err = -NLE_NOMEM;
00254                 goto errout;
00255         }
00256 
00257         prefix = strchr(str, '/');
00258         if (prefix)
00259                 *prefix = '\0';
00260 
00261         if (!strcasecmp(str, "none")) {
00262                 family = hint;
00263                 goto prefix;
00264         }
00265 
00266         if (!strcasecmp(str, "default") ||
00267             !strcasecmp(str, "all") ||
00268             !strcasecmp(str, "any")) {
00269                         
00270                 switch (hint) {
00271                         case AF_INET:
00272                         case AF_UNSPEC:
00273                                 /* Kind of a hack, we assume that if there is
00274                                  * no hint given the user wants to have a IPv4
00275                                  * address given back. */
00276                                 family = AF_INET;
00277                                 len = 4;
00278                                 goto prefix;
00279 
00280                         case AF_INET6:
00281                                 family = AF_INET6;
00282                                 len = 16;
00283                                 goto prefix;
00284 
00285                         case AF_LLC:
00286                                 family = AF_LLC;
00287                                 len = 6;
00288                                 goto prefix;
00289 
00290                         default:
00291                                 err = -NLE_AF_NOSUPPORT;
00292                                 goto errout;
00293                 }
00294         }
00295 
00296         copy = 1;
00297 
00298         if (hint == AF_INET || hint == AF_UNSPEC) {
00299                 if (inet_pton(AF_INET, str, buf) > 0) {
00300                         family = AF_INET;
00301                         len = 4;
00302                         goto prefix;
00303                 }
00304                 if (hint == AF_INET) {
00305                         err = -NLE_NOADDR;
00306                         goto errout;
00307                 }
00308         }
00309 
00310         if (hint == AF_INET6 || hint == AF_UNSPEC) {
00311                 if (inet_pton(AF_INET6, str, buf) > 0) {
00312                         family = AF_INET6;
00313                         len = 16;
00314                         goto prefix;
00315                 }
00316                 if (hint == AF_INET6) {
00317                         err = -NLE_NOADDR;
00318                         goto errout;
00319                 }
00320         }
00321 
00322         if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) {
00323                 unsigned int a, b, c, d, e, f;
00324 
00325                 if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
00326                     &a, &b, &c, &d, &e, &f) == 6) {
00327                         family = AF_LLC;
00328                         len = 6;
00329                         buf[0] = (unsigned char) a;
00330                         buf[1] = (unsigned char) b;
00331                         buf[2] = (unsigned char) c;
00332                         buf[3] = (unsigned char) d;
00333                         buf[4] = (unsigned char) e;
00334                         buf[5] = (unsigned char) f;
00335                         goto prefix;
00336                 }
00337 
00338                 if (hint == AF_LLC) {
00339                         err = -NLE_NOADDR;
00340                         goto errout;
00341                 }
00342         }
00343 
00344         if ((hint == AF_DECnet || hint == AF_UNSPEC) &&
00345             (strchr(str, '.') || strchr(str, ','))) {
00346                 if (dnet_pton(str, buf) > 0) {
00347                         family = AF_DECnet;
00348                         len = 2;
00349                         goto prefix;
00350                 }
00351                 if (hint == AF_DECnet) {
00352                         err = -NLE_NOADDR;
00353                         goto errout;
00354                 }
00355         }
00356 
00357         if (hint == AF_UNSPEC && strchr(str, ':')) {
00358                 int i = 0;
00359                 char *s = str, *p;
00360                 for (;;) {
00361                         long l = strtol(s, &p, 16);
00362 
00363                         if (s == p || l > 0xff || i >= sizeof(buf)) {
00364                                 err = -NLE_INVAL;
00365                                 goto errout;
00366                         }
00367 
00368                         buf[i++] = (unsigned char) l;
00369                         if (*p == '\0')
00370                                 break;
00371                         s = ++p;
00372                 }
00373 
00374                 len = i;
00375                 family = AF_UNSPEC;
00376                 goto prefix;
00377         }
00378 
00379         err = -NLE_NOADDR;
00380         goto errout;
00381 
00382 prefix:
00383         addr = nl_addr_alloc(len);
00384         if (!addr) {
00385                 err = -NLE_NOMEM;
00386                 goto errout;
00387         }
00388 
00389         nl_addr_set_family(addr, family);
00390 
00391         if (copy)
00392                 nl_addr_set_binary_addr(addr, buf, len);
00393 
00394         if (prefix) {
00395                 char *p;
00396                 long pl = strtol(++prefix, &p, 0);
00397                 if (p == prefix) {
00398                         nl_addr_destroy(addr);
00399                         err = -NLE_INVAL;
00400                         goto errout;
00401                 }
00402                 nl_addr_set_prefixlen(addr, pl);
00403         } else
00404                 nl_addr_set_prefixlen(addr, len * 8);
00405 
00406         *result = addr;
00407         err = 0;
00408 errout:
00409         free(str);
00410 
00411         return err;
00412 }
00413 
00414 /**
00415  * Clone existing abstract address object.
00416  * @arg addr            Abstract address object.
00417  * @return Newly allocated abstract address object being a duplicate of the
00418  *         specified address object or NULL if a failure occured.
00419  */
00420 struct nl_addr *nl_addr_clone(struct nl_addr *addr)
00421 {
00422         struct nl_addr *new;
00423 
00424         new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len);
00425         if (new)
00426                 new->a_prefixlen = addr->a_prefixlen;
00427 
00428         return new;
00429 }
00430 
00431 /** @} */
00432 
00433 /**
00434  * @name Destroying Abstract Addresses
00435  * @{
00436  */
00437 
00438 /**
00439  * Destroy abstract address object.
00440  * @arg addr            Abstract address object.
00441  */
00442 void nl_addr_destroy(struct nl_addr *addr)
00443 {
00444         if (!addr)
00445                 return;
00446 
00447         if (addr->a_refcnt != 1)
00448                 BUG();
00449 
00450         free(addr);
00451 }
00452 
00453 /** @} */
00454 
00455 /**
00456  * @name Managing Usage References
00457  * @{
00458  */
00459 
00460 struct nl_addr *nl_addr_get(struct nl_addr *addr)
00461 {
00462         addr->a_refcnt++;
00463 
00464         return addr;
00465 }
00466 
00467 void nl_addr_put(struct nl_addr *addr)
00468 {
00469         if (!addr)
00470                 return;
00471 
00472         if (addr->a_refcnt == 1)
00473                 nl_addr_destroy(addr);
00474         else
00475                 addr->a_refcnt--;
00476 }
00477 
00478 /**
00479  * Check whether an abstract address object is shared.
00480  * @arg addr            Abstract address object.
00481  * @return Non-zero if the abstract address object is shared, otherwise 0.
00482  */
00483 int nl_addr_shared(struct nl_addr *addr)
00484 {
00485         return addr->a_refcnt > 1;
00486 }
00487 
00488 /** @} */
00489 
00490 /**
00491  * @name Miscellaneous
00492  * @{
00493  */
00494 
00495 /**
00496  * Compares two abstract address objects.
00497  * @arg a               A abstract address object.
00498  * @arg b               Another abstract address object.
00499  *
00500  * @return Integer less than, equal to or greather than zero if \c is found,
00501  *         respectively to be less than, to, or be greater than \c b.
00502  */
00503 int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
00504 {
00505         int d = a->a_family - b->a_family;
00506 
00507         if (d == 0) {
00508                 d = a->a_len - b->a_len;
00509 
00510                 if (a->a_len && d == 0)
00511                         return memcmp(a->a_addr, b->a_addr, a->a_len);
00512         }
00513 
00514         return d;
00515 }
00516 
00517 /**
00518  * Compares the prefix of two abstract address objects.
00519  * @arg a               A abstract address object.
00520  * @arg b               Another abstract address object.
00521  *
00522  * @return Integer less than, equal to or greather than zero if \c is found,
00523  *         respectively to be less than, to, or be greater than \c b.
00524  */
00525 int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
00526 {
00527         int d = a->a_family - b->a_family;
00528 
00529         if (d == 0) {
00530                 int len = min(a->a_prefixlen, b->a_prefixlen);
00531                 int bytes = len / 8;
00532 
00533                 d = memcmp(a->a_addr, b->a_addr, bytes);
00534                 if (d == 0) {
00535                         int mask = (1UL << (len % 8)) - 1UL;
00536 
00537                         d = (a->a_addr[bytes] & mask) -
00538                             (b->a_addr[bytes] & mask);
00539                 }
00540         }
00541 
00542         return d;
00543 }
00544 
00545 /**
00546  * Returns true if the address consists of all zeros
00547  * @arg addr            Address to look at.
00548  */
00549 int nl_addr_iszero(struct nl_addr *addr)
00550 {
00551         int i;
00552 
00553         for (i = 0; i < addr->a_len; i++)
00554                 if (addr->a_addr[i])
00555                         return 0;
00556 
00557         return 1;
00558 }
00559 
00560 /**
00561  * Check if an address matches a certain family.
00562  * @arg addr            Address represented as character string.
00563  * @arg family          Desired address family.
00564  *
00565  * @return 1 if the address is of the desired address family,
00566  *         otherwise 0 is returned.
00567  */
00568 int nl_addr_valid(char *addr, int family)
00569 {
00570         int ret;
00571         char buf[32];
00572 
00573         switch (family) {
00574         case AF_INET:
00575         case AF_INET6:
00576                 ret = inet_pton(family, addr, buf);
00577                 if (ret <= 0)
00578                         return 0;
00579                 break;
00580 
00581         case AF_DECnet:
00582                 ret = dnet_pton(addr, buf);
00583                 if (ret <= 0)
00584                         return 0;
00585                 break;
00586 
00587         case AF_LLC:
00588                 if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6)
00589                         return 0;
00590                 break;
00591         }
00592 
00593         return 1;
00594 }
00595 
00596 /**
00597  * Guess address family of an abstract address object based on address size.
00598  * @arg addr            Abstract address object.
00599  * @return Address family or AF_UNSPEC if guessing wasn't successful.
00600  */
00601 int nl_addr_guess_family(struct nl_addr *addr)
00602 {
00603         switch (addr->a_len) {
00604                 case 4:
00605                         return AF_INET;
00606                 case 6:
00607                         return AF_LLC;
00608                 case 16:
00609                         return AF_INET6;
00610                 default:
00611                         return AF_UNSPEC;
00612         }
00613 }
00614 
00615 /**
00616  * Fill out sockaddr structure with values from abstract address object.
00617  * @arg addr            Abstract address object.
00618  * @arg sa              Destination sockaddr structure buffer.
00619  * @arg salen           Length of sockaddr structure buffer.
00620  *
00621  * Fills out the specified sockaddr structure with the data found in the
00622  * specified abstract address. The salen argument needs to be set to the
00623  * size of sa but will be modified to the actual size used during before
00624  * the function exits.
00625  *
00626  * @return 0 on success or a negative error code
00627  */
00628 int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
00629                           socklen_t *salen)
00630 {
00631         switch (addr->a_family) {
00632         case AF_INET: {
00633                 struct sockaddr_in *sai = (struct sockaddr_in *) sa;
00634 
00635                 if (*salen < sizeof(*sai))
00636                         return -NLE_INVAL;
00637 
00638                 sai->sin_family = addr->a_family;
00639                 memcpy(&sai->sin_addr, addr->a_addr, 4);
00640                 *salen = sizeof(*sai);
00641         }
00642                 break;
00643 
00644         case AF_INET6: {
00645                 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
00646 
00647                 if (*salen < sizeof(*sa6))
00648                         return -NLE_INVAL;
00649 
00650                 sa6->sin6_family = addr->a_family;
00651                 memcpy(&sa6->sin6_addr, addr->a_addr, 16);
00652                 *salen = sizeof(*sa6);
00653         }
00654                 break;
00655 
00656         default:
00657                 return -NLE_INVAL;
00658         }
00659 
00660         return 0;
00661 }
00662 
00663 
00664 /** @} */
00665 
00666 /**
00667  * @name Getting Information About Addresses
00668  * @{
00669  */
00670 
00671 /**
00672  * Call getaddrinfo() for an abstract address object.
00673  * @arg addr            Abstract address object.
00674  * @arg result          Pointer to store resulting address list.
00675  * 
00676  * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST
00677  * mode.
00678  *
00679  * @note The caller is responsible for freeing the linked list using the
00680  *       interface provided by getaddrinfo(3).
00681  *
00682  * @return 0 on success or a negative error code.
00683  */
00684 int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
00685 {
00686         int err;
00687         char buf[INET6_ADDRSTRLEN+5];
00688         struct addrinfo hint = {
00689                 .ai_flags = AI_NUMERICHOST,
00690                 .ai_family = addr->a_family,
00691         };
00692 
00693         nl_addr2str(addr, buf, sizeof(buf));
00694 
00695         err = getaddrinfo(buf, NULL, &hint, result);
00696         if (err != 0) {
00697                 switch (err) {
00698                 case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT;
00699                 case EAI_AGAIN: return -NLE_AGAIN;
00700                 case EAI_BADFLAGS: return -NLE_INVAL;
00701                 case EAI_FAIL: return -NLE_NOADDR;
00702                 case EAI_FAMILY: return -NLE_AF_NOSUPPORT;
00703                 case EAI_MEMORY: return -NLE_NOMEM;
00704                 case EAI_NODATA: return -NLE_NOADDR;
00705                 case EAI_NONAME: return -NLE_OBJ_NOTFOUND;
00706                 case EAI_SERVICE: return -NLE_OPNOTSUPP;
00707                 case EAI_SOCKTYPE: return -NLE_BAD_SOCK;
00708                 default: return -NLE_FAILURE;
00709                 }
00710         }
00711 
00712         return 0;
00713 }
00714 
00715 /**
00716  * Resolve abstract address object to a name using getnameinfo().
00717  * @arg addr            Abstract address object.
00718  * @arg host            Destination buffer for host name.
00719  * @arg hostlen         Length of destination buffer.
00720  *
00721  * Resolves the abstract address to a name and writes the looked up result
00722  * into the host buffer. getnameinfo() is used to perform the lookup and
00723  * is put into NI_NAMEREQD mode so the function will fail if the lookup
00724  * couldn't be performed.
00725  *
00726  * @return 0 on success or a negative error code.
00727  */
00728 int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
00729 {
00730         int err;
00731         struct sockaddr_in6 buf;
00732         socklen_t salen = sizeof(buf);
00733 
00734         err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen);
00735         if (err < 0)
00736                 return err;
00737 
00738         err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen,
00739                           NULL, 0, NI_NAMEREQD);
00740         if (err < 0)
00741                 return nl_syserr2nlerr(err);
00742 
00743         return 0;
00744 }
00745 
00746 /** @} */
00747 
00748 /**
00749  * @name Attributes
00750  * @{
00751  */
00752 
00753 void nl_addr_set_family(struct nl_addr *addr, int family)
00754 {
00755         addr->a_family = family;
00756 }
00757 
00758 int nl_addr_get_family(struct nl_addr *addr)
00759 {
00760         return addr->a_family;
00761 }
00762 
00763 /**
00764  * Set binary address of abstract address object.
00765  * @arg addr            Abstract address object.
00766  * @arg buf             Buffer containing binary address.
00767  * @arg len             Length of buffer containing binary address.
00768  */
00769 int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
00770 {
00771         if (len > addr->a_maxsize)
00772                 return -NLE_RANGE;
00773 
00774         addr->a_len = len;
00775         memcpy(addr->a_addr, buf, len);
00776 
00777         return 0;
00778 }
00779 
00780 /**
00781  * Get binary address of abstract address object.
00782  * @arg addr            Abstract address object.
00783  */
00784 void *nl_addr_get_binary_addr(struct nl_addr *addr)
00785 {
00786         return addr->a_addr;
00787 }
00788 
00789 /**
00790  * Get length of binary address of abstract address object.
00791  * @arg addr            Abstract address object.
00792  */
00793 unsigned int nl_addr_get_len(struct nl_addr *addr)
00794 {
00795         return addr->a_len;
00796 }
00797 
00798 void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
00799 {
00800         addr->a_prefixlen = prefixlen;
00801 }
00802 
00803 /**
00804  * Get prefix length of abstract address object.
00805  * @arg addr            Abstract address object.
00806  */
00807 unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
00808 {
00809         return addr->a_prefixlen;
00810 }
00811 
00812 /** @} */
00813 
00814 /**
00815  * @name Translations to Strings
00816  * @{
00817  */
00818 
00819 /**
00820  * Convert abstract address object to character string.
00821  * @arg addr            Abstract address object.
00822  * @arg buf             Destination buffer.
00823  * @arg size            Size of destination buffer.
00824  *
00825  * Converts an abstract address to a character string and stores
00826  * the result in the specified destination buffer.
00827  *
00828  * @return Address represented in ASCII stored in destination buffer.
00829  */
00830 char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
00831 {
00832         int i;
00833         char tmp[16];
00834 
00835         if (!addr || !addr->a_len) {
00836                 snprintf(buf, size, "none");
00837                 if (addr)
00838                         goto prefix;
00839                 else
00840                         return buf;
00841         }
00842 
00843         switch (addr->a_family) {
00844                 case AF_INET:
00845                         inet_ntop(AF_INET, addr->a_addr, buf, size);
00846                         break;
00847 
00848                 case AF_INET6:
00849                         inet_ntop(AF_INET6, addr->a_addr, buf, size);
00850                         break;
00851 
00852                 case AF_DECnet:
00853                         dnet_ntop(addr->a_addr, addr->a_len, buf, size);
00854                         break;
00855 
00856                 case AF_LLC:
00857                 default:
00858                         snprintf(buf, size, "%02x",
00859                                  (unsigned char) addr->a_addr[0]);
00860                         for (i = 1; i < addr->a_len; i++) {
00861                                 snprintf(tmp, sizeof(tmp), ":%02x",
00862                                          (unsigned char) addr->a_addr[i]);
00863                                 strncat(buf, tmp, size - strlen(buf) - 1);
00864                         }
00865                         break;
00866         }
00867 
00868 prefix:
00869         if (addr->a_prefixlen != (8 * addr->a_len)) {
00870                 snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
00871                 strncat(buf, tmp, size - strlen(buf) - 1);
00872         }
00873 
00874         return buf;
00875 }
00876 
00877 /** @} */
00878 
00879 /**
00880  * @name Address Family Transformations
00881  * @{
00882  */
00883 
00884 static struct trans_tbl afs[] = {
00885         __ADD(AF_UNSPEC,unspec)
00886         __ADD(AF_UNIX,unix)
00887         __ADD(AF_LOCAL,local)
00888         __ADD(AF_INET,inet)
00889         __ADD(AF_AX25,ax25)
00890         __ADD(AF_IPX,ipx)
00891         __ADD(AF_APPLETALK,appletalk)
00892         __ADD(AF_NETROM,netrom)
00893         __ADD(AF_BRIDGE,bridge)
00894         __ADD(AF_ATMPVC,atmpvc)
00895         __ADD(AF_X25,x25)
00896         __ADD(AF_INET6,inet6)
00897         __ADD(AF_ROSE,rose)
00898         __ADD(AF_DECnet,decnet)
00899         __ADD(AF_NETBEUI,netbeui)
00900         __ADD(AF_SECURITY,security)
00901         __ADD(AF_KEY,key)
00902         __ADD(AF_NETLINK,netlink)
00903         __ADD(AF_ROUTE,route)
00904         __ADD(AF_PACKET,packet)
00905         __ADD(AF_ASH,ash)
00906         __ADD(AF_ECONET,econet)
00907         __ADD(AF_ATMSVC,atmsvc)
00908         __ADD(AF_SNA,sna)
00909         __ADD(AF_IRDA,irda)
00910         __ADD(AF_PPPOX,pppox)
00911         __ADD(AF_WANPIPE,wanpipe)
00912         __ADD(AF_LLC,llc)
00913         __ADD(AF_BLUETOOTH,bluetooth)
00914 };
00915 
00916 char *nl_af2str(int family, char *buf, size_t size)
00917 {
00918         return __type2str(family, buf, size, afs, ARRAY_SIZE(afs));
00919 }
00920 
00921 int nl_str2af(const char *name)
00922 {
00923         int fam = __str2type(name, afs, ARRAY_SIZE(afs));
00924         return fam >= 0 ? fam : AF_UNSPEC;
00925 }
00926 
00927 /** @} */
00928 
00929 /** @} */