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