You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.1 KiB
110 lines
2.1 KiB
/* SPDX-License-Identifier: LGPL-2.1-only */
|
|
/*
|
|
* Adapted from mpls_ntop and mpls_pton copied from iproute2,
|
|
* lib/mpls_ntop.c and lib/mpls_pton.c
|
|
*/
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <netinet/in.h>
|
|
#include <netlink/netlink-compat.h>
|
|
#include <netlink-private/route/mpls.h>
|
|
#include <linux-private/linux/mpls.h>
|
|
|
|
static const char *mpls_ntop1(const struct mpls_label *addr,
|
|
char *buf, size_t buflen)
|
|
{
|
|
size_t destlen = buflen;
|
|
char *dest = buf;
|
|
int count = 0;
|
|
|
|
while (1) {
|
|
uint32_t entry = ntohl(addr[count++].entry);
|
|
uint32_t label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
|
|
int len = snprintf(dest, destlen, "%u", label);
|
|
|
|
if (len >= destlen)
|
|
break;
|
|
|
|
/* Is this the end? */
|
|
if (entry & MPLS_LS_S_MASK)
|
|
return buf;
|
|
|
|
dest += len;
|
|
destlen -= len;
|
|
if (destlen) {
|
|
*dest = '/';
|
|
dest++;
|
|
destlen--;
|
|
}
|
|
}
|
|
errno = E2BIG;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen)
|
|
{
|
|
switch(af) {
|
|
case AF_MPLS:
|
|
errno = 0;
|
|
return mpls_ntop1((struct mpls_label *)addr, buf, buflen);
|
|
}
|
|
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
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 (count + 1) * sizeof(struct mpls_label);
|
|
}
|
|
|
|
/* Bad character in the address */
|
|
if (*endp != '/')
|
|
return 0;
|
|
|
|
name = endp + 1;
|
|
addr += 1;
|
|
}
|
|
|
|
/* The address was too long */
|
|
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;
|
|
}
|