libnl  3.4.0
mpls.c
1 /*
2  * Adapted from mpls_ntop and mpls_pton copied from iproute2,
3  * lib/mpls_ntop.c and lib/mpls_pton.c
4  */
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <netinet/in.h>
9 #include <netlink/netlink-compat.h>
10 #include <netlink-private/route/mpls.h>
11 #include <linux-private/linux/mpls.h>
12 
13 static const char *mpls_ntop1(const struct mpls_label *addr,
14  char *buf, size_t buflen)
15 {
16  size_t destlen = buflen;
17  char *dest = buf;
18  int count = 0;
19 
20  while (1) {
21  uint32_t entry = ntohl(addr[count++].entry);
22  uint32_t label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
23  int len = snprintf(dest, destlen, "%u", label);
24 
25  if (len >= destlen)
26  break;
27 
28  /* Is this the end? */
29  if (entry & MPLS_LS_S_MASK)
30  return buf;
31 
32  dest += len;
33  destlen -= len;
34  if (destlen) {
35  *dest = '/';
36  dest++;
37  destlen--;
38  }
39  }
40  errno = E2BIG;
41 
42  return NULL;
43 }
44 
45 const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen)
46 {
47  switch(af) {
48  case AF_MPLS:
49  errno = 0;
50  return mpls_ntop1((struct mpls_label *)addr, buf, buflen);
51  }
52 
53  errno = EINVAL;
54  return NULL;
55 }
56 
57 static int mpls_pton1(const char *name, struct mpls_label *addr,
58  unsigned int maxlabels)
59 {
60  char *endp;
61  unsigned count;
62 
63  for (count = 0; count < maxlabels; count++) {
64  unsigned long label;
65 
66  label = strtoul(name, &endp, 0);
67  /* Fail when the label value is out or range */
68  if (label >= (1 << 20))
69  return 0;
70 
71  if (endp == name) /* no digits */
72  return 0;
73 
74  addr->entry = htonl(label << MPLS_LS_LABEL_SHIFT);
75  if (*endp == '\0') {
76  addr->entry |= htonl(1 << MPLS_LS_S_SHIFT);
77  return (count + 1) * sizeof(struct mpls_label);
78  }
79 
80  /* Bad character in the address */
81  if (*endp != '/')
82  return 0;
83 
84  name = endp + 1;
85  addr += 1;
86  }
87 
88  /* The address was too long */
89  return 0;
90 }
91 
92 int mpls_pton(int af, const char *src, void *addr, size_t alen)
93 {
94  unsigned int maxlabels = alen / sizeof(struct mpls_label);
95  int err;
96 
97  switch(af) {
98  case AF_MPLS:
99  errno = 0;
100  err = mpls_pton1(src, (struct mpls_label *)addr, maxlabels);
101  break;
102  default:
103  errno = EAFNOSUPPORT;
104  err = -1;
105  }
106 
107  return err;
108 }