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