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