xref: /aosp_15_r20/external/libnl/lib/route/classid.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  * Copyright (c) 2010-2013 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker  * @ingroup tc
8*4dc78e53SAndroid Build Coastguard Worker  * @defgroup classid ClassID Management
9*4dc78e53SAndroid Build Coastguard Worker  * @{
10*4dc78e53SAndroid Build Coastguard Worker  */
11*4dc78e53SAndroid Build Coastguard Worker 
12*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
13*4dc78e53SAndroid Build Coastguard Worker 
14*4dc78e53SAndroid Build Coastguard Worker #include <sys/stat.h>
15*4dc78e53SAndroid Build Coastguard Worker #include <search.h>
16*4dc78e53SAndroid Build Coastguard Worker 
17*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
18*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
19*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/tc.h>
20*4dc78e53SAndroid Build Coastguard Worker 
21*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
22*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-core/nl-core.h"
23*4dc78e53SAndroid Build Coastguard Worker 
24*4dc78e53SAndroid Build Coastguard Worker struct classid_map
25*4dc78e53SAndroid Build Coastguard Worker {
26*4dc78e53SAndroid Build Coastguard Worker 	uint32_t		classid;
27*4dc78e53SAndroid Build Coastguard Worker 	char *			name;
28*4dc78e53SAndroid Build Coastguard Worker 	struct nl_list_head	name_list;
29*4dc78e53SAndroid Build Coastguard Worker };
30*4dc78e53SAndroid Build Coastguard Worker 
31*4dc78e53SAndroid Build Coastguard Worker #define CLASSID_NAME_HT_SIZ 256
32*4dc78e53SAndroid Build Coastguard Worker 
33*4dc78e53SAndroid Build Coastguard Worker static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ];
34*4dc78e53SAndroid Build Coastguard Worker 
35*4dc78e53SAndroid Build Coastguard Worker static void *id_root = NULL;
36*4dc78e53SAndroid Build Coastguard Worker 
compare_id(const void * pa,const void * pb)37*4dc78e53SAndroid Build Coastguard Worker static int compare_id(const void *pa, const void *pb)
38*4dc78e53SAndroid Build Coastguard Worker {
39*4dc78e53SAndroid Build Coastguard Worker 	const struct classid_map *ma = pa;
40*4dc78e53SAndroid Build Coastguard Worker 	const struct classid_map *mb = pb;
41*4dc78e53SAndroid Build Coastguard Worker 
42*4dc78e53SAndroid Build Coastguard Worker 	if (ma->classid < mb->classid)
43*4dc78e53SAndroid Build Coastguard Worker 		return -1;
44*4dc78e53SAndroid Build Coastguard Worker 
45*4dc78e53SAndroid Build Coastguard Worker 	if (ma->classid > mb->classid)
46*4dc78e53SAndroid Build Coastguard Worker 		return 1;
47*4dc78e53SAndroid Build Coastguard Worker 
48*4dc78e53SAndroid Build Coastguard Worker 	return 0;
49*4dc78e53SAndroid Build Coastguard Worker }
50*4dc78e53SAndroid Build Coastguard Worker 
51*4dc78e53SAndroid Build Coastguard Worker /* djb2 */
classid_tbl_hash(const char * str)52*4dc78e53SAndroid Build Coastguard Worker static unsigned int classid_tbl_hash(const char *str)
53*4dc78e53SAndroid Build Coastguard Worker {
54*4dc78e53SAndroid Build Coastguard Worker 	unsigned long hash = 5381;
55*4dc78e53SAndroid Build Coastguard Worker 	int c;
56*4dc78e53SAndroid Build Coastguard Worker 
57*4dc78e53SAndroid Build Coastguard Worker 	while ((c = *str++))
58*4dc78e53SAndroid Build Coastguard Worker 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
59*4dc78e53SAndroid Build Coastguard Worker 
60*4dc78e53SAndroid Build Coastguard Worker 	return hash % CLASSID_NAME_HT_SIZ;
61*4dc78e53SAndroid Build Coastguard Worker }
62*4dc78e53SAndroid Build Coastguard Worker 
classid_lookup(const char * name,uint32_t * result)63*4dc78e53SAndroid Build Coastguard Worker static int classid_lookup(const char *name, uint32_t *result)
64*4dc78e53SAndroid Build Coastguard Worker {
65*4dc78e53SAndroid Build Coastguard Worker 	struct classid_map *map;
66*4dc78e53SAndroid Build Coastguard Worker 	int n = classid_tbl_hash(name);
67*4dc78e53SAndroid Build Coastguard Worker 
68*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(map, &tbl_name[n], name_list) {
69*4dc78e53SAndroid Build Coastguard Worker 		if (!strcasecmp(map->name, name)) {
70*4dc78e53SAndroid Build Coastguard Worker 			*result = map->classid;
71*4dc78e53SAndroid Build Coastguard Worker 			return 0;
72*4dc78e53SAndroid Build Coastguard Worker 		}
73*4dc78e53SAndroid Build Coastguard Worker 	}
74*4dc78e53SAndroid Build Coastguard Worker 
75*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_OBJ_NOTFOUND;
76*4dc78e53SAndroid Build Coastguard Worker }
77*4dc78e53SAndroid Build Coastguard Worker 
name_lookup(const uint32_t classid)78*4dc78e53SAndroid Build Coastguard Worker static char *name_lookup(const uint32_t classid)
79*4dc78e53SAndroid Build Coastguard Worker {
80*4dc78e53SAndroid Build Coastguard Worker 	void *res;
81*4dc78e53SAndroid Build Coastguard Worker 	struct classid_map cm = {
82*4dc78e53SAndroid Build Coastguard Worker 		.classid = classid,
83*4dc78e53SAndroid Build Coastguard Worker 		.name = "search entry",
84*4dc78e53SAndroid Build Coastguard Worker 	};
85*4dc78e53SAndroid Build Coastguard Worker 
86*4dc78e53SAndroid Build Coastguard Worker 	if ((res = tfind(&cm, &id_root, &compare_id)))
87*4dc78e53SAndroid Build Coastguard Worker 		return (*(struct classid_map **) res)->name;
88*4dc78e53SAndroid Build Coastguard Worker 
89*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
90*4dc78e53SAndroid Build Coastguard Worker }
91*4dc78e53SAndroid Build Coastguard Worker 
92*4dc78e53SAndroid Build Coastguard Worker /**
93*4dc78e53SAndroid Build Coastguard Worker  * @name Traffic Control Handle Translations
94*4dc78e53SAndroid Build Coastguard Worker  * @{
95*4dc78e53SAndroid Build Coastguard Worker  */
96*4dc78e53SAndroid Build Coastguard Worker 
97*4dc78e53SAndroid Build Coastguard Worker /**
98*4dc78e53SAndroid Build Coastguard Worker  * Convert a traffic control handle to a character string (Reentrant).
99*4dc78e53SAndroid Build Coastguard Worker  * @arg handle		traffic control handle
100*4dc78e53SAndroid Build Coastguard Worker  * @arg buf		destination buffer
101*4dc78e53SAndroid Build Coastguard Worker  * @arg len		buffer length
102*4dc78e53SAndroid Build Coastguard Worker  *
103*4dc78e53SAndroid Build Coastguard Worker  * Converts a tarffic control handle to a character string in the
104*4dc78e53SAndroid Build Coastguard Worker  * form of \c MAJ:MIN and stores it in the specified destination buffer.
105*4dc78e53SAndroid Build Coastguard Worker  *
106*4dc78e53SAndroid Build Coastguard Worker  * @return The destination buffer or the type encoded in hexidecimal
107*4dc78e53SAndroid Build Coastguard Worker  *         form if no match was found.
108*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_tc_handle2str(uint32_t handle,char * buf,size_t len)109*4dc78e53SAndroid Build Coastguard Worker char *rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
110*4dc78e53SAndroid Build Coastguard Worker {
111*4dc78e53SAndroid Build Coastguard Worker 	if (TC_H_ROOT == handle)
112*4dc78e53SAndroid Build Coastguard Worker 		snprintf(buf, len, "root");
113*4dc78e53SAndroid Build Coastguard Worker 	else if (TC_H_UNSPEC == handle)
114*4dc78e53SAndroid Build Coastguard Worker 		snprintf(buf, len, "none");
115*4dc78e53SAndroid Build Coastguard Worker 	else if (TC_H_INGRESS == handle)
116*4dc78e53SAndroid Build Coastguard Worker 		snprintf(buf, len, "ingress");
117*4dc78e53SAndroid Build Coastguard Worker 	else {
118*4dc78e53SAndroid Build Coastguard Worker 		char *name;
119*4dc78e53SAndroid Build Coastguard Worker 
120*4dc78e53SAndroid Build Coastguard Worker 		if ((name = name_lookup(handle)))
121*4dc78e53SAndroid Build Coastguard Worker 			snprintf(buf, len, "%s", name);
122*4dc78e53SAndroid Build Coastguard Worker 		else if (0 == TC_H_MAJ(handle))
123*4dc78e53SAndroid Build Coastguard Worker 			snprintf(buf, len, ":%x", TC_H_MIN(handle));
124*4dc78e53SAndroid Build Coastguard Worker 		else if (0 == TC_H_MIN(handle))
125*4dc78e53SAndroid Build Coastguard Worker 			snprintf(buf, len, "%x:", TC_H_MAJ(handle) >> 16);
126*4dc78e53SAndroid Build Coastguard Worker 		else
127*4dc78e53SAndroid Build Coastguard Worker 			snprintf(buf, len, "%x:%x",
128*4dc78e53SAndroid Build Coastguard Worker 				TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
129*4dc78e53SAndroid Build Coastguard Worker 	}
130*4dc78e53SAndroid Build Coastguard Worker 
131*4dc78e53SAndroid Build Coastguard Worker 	return buf;
132*4dc78e53SAndroid Build Coastguard Worker }
133*4dc78e53SAndroid Build Coastguard Worker 
134*4dc78e53SAndroid Build Coastguard Worker /**
135*4dc78e53SAndroid Build Coastguard Worker  * Convert a charactering strint to a traffic control handle
136*4dc78e53SAndroid Build Coastguard Worker  * @arg str		traffic control handle as character string
137*4dc78e53SAndroid Build Coastguard Worker  * @arg res		destination buffer
138*4dc78e53SAndroid Build Coastguard Worker  *
139*4dc78e53SAndroid Build Coastguard Worker  * Converts the provided character string specifying a traffic
140*4dc78e53SAndroid Build Coastguard Worker  * control handle to the corresponding numeric value.
141*4dc78e53SAndroid Build Coastguard Worker  *
142*4dc78e53SAndroid Build Coastguard Worker  * The handle must be provided in one of the following formats:
143*4dc78e53SAndroid Build Coastguard Worker  *  - NAME
144*4dc78e53SAndroid Build Coastguard Worker  *  - root
145*4dc78e53SAndroid Build Coastguard Worker  *  - none
146*4dc78e53SAndroid Build Coastguard Worker  *  - MAJ:
147*4dc78e53SAndroid Build Coastguard Worker  *  - :MIN
148*4dc78e53SAndroid Build Coastguard Worker  *  - NAME:MIN
149*4dc78e53SAndroid Build Coastguard Worker  *  - MAJ:MIN
150*4dc78e53SAndroid Build Coastguard Worker  *  - MAJMIN
151*4dc78e53SAndroid Build Coastguard Worker  *
152*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code
153*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_tc_str2handle(const char * str,uint32_t * res)154*4dc78e53SAndroid Build Coastguard Worker int rtnl_tc_str2handle(const char *str, uint32_t *res)
155*4dc78e53SAndroid Build Coastguard Worker {
156*4dc78e53SAndroid Build Coastguard Worker 	char *colon, *end;
157*4dc78e53SAndroid Build Coastguard Worker 	uint32_t h;
158*4dc78e53SAndroid Build Coastguard Worker 	int err;
159*4dc78e53SAndroid Build Coastguard Worker 
160*4dc78e53SAndroid Build Coastguard Worker 	if (!strcasecmp(str, "root")) {
161*4dc78e53SAndroid Build Coastguard Worker 		*res = TC_H_ROOT;
162*4dc78e53SAndroid Build Coastguard Worker 		return 0;
163*4dc78e53SAndroid Build Coastguard Worker 	}
164*4dc78e53SAndroid Build Coastguard Worker 
165*4dc78e53SAndroid Build Coastguard Worker 	if (!strcasecmp(str, "none")) {
166*4dc78e53SAndroid Build Coastguard Worker 		*res = TC_H_UNSPEC;
167*4dc78e53SAndroid Build Coastguard Worker 		return 0;
168*4dc78e53SAndroid Build Coastguard Worker 	}
169*4dc78e53SAndroid Build Coastguard Worker 
170*4dc78e53SAndroid Build Coastguard Worker 	if (!strcasecmp(str, "ingress")) {
171*4dc78e53SAndroid Build Coastguard Worker 		*res = TC_H_INGRESS;
172*4dc78e53SAndroid Build Coastguard Worker 		return 0;
173*4dc78e53SAndroid Build Coastguard Worker 	}
174*4dc78e53SAndroid Build Coastguard Worker 
175*4dc78e53SAndroid Build Coastguard Worker 	h = strtoul(str, &colon, 16);
176*4dc78e53SAndroid Build Coastguard Worker 
177*4dc78e53SAndroid Build Coastguard Worker 	/* MAJ is not a number */
178*4dc78e53SAndroid Build Coastguard Worker 	if (colon == str) {
179*4dc78e53SAndroid Build Coastguard Worker not_a_number:
180*4dc78e53SAndroid Build Coastguard Worker 		if (*colon == ':') {
181*4dc78e53SAndroid Build Coastguard Worker 			/* :YYYY */
182*4dc78e53SAndroid Build Coastguard Worker 			h = 0;
183*4dc78e53SAndroid Build Coastguard Worker 		} else {
184*4dc78e53SAndroid Build Coastguard Worker 			size_t len;
185*4dc78e53SAndroid Build Coastguard Worker 			char name[64] = { 0 };
186*4dc78e53SAndroid Build Coastguard Worker 
187*4dc78e53SAndroid Build Coastguard Worker 			if (!(colon = strpbrk(str, ":"))) {
188*4dc78e53SAndroid Build Coastguard Worker 				/* NAME */
189*4dc78e53SAndroid Build Coastguard Worker 				return classid_lookup(str, res);
190*4dc78e53SAndroid Build Coastguard Worker 			} else {
191*4dc78e53SAndroid Build Coastguard Worker 				/* NAME:YYYY */
192*4dc78e53SAndroid Build Coastguard Worker 				len = colon - str;
193*4dc78e53SAndroid Build Coastguard Worker 				if (len >= sizeof(name))
194*4dc78e53SAndroid Build Coastguard Worker 					return -NLE_INVAL;
195*4dc78e53SAndroid Build Coastguard Worker 
196*4dc78e53SAndroid Build Coastguard Worker 				memcpy(name, str, len);
197*4dc78e53SAndroid Build Coastguard Worker 
198*4dc78e53SAndroid Build Coastguard Worker 				if ((err = classid_lookup(name, &h)) < 0)
199*4dc78e53SAndroid Build Coastguard Worker 					return err;
200*4dc78e53SAndroid Build Coastguard Worker 
201*4dc78e53SAndroid Build Coastguard Worker 				/* Name must point to a qdisc alias */
202*4dc78e53SAndroid Build Coastguard Worker 				if (TC_H_MIN(h))
203*4dc78e53SAndroid Build Coastguard Worker 					return -NLE_INVAL;
204*4dc78e53SAndroid Build Coastguard Worker 
205*4dc78e53SAndroid Build Coastguard Worker 				/* NAME: is not allowed */
206*4dc78e53SAndroid Build Coastguard Worker 				if (colon[1] == '\0')
207*4dc78e53SAndroid Build Coastguard Worker 					return -NLE_INVAL;
208*4dc78e53SAndroid Build Coastguard Worker 
209*4dc78e53SAndroid Build Coastguard Worker 				goto update;
210*4dc78e53SAndroid Build Coastguard Worker 			}
211*4dc78e53SAndroid Build Coastguard Worker 		}
212*4dc78e53SAndroid Build Coastguard Worker 	}
213*4dc78e53SAndroid Build Coastguard Worker 
214*4dc78e53SAndroid Build Coastguard Worker 	if (':' == *colon) {
215*4dc78e53SAndroid Build Coastguard Worker 		/* check if we would lose bits */
216*4dc78e53SAndroid Build Coastguard Worker 		if (TC_H_MAJ(h))
217*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_RANGE;
218*4dc78e53SAndroid Build Coastguard Worker 		h <<= 16;
219*4dc78e53SAndroid Build Coastguard Worker 
220*4dc78e53SAndroid Build Coastguard Worker 		if ('\0' == colon[1]) {
221*4dc78e53SAndroid Build Coastguard Worker 			/* XXXX: */
222*4dc78e53SAndroid Build Coastguard Worker 			*res = h;
223*4dc78e53SAndroid Build Coastguard Worker 		} else {
224*4dc78e53SAndroid Build Coastguard Worker 			/* XXXX:YYYY */
225*4dc78e53SAndroid Build Coastguard Worker 			uint32_t l;
226*4dc78e53SAndroid Build Coastguard Worker 
227*4dc78e53SAndroid Build Coastguard Worker update:
228*4dc78e53SAndroid Build Coastguard Worker 			l = strtoul(colon+1, &end, 16);
229*4dc78e53SAndroid Build Coastguard Worker 
230*4dc78e53SAndroid Build Coastguard Worker 			/* check if we overlap with major part */
231*4dc78e53SAndroid Build Coastguard Worker 			if (TC_H_MAJ(l))
232*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_RANGE;
233*4dc78e53SAndroid Build Coastguard Worker 
234*4dc78e53SAndroid Build Coastguard Worker 			if ('\0' != *end)
235*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_INVAL;
236*4dc78e53SAndroid Build Coastguard Worker 
237*4dc78e53SAndroid Build Coastguard Worker 			*res = (h | l);
238*4dc78e53SAndroid Build Coastguard Worker 		}
239*4dc78e53SAndroid Build Coastguard Worker 	} else if ('\0' == *colon) {
240*4dc78e53SAndroid Build Coastguard Worker 		/* XXXXYYYY */
241*4dc78e53SAndroid Build Coastguard Worker 		*res = h;
242*4dc78e53SAndroid Build Coastguard Worker 	} else
243*4dc78e53SAndroid Build Coastguard Worker 		goto not_a_number;
244*4dc78e53SAndroid Build Coastguard Worker 
245*4dc78e53SAndroid Build Coastguard Worker 	return 0;
246*4dc78e53SAndroid Build Coastguard Worker }
247*4dc78e53SAndroid Build Coastguard Worker 
free_nothing(void * arg)248*4dc78e53SAndroid Build Coastguard Worker static void free_nothing(void *arg)
249*4dc78e53SAndroid Build Coastguard Worker {
250*4dc78e53SAndroid Build Coastguard Worker }
251*4dc78e53SAndroid Build Coastguard Worker 
classid_map_free(struct classid_map * map)252*4dc78e53SAndroid Build Coastguard Worker static void classid_map_free(struct classid_map *map)
253*4dc78e53SAndroid Build Coastguard Worker {
254*4dc78e53SAndroid Build Coastguard Worker 	if (!map)
255*4dc78e53SAndroid Build Coastguard Worker 		return;
256*4dc78e53SAndroid Build Coastguard Worker 
257*4dc78e53SAndroid Build Coastguard Worker 	free(map->name);
258*4dc78e53SAndroid Build Coastguard Worker 	free(map);
259*4dc78e53SAndroid Build Coastguard Worker }
260*4dc78e53SAndroid Build Coastguard Worker 
clear_hashtable(void)261*4dc78e53SAndroid Build Coastguard Worker static void clear_hashtable(void)
262*4dc78e53SAndroid Build Coastguard Worker {
263*4dc78e53SAndroid Build Coastguard Worker 	int i;
264*4dc78e53SAndroid Build Coastguard Worker 
265*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) {
266*4dc78e53SAndroid Build Coastguard Worker 		struct classid_map *map, *n;
267*4dc78e53SAndroid Build Coastguard Worker 
268*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list)
269*4dc78e53SAndroid Build Coastguard Worker 			classid_map_free(map);
270*4dc78e53SAndroid Build Coastguard Worker 
271*4dc78e53SAndroid Build Coastguard Worker 		nl_init_list_head(&tbl_name[i]);
272*4dc78e53SAndroid Build Coastguard Worker 
273*4dc78e53SAndroid Build Coastguard Worker 	}
274*4dc78e53SAndroid Build Coastguard Worker 
275*4dc78e53SAndroid Build Coastguard Worker 	if (id_root) {
276*4dc78e53SAndroid Build Coastguard Worker 		tdestroy(&id_root, &free_nothing);
277*4dc78e53SAndroid Build Coastguard Worker 		id_root = NULL;
278*4dc78e53SAndroid Build Coastguard Worker 	}
279*4dc78e53SAndroid Build Coastguard Worker }
280*4dc78e53SAndroid Build Coastguard Worker 
classid_map_add(uint32_t classid,const char * name)281*4dc78e53SAndroid Build Coastguard Worker static int classid_map_add(uint32_t classid, const char *name)
282*4dc78e53SAndroid Build Coastguard Worker {
283*4dc78e53SAndroid Build Coastguard Worker 	struct classid_map *map;
284*4dc78e53SAndroid Build Coastguard Worker 	int n;
285*4dc78e53SAndroid Build Coastguard Worker 
286*4dc78e53SAndroid Build Coastguard Worker 	if (!(map = calloc(1, sizeof(*map))))
287*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
288*4dc78e53SAndroid Build Coastguard Worker 
289*4dc78e53SAndroid Build Coastguard Worker 	map->classid = classid;
290*4dc78e53SAndroid Build Coastguard Worker 	map->name = strdup(name);
291*4dc78e53SAndroid Build Coastguard Worker 
292*4dc78e53SAndroid Build Coastguard Worker 	n = classid_tbl_hash(map->name);
293*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&map->name_list, &tbl_name[n]);
294*4dc78e53SAndroid Build Coastguard Worker 
295*4dc78e53SAndroid Build Coastguard Worker 	if (!tsearch((void *) map, &id_root, &compare_id)) {
296*4dc78e53SAndroid Build Coastguard Worker 		classid_map_free(map);
297*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
298*4dc78e53SAndroid Build Coastguard Worker 	}
299*4dc78e53SAndroid Build Coastguard Worker 
300*4dc78e53SAndroid Build Coastguard Worker 	return 0;
301*4dc78e53SAndroid Build Coastguard Worker }
302*4dc78e53SAndroid Build Coastguard Worker 
303*4dc78e53SAndroid Build Coastguard Worker /**
304*4dc78e53SAndroid Build Coastguard Worker  * (Re-)read classid file
305*4dc78e53SAndroid Build Coastguard Worker  *
306*4dc78e53SAndroid Build Coastguard Worker  * Rereads the contents of the classid file (typically found at the location
307*4dc78e53SAndroid Build Coastguard Worker  * /etc/libnl/classid) and refreshes the classid maps.
308*4dc78e53SAndroid Build Coastguard Worker  *
309*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
310*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_tc_read_classid_file(void)311*4dc78e53SAndroid Build Coastguard Worker int rtnl_tc_read_classid_file(void)
312*4dc78e53SAndroid Build Coastguard Worker {
313*4dc78e53SAndroid Build Coastguard Worker 	static time_t last_read;
314*4dc78e53SAndroid Build Coastguard Worker 	struct stat st;
315*4dc78e53SAndroid Build Coastguard Worker 	char buf[256], *path;
316*4dc78e53SAndroid Build Coastguard Worker 	FILE *fd;
317*4dc78e53SAndroid Build Coastguard Worker 	int err;
318*4dc78e53SAndroid Build Coastguard Worker 
319*4dc78e53SAndroid Build Coastguard Worker 	if (build_sysconf_path(&path, "classid") < 0)
320*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
321*4dc78e53SAndroid Build Coastguard Worker 
322*4dc78e53SAndroid Build Coastguard Worker 	/* if stat fails, just (re-)read the file */
323*4dc78e53SAndroid Build Coastguard Worker 	if (stat(path, &st) == 0) {
324*4dc78e53SAndroid Build Coastguard Worker 		/* Don't re-read file if file is unchanged */
325*4dc78e53SAndroid Build Coastguard Worker 		if (last_read == st.st_mtime) {
326*4dc78e53SAndroid Build Coastguard Worker 			err = 0;
327*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
328*4dc78e53SAndroid Build Coastguard Worker 		}
329*4dc78e53SAndroid Build Coastguard Worker 	}
330*4dc78e53SAndroid Build Coastguard Worker 
331*4dc78e53SAndroid Build Coastguard Worker 	if (!(fd = fopen(path, "re"))) {
332*4dc78e53SAndroid Build Coastguard Worker 		err = -nl_syserr2nlerr(errno);
333*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
334*4dc78e53SAndroid Build Coastguard Worker 	}
335*4dc78e53SAndroid Build Coastguard Worker 
336*4dc78e53SAndroid Build Coastguard Worker 	clear_hashtable();
337*4dc78e53SAndroid Build Coastguard Worker 
338*4dc78e53SAndroid Build Coastguard Worker 	while (fgets(buf, sizeof(buf), fd)) {
339*4dc78e53SAndroid Build Coastguard Worker 		uint32_t classid;
340*4dc78e53SAndroid Build Coastguard Worker 		char *ptr, *tok;
341*4dc78e53SAndroid Build Coastguard Worker 
342*4dc78e53SAndroid Build Coastguard Worker 		/* ignore comments and empty lines */
343*4dc78e53SAndroid Build Coastguard Worker 		if (*buf == '#' || *buf == '\n' || *buf == '\r')
344*4dc78e53SAndroid Build Coastguard Worker 			continue;
345*4dc78e53SAndroid Build Coastguard Worker 
346*4dc78e53SAndroid Build Coastguard Worker 		/* token 1 */
347*4dc78e53SAndroid Build Coastguard Worker 		if (!(tok = strtok_r(buf, " \t", &ptr))) {
348*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_INVAL;
349*4dc78e53SAndroid Build Coastguard Worker 			goto errout_close;
350*4dc78e53SAndroid Build Coastguard Worker 		}
351*4dc78e53SAndroid Build Coastguard Worker 
352*4dc78e53SAndroid Build Coastguard Worker 		if ((err = rtnl_tc_str2handle(tok, &classid)) < 0)
353*4dc78e53SAndroid Build Coastguard Worker 			goto errout_close;
354*4dc78e53SAndroid Build Coastguard Worker 
355*4dc78e53SAndroid Build Coastguard Worker 		if (!(tok = strtok_r(NULL, " \t\n\r#", &ptr))) {
356*4dc78e53SAndroid Build Coastguard Worker 			err = -NLE_INVAL;
357*4dc78e53SAndroid Build Coastguard Worker 			goto errout_close;
358*4dc78e53SAndroid Build Coastguard Worker 		}
359*4dc78e53SAndroid Build Coastguard Worker 
360*4dc78e53SAndroid Build Coastguard Worker 		if ((err = classid_map_add(classid, tok)) < 0)
361*4dc78e53SAndroid Build Coastguard Worker 			goto errout_close;
362*4dc78e53SAndroid Build Coastguard Worker 	}
363*4dc78e53SAndroid Build Coastguard Worker 
364*4dc78e53SAndroid Build Coastguard Worker 	err = 0;
365*4dc78e53SAndroid Build Coastguard Worker 	last_read = st.st_mtime;
366*4dc78e53SAndroid Build Coastguard Worker 
367*4dc78e53SAndroid Build Coastguard Worker errout_close:
368*4dc78e53SAndroid Build Coastguard Worker 	fclose(fd);
369*4dc78e53SAndroid Build Coastguard Worker errout:
370*4dc78e53SAndroid Build Coastguard Worker 	free(path);
371*4dc78e53SAndroid Build Coastguard Worker 
372*4dc78e53SAndroid Build Coastguard Worker 	return err;
373*4dc78e53SAndroid Build Coastguard Worker 
374*4dc78e53SAndroid Build Coastguard Worker }
375*4dc78e53SAndroid Build Coastguard Worker 
rtnl_classid_generate(const char * name,uint32_t * result,uint32_t parent)376*4dc78e53SAndroid Build Coastguard Worker int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent)
377*4dc78e53SAndroid Build Coastguard Worker {
378*4dc78e53SAndroid Build Coastguard Worker 	static uint32_t base = 0x4000 << 16;
379*4dc78e53SAndroid Build Coastguard Worker 	uint32_t classid;
380*4dc78e53SAndroid Build Coastguard Worker 	char *path;
381*4dc78e53SAndroid Build Coastguard Worker 	FILE *fd;
382*4dc78e53SAndroid Build Coastguard Worker 	int err = 0;
383*4dc78e53SAndroid Build Coastguard Worker 
384*4dc78e53SAndroid Build Coastguard Worker 	if (parent == TC_H_ROOT || parent == TC_H_INGRESS) {
385*4dc78e53SAndroid Build Coastguard Worker 		do {
386*4dc78e53SAndroid Build Coastguard Worker 			base += (1 << 16);
387*4dc78e53SAndroid Build Coastguard Worker 			if (base == TC_H_MAJ(TC_H_ROOT))
388*4dc78e53SAndroid Build Coastguard Worker 				base = 0x4000 << 16;
389*4dc78e53SAndroid Build Coastguard Worker 		} while (name_lookup(base));
390*4dc78e53SAndroid Build Coastguard Worker 
391*4dc78e53SAndroid Build Coastguard Worker 		classid = base;
392*4dc78e53SAndroid Build Coastguard Worker 	} else {
393*4dc78e53SAndroid Build Coastguard Worker 		classid = TC_H_MAJ(parent);
394*4dc78e53SAndroid Build Coastguard Worker 		do {
395*4dc78e53SAndroid Build Coastguard Worker 			if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT))
396*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_RANGE;
397*4dc78e53SAndroid Build Coastguard Worker 		} while (name_lookup(classid));
398*4dc78e53SAndroid Build Coastguard Worker 	}
399*4dc78e53SAndroid Build Coastguard Worker 
400*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Generated new classid %#x\n", classid);
401*4dc78e53SAndroid Build Coastguard Worker 
402*4dc78e53SAndroid Build Coastguard Worker 	if (build_sysconf_path(&path, "classid") < 0)
403*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
404*4dc78e53SAndroid Build Coastguard Worker 
405*4dc78e53SAndroid Build Coastguard Worker 	if (!(fd = fopen(path, "ae"))) {
406*4dc78e53SAndroid Build Coastguard Worker 		err = -nl_syserr2nlerr(errno);
407*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
408*4dc78e53SAndroid Build Coastguard Worker 	}
409*4dc78e53SAndroid Build Coastguard Worker 
410*4dc78e53SAndroid Build Coastguard Worker 	fprintf(fd, "%x:", TC_H_MAJ(classid) >> 16);
411*4dc78e53SAndroid Build Coastguard Worker 	if (TC_H_MIN(classid))
412*4dc78e53SAndroid Build Coastguard Worker 		fprintf(fd, "%x", TC_H_MIN(classid));
413*4dc78e53SAndroid Build Coastguard Worker 	fprintf(fd, "\t\t\t%s\n", name);
414*4dc78e53SAndroid Build Coastguard Worker 
415*4dc78e53SAndroid Build Coastguard Worker 	fclose(fd);
416*4dc78e53SAndroid Build Coastguard Worker 
417*4dc78e53SAndroid Build Coastguard Worker 	if (classid_map_add(classid, name) < 0) {
418*4dc78e53SAndroid Build Coastguard Worker 		/*
419*4dc78e53SAndroid Build Coastguard Worker 		 * Error adding classid map, re-read classid file is best
420*4dc78e53SAndroid Build Coastguard Worker 		 * option here. It is likely to fail as well but better
421*4dc78e53SAndroid Build Coastguard Worker 		 * than nothing, entry was added to the file already anyway.
422*4dc78e53SAndroid Build Coastguard Worker 		 */
423*4dc78e53SAndroid Build Coastguard Worker 		rtnl_tc_read_classid_file();
424*4dc78e53SAndroid Build Coastguard Worker 	}
425*4dc78e53SAndroid Build Coastguard Worker 
426*4dc78e53SAndroid Build Coastguard Worker 	*result = classid;
427*4dc78e53SAndroid Build Coastguard Worker 	err = 0;
428*4dc78e53SAndroid Build Coastguard Worker errout:
429*4dc78e53SAndroid Build Coastguard Worker 	free(path);
430*4dc78e53SAndroid Build Coastguard Worker 
431*4dc78e53SAndroid Build Coastguard Worker 	return err;
432*4dc78e53SAndroid Build Coastguard Worker }
433*4dc78e53SAndroid Build Coastguard Worker 
434*4dc78e53SAndroid Build Coastguard Worker /** @} */
435*4dc78e53SAndroid Build Coastguard Worker 
classid_init(void)436*4dc78e53SAndroid Build Coastguard Worker static void _nl_init classid_init(void)
437*4dc78e53SAndroid Build Coastguard Worker {
438*4dc78e53SAndroid Build Coastguard Worker 	int err, i;
439*4dc78e53SAndroid Build Coastguard Worker 
440*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
441*4dc78e53SAndroid Build Coastguard Worker 		nl_init_list_head(&tbl_name[i]);
442*4dc78e53SAndroid Build Coastguard Worker 
443*4dc78e53SAndroid Build Coastguard Worker 	if ((err = rtnl_tc_read_classid_file()) < 0)
444*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(1, "Failed to read classid file: %s\n", nl_geterror(err));
445*4dc78e53SAndroid Build Coastguard Worker }
446*4dc78e53SAndroid Build Coastguard Worker 
free_map(void * map)447*4dc78e53SAndroid Build Coastguard Worker static void free_map(void *map)
448*4dc78e53SAndroid Build Coastguard Worker {
449*4dc78e53SAndroid Build Coastguard Worker 	free(((struct classid_map *)map)->name);
450*4dc78e53SAndroid Build Coastguard Worker 	free(map);
451*4dc78e53SAndroid Build Coastguard Worker }
452*4dc78e53SAndroid Build Coastguard Worker 
classid_exit(void)453*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit classid_exit(void)
454*4dc78e53SAndroid Build Coastguard Worker {
455*4dc78e53SAndroid Build Coastguard Worker 	tdestroy(id_root, free_map);
456*4dc78e53SAndroid Build Coastguard Worker }
457*4dc78e53SAndroid Build Coastguard Worker /** @} */
458