]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/ports.c
ports: Refactor enumerating ports
[people/ms/network.git] / src / networkd / ports.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <dirent.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/queue.h>
25 #include <sys/stat.h>
26
27 #include "logging.h"
28 #include "port.h"
29 #include "ports.h"
30 #include "string.h"
31 #include "util.h"
32
33 struct nw_ports_entry {
34 nw_port* port;
35
36 // Link to the other entries
37 STAILQ_ENTRY(nw_ports_entry) nodes;
38 };
39
40 struct nw_ports {
41 nw_daemon* daemon;
42 int nrefs;
43
44 // Port Entries
45 STAILQ_HEAD(entries, nw_ports_entry) entries;
46
47 // A counter of the port entries
48 unsigned int num;
49 };
50
51 int nw_ports_create(nw_ports** ports, nw_daemon* daemon) {
52 nw_ports* p = calloc(1, sizeof(*p));
53 if (!p)
54 return 1;
55
56 // Store a reference to the daemon
57 p->daemon = nw_daemon_ref(daemon);
58
59 // Initialize the reference counter
60 p->nrefs = 1;
61
62 // Initialize entries
63 STAILQ_INIT(&p->entries);
64
65 // Reference the pointer
66 *ports = p;
67
68 return 0;
69 }
70
71 static void nw_ports_free(nw_ports* ports) {
72 struct nw_ports_entry* entry = NULL;
73
74 while (!STAILQ_EMPTY(&ports->entries)) {
75 entry = STAILQ_FIRST(&ports->entries);
76
77 // Dereference the port
78 nw_port_unref(entry->port);
79
80 // Remove the entry from the list
81 STAILQ_REMOVE_HEAD(&ports->entries, nodes);
82
83 // Free the entry
84 free(entry);
85 }
86 }
87
88 nw_ports* nw_ports_ref(nw_ports* ports) {
89 ports->nrefs++;
90
91 return ports;
92 }
93
94 nw_ports* nw_ports_unref(nw_ports* ports) {
95 if (--ports->nrefs > 0)
96 return ports;
97
98 nw_ports_free(ports);
99 return NULL;
100 }
101
102 int nw_ports_save(nw_ports* ports) {
103 struct nw_ports_entry* entry = NULL;
104 int r;
105
106 STAILQ_FOREACH(entry, &ports->entries, nodes) {
107 r = nw_port_save(entry->port);
108 if (r)
109 return r;
110 }
111
112 return 0;
113 }
114
115 static int nw_ports_add_port(nw_ports* ports, nw_port* port) {
116 // Allocate a new entry
117 struct nw_ports_entry* entry = calloc(1, sizeof(*entry));
118 if (!entry)
119 return 1;
120
121 // Reference the port
122 entry->port = nw_port_ref(port);
123
124 // Add it to the list
125 STAILQ_INSERT_TAIL(&ports->entries, entry, nodes);
126
127 // Increment the counter
128 ports->num++;
129
130 return 0;
131 }
132
133 static int nw_ports_enumerate_port(nw_ports* ports, const char* name) {
134 nw_port* port = NULL;
135 int r;
136
137 // Create a new port
138 r = nw_port_open(&port, ports->daemon, name);
139 if (r < 0 || r == 1)
140 goto ERROR;
141
142 // Add the port to the list
143 r = nw_ports_add_port(ports, port);
144 if (r)
145 goto ERROR;
146
147 ERROR:
148 if (port)
149 nw_port_unref(port);
150
151 return r;
152 }
153
154 int nw_ports_enumerate(nw_ports* ports) {
155 DIR* d = NULL;
156 struct dirent* entry = NULL;
157 int r;
158
159 // Open the ports directory
160 d = nw_daemon_config_opendir(ports->daemon, "ports");
161 if (!d) {
162 switch (errno) {
163 case ENOENT:
164 return 0;
165
166 default:
167 return -errno;
168 }
169 }
170
171 for (;;) {
172 // Read the next entry
173 entry = readdir(d);
174 if (!entry)
175 break;
176
177 // Skip anything that is not a regular file
178 if (entry->d_type != DT_REG)
179 continue;
180
181 // Skip hidden files
182 if (entry->d_name[0] == '.')
183 continue;
184
185 // Enumerate the port
186 r = nw_ports_enumerate_port(ports, entry->d_name);
187 if (r < 0)
188 goto ERROR;
189 }
190
191 ERROR:
192 if (d)
193 closedir(d);
194
195 return r;
196 }
197
198 nw_port* nw_ports_get_by_name(nw_ports* ports, const char* name) {
199 struct nw_ports_entry* entry = NULL;
200
201 STAILQ_FOREACH(entry, &ports->entries, nodes) {
202 const char* __name = nw_port_name(entry->port);
203
204 // If the name matches, return a reference to the zone
205 if (strcmp(name, __name) == 0)
206 return nw_port_ref(entry->port);
207 }
208
209 // No match found
210 return NULL;
211 }
212
213 int nw_ports_bus_paths(nw_ports* ports, char*** paths) {
214 struct nw_ports_entry* entry = NULL;
215 char* path = NULL;
216
217 // Allocate an array for all paths
218 char** p = calloc(ports->num + 1, sizeof(*p));
219 if (!p)
220 return 1;
221
222 unsigned int i = 0;
223
224 // Walk through all ports
225 STAILQ_FOREACH(entry, &ports->entries, nodes) {
226 // Generate the bus path
227 path = nw_port_bus_path(entry->port);
228 if (!path)
229 goto ERROR;
230
231 // Append the bus path to the array
232 p[i++] = path;
233 }
234
235 // Return pointer
236 *paths = p;
237
238 return 0;
239
240 ERROR:
241 if (p) {
242 for (char** e = p; *e; e++)
243 free(*e);
244 free(p);
245 }
246
247 return 1;
248 }
249
250 int nw_ports_walk(nw_ports* ports, nw_ports_walk_callback callback, void* data) {
251 struct nw_ports_entry* entry = NULL;
252 int r;
253
254 STAILQ_FOREACH(entry, &ports->entries, nodes) {
255 r = callback(ports->daemon, entry->port, data);
256 if (r)
257 return r;
258 }
259
260 return 0;
261 }
262
263 static int __nw_ports_reconfigure(nw_daemon* daemon, nw_port* port, void* data) {
264 return nw_port_reconfigure(port);
265 }
266
267 int nw_ports_reconfigure(nw_ports* ports) {
268 return nw_ports_walk(ports, __nw_ports_reconfigure, NULL);
269 }