xref: /aosp_15_r20/external/libnl/lib/route/pktloc.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) 2008-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 pktloc Packet Location Aliasing
9*4dc78e53SAndroid Build Coastguard Worker  * Packet Location Aliasing
10*4dc78e53SAndroid Build Coastguard Worker  *
11*4dc78e53SAndroid Build Coastguard Worker  * The packet location aliasing interface eases the use of offset definitions
12*4dc78e53SAndroid Build Coastguard Worker  * inside packets by allowing them to be referenced by name. Known positions
13*4dc78e53SAndroid Build Coastguard Worker  * of protocol fields are stored in a configuration file and associated with
14*4dc78e53SAndroid Build Coastguard Worker  * a name for later reference. The configuration file is distributed with the
15*4dc78e53SAndroid Build Coastguard Worker  * library and provides a well defined set of definitions for most common
16*4dc78e53SAndroid Build Coastguard Worker  * protocol fields.
17*4dc78e53SAndroid Build Coastguard Worker  *
18*4dc78e53SAndroid Build Coastguard Worker  * @section pktloc_examples Examples
19*4dc78e53SAndroid Build Coastguard Worker  * @par Example 1.1 Looking up a packet location
20*4dc78e53SAndroid Build Coastguard Worker  * @code
21*4dc78e53SAndroid Build Coastguard Worker  * struct rtnl_pktloc *loc;
22*4dc78e53SAndroid Build Coastguard Worker  *
23*4dc78e53SAndroid Build Coastguard Worker  * rtnl_pktloc_lookup("ip.src", &loc);
24*4dc78e53SAndroid Build Coastguard Worker  * @endcode
25*4dc78e53SAndroid Build Coastguard Worker  * @{
26*4dc78e53SAndroid Build Coastguard Worker  */
27*4dc78e53SAndroid Build Coastguard Worker 
28*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
29*4dc78e53SAndroid Build Coastguard Worker 
30*4dc78e53SAndroid Build Coastguard Worker #include <sys/stat.h>
31*4dc78e53SAndroid Build Coastguard Worker 
32*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
33*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
34*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/pktloc.h>
35*4dc78e53SAndroid Build Coastguard Worker 
36*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
37*4dc78e53SAndroid Build Coastguard Worker 
38*4dc78e53SAndroid Build Coastguard Worker #include "pktloc_syntax.h"
39*4dc78e53SAndroid Build Coastguard Worker #include "pktloc_grammar.h"
40*4dc78e53SAndroid Build Coastguard Worker 
41*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
42*4dc78e53SAndroid Build Coastguard Worker #define PKTLOC_NAME_HT_SIZ 256
43*4dc78e53SAndroid Build Coastguard Worker 
44*4dc78e53SAndroid Build Coastguard Worker static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
45*4dc78e53SAndroid Build Coastguard Worker 
46*4dc78e53SAndroid Build Coastguard Worker /* djb2 */
pktloc_hash(const char * str)47*4dc78e53SAndroid Build Coastguard Worker static unsigned int pktloc_hash(const char *str)
48*4dc78e53SAndroid Build Coastguard Worker {
49*4dc78e53SAndroid Build Coastguard Worker 	unsigned long hash = 5381;
50*4dc78e53SAndroid Build Coastguard Worker 	int c;
51*4dc78e53SAndroid Build Coastguard Worker 
52*4dc78e53SAndroid Build Coastguard Worker 	while ((c = *str++))
53*4dc78e53SAndroid Build Coastguard Worker 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
54*4dc78e53SAndroid Build Coastguard Worker 
55*4dc78e53SAndroid Build Coastguard Worker 	return hash % PKTLOC_NAME_HT_SIZ;
56*4dc78e53SAndroid Build Coastguard Worker }
57*4dc78e53SAndroid Build Coastguard Worker 
__pktloc_lookup(const char * name,struct rtnl_pktloc ** result)58*4dc78e53SAndroid Build Coastguard Worker static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result)
59*4dc78e53SAndroid Build Coastguard Worker {
60*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_pktloc *loc;
61*4dc78e53SAndroid Build Coastguard Worker 	int hash;
62*4dc78e53SAndroid Build Coastguard Worker 
63*4dc78e53SAndroid Build Coastguard Worker 	hash = pktloc_hash(name);
64*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
65*4dc78e53SAndroid Build Coastguard Worker 		if (!strcasecmp(loc->name, name)) {
66*4dc78e53SAndroid Build Coastguard Worker 			loc->refcnt++;
67*4dc78e53SAndroid Build Coastguard Worker 			*result = loc;
68*4dc78e53SAndroid Build Coastguard Worker 			return 0;
69*4dc78e53SAndroid Build Coastguard Worker 		}
70*4dc78e53SAndroid Build Coastguard Worker 	}
71*4dc78e53SAndroid Build Coastguard Worker 
72*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_OBJ_NOTFOUND;
73*4dc78e53SAndroid Build Coastguard Worker }
74*4dc78e53SAndroid Build Coastguard Worker 
75*4dc78e53SAndroid Build Coastguard Worker extern int pktloc_parse(void *scanner);
76*4dc78e53SAndroid Build Coastguard Worker 
rtnl_pktloc_free(struct rtnl_pktloc * loc)77*4dc78e53SAndroid Build Coastguard Worker static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
78*4dc78e53SAndroid Build Coastguard Worker {
79*4dc78e53SAndroid Build Coastguard Worker 	if (!loc)
80*4dc78e53SAndroid Build Coastguard Worker 		return;
81*4dc78e53SAndroid Build Coastguard Worker 
82*4dc78e53SAndroid Build Coastguard Worker 	free(loc->name);
83*4dc78e53SAndroid Build Coastguard Worker 	free(loc);
84*4dc78e53SAndroid Build Coastguard Worker }
85*4dc78e53SAndroid Build Coastguard Worker 
read_pktlocs(void)86*4dc78e53SAndroid Build Coastguard Worker static int read_pktlocs(void)
87*4dc78e53SAndroid Build Coastguard Worker {
88*4dc78e53SAndroid Build Coastguard Worker 	YY_BUFFER_STATE buf = NULL;
89*4dc78e53SAndroid Build Coastguard Worker 	yyscan_t scanner = NULL;
90*4dc78e53SAndroid Build Coastguard Worker 	static time_t last_read;
91*4dc78e53SAndroid Build Coastguard Worker 	struct stat st;
92*4dc78e53SAndroid Build Coastguard Worker 	char *path;
93*4dc78e53SAndroid Build Coastguard Worker 	int i, err;
94*4dc78e53SAndroid Build Coastguard Worker 	FILE *fd;
95*4dc78e53SAndroid Build Coastguard Worker 
96*4dc78e53SAndroid Build Coastguard Worker 	if (build_sysconf_path(&path, "pktloc") < 0)
97*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
98*4dc78e53SAndroid Build Coastguard Worker 
99*4dc78e53SAndroid Build Coastguard Worker 	/* if stat fails, just try to read the file */
100*4dc78e53SAndroid Build Coastguard Worker 	if (stat(path, &st) == 0) {
101*4dc78e53SAndroid Build Coastguard Worker 		/* Don't re-read file if file is unchanged */
102*4dc78e53SAndroid Build Coastguard Worker 		if (last_read == st.st_mtime) {
103*4dc78e53SAndroid Build Coastguard Worker 			err = 0;
104*4dc78e53SAndroid Build Coastguard Worker 			goto errout;
105*4dc78e53SAndroid Build Coastguard Worker 		}
106*4dc78e53SAndroid Build Coastguard Worker 	}
107*4dc78e53SAndroid Build Coastguard Worker 
108*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "Reading packet location file \"%s\"\n", path);
109*4dc78e53SAndroid Build Coastguard Worker 
110*4dc78e53SAndroid Build Coastguard Worker 	if (!(fd = fopen(path, "re"))) {
111*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_PKTLOC_FILE;
112*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
113*4dc78e53SAndroid Build Coastguard Worker 	}
114*4dc78e53SAndroid Build Coastguard Worker 
115*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
116*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_pktloc *loc, *n;
117*4dc78e53SAndroid Build Coastguard Worker 
118*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
119*4dc78e53SAndroid Build Coastguard Worker 			rtnl_pktloc_put(loc);
120*4dc78e53SAndroid Build Coastguard Worker 
121*4dc78e53SAndroid Build Coastguard Worker 		nl_init_list_head(&pktloc_name_ht[i]);
122*4dc78e53SAndroid Build Coastguard Worker 	}
123*4dc78e53SAndroid Build Coastguard Worker 
124*4dc78e53SAndroid Build Coastguard Worker 	if (pktloc_lex_init(&scanner) < 0) {
125*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_FAILURE;
126*4dc78e53SAndroid Build Coastguard Worker 		goto errout_close;
127*4dc78e53SAndroid Build Coastguard Worker 	}
128*4dc78e53SAndroid Build Coastguard Worker 
129*4dc78e53SAndroid Build Coastguard Worker 	buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
130*4dc78e53SAndroid Build Coastguard Worker 	pktloc__switch_to_buffer(buf, scanner);
131*4dc78e53SAndroid Build Coastguard Worker 
132*4dc78e53SAndroid Build Coastguard Worker 	if ((err = pktloc_parse(scanner)) != 0) {
133*4dc78e53SAndroid Build Coastguard Worker 		pktloc__delete_buffer(buf, scanner);
134*4dc78e53SAndroid Build Coastguard Worker 		err = -NLE_PARSE_ERR;
135*4dc78e53SAndroid Build Coastguard Worker 		goto errout_scanner;
136*4dc78e53SAndroid Build Coastguard Worker 	}
137*4dc78e53SAndroid Build Coastguard Worker 
138*4dc78e53SAndroid Build Coastguard Worker 	last_read = st.st_mtime;
139*4dc78e53SAndroid Build Coastguard Worker 
140*4dc78e53SAndroid Build Coastguard Worker errout_scanner:
141*4dc78e53SAndroid Build Coastguard Worker 	pktloc_lex_destroy(scanner);
142*4dc78e53SAndroid Build Coastguard Worker errout_close:
143*4dc78e53SAndroid Build Coastguard Worker 	fclose(fd);
144*4dc78e53SAndroid Build Coastguard Worker errout:
145*4dc78e53SAndroid Build Coastguard Worker 	free(path);
146*4dc78e53SAndroid Build Coastguard Worker 
147*4dc78e53SAndroid Build Coastguard Worker 	return err;
148*4dc78e53SAndroid Build Coastguard Worker }
149*4dc78e53SAndroid Build Coastguard Worker 
150*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
151*4dc78e53SAndroid Build Coastguard Worker 
152*4dc78e53SAndroid Build Coastguard Worker /**
153*4dc78e53SAndroid Build Coastguard Worker  * Lookup packet location alias
154*4dc78e53SAndroid Build Coastguard Worker  * @arg name		Name of packet location.
155*4dc78e53SAndroid Build Coastguard Worker  * @arg result		Result pointer
156*4dc78e53SAndroid Build Coastguard Worker  *
157*4dc78e53SAndroid Build Coastguard Worker  * Tries to find a matching packet location alias for the supplied
158*4dc78e53SAndroid Build Coastguard Worker  * packet location name.
159*4dc78e53SAndroid Build Coastguard Worker  *
160*4dc78e53SAndroid Build Coastguard Worker  * The file containing the packet location definitions is automatically
161*4dc78e53SAndroid Build Coastguard Worker  * re-read if its modification time has changed since the last call.
162*4dc78e53SAndroid Build Coastguard Worker  *
163*4dc78e53SAndroid Build Coastguard Worker  * The returned packet location has to be returned after use by calling
164*4dc78e53SAndroid Build Coastguard Worker  * rtnl_pktloc_put() in order to allow freeing its memory after the last
165*4dc78e53SAndroid Build Coastguard Worker  * user has abandoned it.
166*4dc78e53SAndroid Build Coastguard Worker  *
167*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
168*4dc78e53SAndroid Build Coastguard Worker  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
169*4dc78e53SAndroid Build Coastguard Worker  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
170*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_pktloc_lookup(const char * name,struct rtnl_pktloc ** result)171*4dc78e53SAndroid Build Coastguard Worker int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
172*4dc78e53SAndroid Build Coastguard Worker {
173*4dc78e53SAndroid Build Coastguard Worker 	int err;
174*4dc78e53SAndroid Build Coastguard Worker 
175*4dc78e53SAndroid Build Coastguard Worker 	if ((err = read_pktlocs()) < 0)
176*4dc78e53SAndroid Build Coastguard Worker 		return err;
177*4dc78e53SAndroid Build Coastguard Worker 
178*4dc78e53SAndroid Build Coastguard Worker 	return __pktloc_lookup(name, result);
179*4dc78e53SAndroid Build Coastguard Worker }
180*4dc78e53SAndroid Build Coastguard Worker 
181*4dc78e53SAndroid Build Coastguard Worker /**
182*4dc78e53SAndroid Build Coastguard Worker  * Allocate packet location object
183*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_pktloc_alloc(void)184*4dc78e53SAndroid Build Coastguard Worker struct rtnl_pktloc *rtnl_pktloc_alloc(void)
185*4dc78e53SAndroid Build Coastguard Worker {
186*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_pktloc *loc;
187*4dc78e53SAndroid Build Coastguard Worker 
188*4dc78e53SAndroid Build Coastguard Worker 	if (!(loc = calloc(1, sizeof(*loc))))
189*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
190*4dc78e53SAndroid Build Coastguard Worker 
191*4dc78e53SAndroid Build Coastguard Worker 	loc->refcnt = 1;
192*4dc78e53SAndroid Build Coastguard Worker 	nl_init_list_head(&loc->list);
193*4dc78e53SAndroid Build Coastguard Worker 
194*4dc78e53SAndroid Build Coastguard Worker 	return loc;
195*4dc78e53SAndroid Build Coastguard Worker }
196*4dc78e53SAndroid Build Coastguard Worker 
197*4dc78e53SAndroid Build Coastguard Worker /**
198*4dc78e53SAndroid Build Coastguard Worker  * Return reference of a packet location
199*4dc78e53SAndroid Build Coastguard Worker  * @arg loc		packet location object.
200*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_pktloc_put(struct rtnl_pktloc * loc)201*4dc78e53SAndroid Build Coastguard Worker void rtnl_pktloc_put(struct rtnl_pktloc *loc)
202*4dc78e53SAndroid Build Coastguard Worker {
203*4dc78e53SAndroid Build Coastguard Worker 	if (!loc)
204*4dc78e53SAndroid Build Coastguard Worker 		return;
205*4dc78e53SAndroid Build Coastguard Worker 
206*4dc78e53SAndroid Build Coastguard Worker 	loc->refcnt--;
207*4dc78e53SAndroid Build Coastguard Worker 	if (loc->refcnt <= 0)
208*4dc78e53SAndroid Build Coastguard Worker 		rtnl_pktloc_free(loc);
209*4dc78e53SAndroid Build Coastguard Worker }
210*4dc78e53SAndroid Build Coastguard Worker 
211*4dc78e53SAndroid Build Coastguard Worker /**
212*4dc78e53SAndroid Build Coastguard Worker  * Add a packet location to the hash table
213*4dc78e53SAndroid Build Coastguard Worker  * @arg loc		packet location object
214*4dc78e53SAndroid Build Coastguard Worker  *
215*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
216*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_pktloc_add(struct rtnl_pktloc * loc)217*4dc78e53SAndroid Build Coastguard Worker int rtnl_pktloc_add(struct rtnl_pktloc *loc)
218*4dc78e53SAndroid Build Coastguard Worker {
219*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_pktloc *l;
220*4dc78e53SAndroid Build Coastguard Worker 
221*4dc78e53SAndroid Build Coastguard Worker 	if (__pktloc_lookup(loc->name, &l) == 0) {
222*4dc78e53SAndroid Build Coastguard Worker 		rtnl_pktloc_put(l);
223*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_EXIST;
224*4dc78e53SAndroid Build Coastguard Worker 	}
225*4dc78e53SAndroid Build Coastguard Worker 
226*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u "
227*4dc78e53SAndroid Build Coastguard Worker 		  "offset=%u mask=%#x shift=%u refnt=%u\n",
228*4dc78e53SAndroid Build Coastguard Worker 		  loc->name, loc->align, loc->layer, loc->offset,
229*4dc78e53SAndroid Build Coastguard Worker 		  loc->mask, loc->shift, loc->refcnt);
230*4dc78e53SAndroid Build Coastguard Worker 
231*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
232*4dc78e53SAndroid Build Coastguard Worker 
233*4dc78e53SAndroid Build Coastguard Worker 	return 0;
234*4dc78e53SAndroid Build Coastguard Worker }
235*4dc78e53SAndroid Build Coastguard Worker 
rtnl_pktloc_foreach(void (* cb)(struct rtnl_pktloc *,void *),void * arg)236*4dc78e53SAndroid Build Coastguard Worker void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg)
237*4dc78e53SAndroid Build Coastguard Worker {
238*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_pktloc *loc;
239*4dc78e53SAndroid Build Coastguard Worker 	int i;
240*4dc78e53SAndroid Build Coastguard Worker 
241*4dc78e53SAndroid Build Coastguard Worker 	/* ignore errors */
242*4dc78e53SAndroid Build Coastguard Worker 	read_pktlocs();
243*4dc78e53SAndroid Build Coastguard Worker 
244*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
245*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(loc, &pktloc_name_ht[i], list)
246*4dc78e53SAndroid Build Coastguard Worker 			cb(loc, arg);
247*4dc78e53SAndroid Build Coastguard Worker }
248*4dc78e53SAndroid Build Coastguard Worker 
pktloc_init(void)249*4dc78e53SAndroid Build Coastguard Worker static int _nl_init pktloc_init(void)
250*4dc78e53SAndroid Build Coastguard Worker {
251*4dc78e53SAndroid Build Coastguard Worker 	int i;
252*4dc78e53SAndroid Build Coastguard Worker 
253*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
254*4dc78e53SAndroid Build Coastguard Worker 		nl_init_list_head(&pktloc_name_ht[i]);
255*4dc78e53SAndroid Build Coastguard Worker 
256*4dc78e53SAndroid Build Coastguard Worker 	return 0;
257*4dc78e53SAndroid Build Coastguard Worker }
258*4dc78e53SAndroid Build Coastguard Worker 
259*4dc78e53SAndroid Build Coastguard Worker /** @} */
260