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