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