Fix incorrect license header
[platform/upstream/libnl2.git] / lib / route / pktloc.c
1 /*
2  * lib/route/pktloc.c     Packet Location Aliasing
3  *
4  *      This library is free software; you can redistribute it and/or
5  *      modify it under the terms of the GNU Lesser General Public
6  *      License as published by the Free Software Foundation version 2.1
7  *      of the License.
8  *
9  * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
10  */
11
12 /**
13  * @ingroup tc
14  * @defgroup pktloc Packet Location Aliasing
15  * Packet Location Aliasing
16  *
17  * The packet location aliasing interface eases the use of offset definitions
18  * inside packets by allowing them to be referenced by name. Known positions
19  * of protocol fields are stored in a configuration file and associated with
20  * a name for later reference. The configuration file is distributed with the
21  * library and provides a well defined set of definitions for most common
22  * protocol fields.
23  *
24  * @subsection pktloc_examples Examples
25  * @par Example 1.1 Looking up a packet location
26  * @code
27  * struct rtnl_pktloc *loc;
28  *
29  * rtnl_pktloc_lookup("ip.src", &loc);
30  * @endcode
31  * @{
32  */
33
34 #include <netlink-local.h>
35 #include <netlink-tc.h>
36 #include <netlink/netlink.h>
37 #include <netlink/utils.h>
38 #include <netlink/route/pktloc.h>
39
40 #include "pktloc_syntax.h"
41 #include "pktloc_grammar.h"
42
43 /** @cond */
44 #define PKTLOC_NAME_HT_SIZ 256
45
46 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
47
48 /* djb2 */
49 unsigned int pktloc_hash(const char *str)
50 {
51         unsigned long hash = 5381;
52         int c;
53
54         while ((c = *str++))
55                 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
56
57         return hash % PKTLOC_NAME_HT_SIZ;
58 }
59
60
61 void rtnl_pktloc_add(struct rtnl_pktloc *loc)
62 {
63         nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
64 }
65
66 extern int pktloc_parse(void *scanner);
67
68 /** @endcond */
69
70 static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
71 {
72         if (!loc)
73                 return;
74
75         free(loc->name);
76         free(loc);
77 }
78
79 static int read_pktlocs(void)
80 {
81         YY_BUFFER_STATE buf;
82         yyscan_t scanner = NULL;
83         static time_t last_read;
84         struct stat st = {0};
85         char *path;
86         int i, err;
87         FILE *fd;
88
89         asprintf(&path, "%s/pktloc", SYSCONFDIR);
90
91         /* if stat fails, just try to read the file */
92         if (stat(path, &st) == 0) {
93                 /* Don't re-read file if file is unchanged */
94                 if (last_read == st.st_mtime) {
95                         err = 0;
96                         goto errout;
97                 }
98         }
99
100         if (!(fd = fopen(path, "r"))) {
101                 err = -NLE_PKTLOC_FILE;
102                 goto errout;
103         }
104
105         for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
106                 struct rtnl_pktloc *loc, *n;
107
108                 nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
109                         rtnl_pktloc_free(loc);
110
111                 nl_init_list_head(&pktloc_name_ht[i]);
112         }
113
114         if ((err = pktloc_lex_init(&scanner)) < 0) {
115                 err = -NLE_FAILURE;
116                 goto errout_close;
117         }
118
119         buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
120         pktloc__switch_to_buffer(buf, scanner);
121
122         if ((err = pktloc_parse(scanner)) < 0) {
123                 err = -NLE_FAILURE;
124                 goto errout_scanner;
125         }
126
127         last_read = st.st_mtime;
128
129 errout_scanner:
130         if (scanner)
131                 pktloc_lex_destroy(scanner);
132 errout_close:
133         fclose(fd);
134 errout:
135         free(path);
136
137         return err;
138 }
139
140 /**
141  * Lookup packet location alias
142  * @arg name            Name of packet location.
143  *
144  * Tries to find a matching packet location alias for the supplied
145  * packet location name.
146  *
147  * The file containing the packet location definitions is automatically
148  * re-read if its modification time has changed since the last call.
149  *
150  * @return 0 on success or a negative error code.
151  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
152  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
153  */
154 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
155 {
156         struct rtnl_pktloc *loc;
157         int hash, err;
158
159         if ((err = read_pktlocs()) < 0)
160                 return err;
161
162         hash = pktloc_hash(name);
163         nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
164                 if (!strcasecmp(loc->name, name)) {
165                         *result = loc;
166                         return 0;
167                 }
168         }
169
170         return -NLE_OBJ_NOTFOUND;
171 }
172
173 static int __init pktloc_init(void)
174 {
175         int i;
176
177         for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
178                 nl_init_list_head(&pktloc_name_ht[i]);
179
180         return 0;
181 }