summaryrefslogtreecommitdiffstats
path: root/lib/mpls_pton.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/mpls_pton.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/lib/mpls_pton.c b/lib/mpls_pton.c
new file mode 100644
index 0000000..065374e
--- /dev/null
+++ b/lib/mpls_pton.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <linux/mpls.h>
+
+#include "utils.h"
+
+
+static int mpls_pton1(const char *name, struct mpls_label *addr,
+ unsigned int maxlabels)
+{
+ char *endp;
+ unsigned count;
+
+ for (count = 0; count < maxlabels; count++) {
+ unsigned long label;
+
+ label = strtoul(name, &endp, 0);
+ /* Fail when the label value is out or range */
+ if (label >= (1 << 20))
+ return 0;
+
+ if (endp == name) /* no digits */
+ return 0;
+
+ addr->entry = htonl(label << MPLS_LS_LABEL_SHIFT);
+ if (*endp == '\0') {
+ addr->entry |= htonl(1 << MPLS_LS_S_SHIFT);
+ return 1;
+ }
+
+ /* Bad character in the address */
+ if (*endp != '/')
+ return 0;
+
+ name = endp + 1;
+ addr += 1;
+ }
+ /* The address was too long */
+ fprintf(stderr, "Error: too many labels.\n");
+ return 0;
+}
+
+int mpls_pton(int af, const char *src, void *addr, size_t alen)
+{
+ unsigned int maxlabels = alen / sizeof(struct mpls_label);
+ int err;
+
+ switch(af) {
+ case AF_MPLS:
+ errno = 0;
+ err = mpls_pton1(src, (struct mpls_label *)addr, maxlabels);
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ err = -1;
+ }
+
+ return err;
+}