]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/port.c
ec40830fe11405b8585e4de652a6e5024704971a
[people/ms/network.git] / src / networkd / port.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 <limits.h>
22 #include <net/if.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25
26 #include <systemd/sd-bus.h>
27
28 #include "address.h"
29 #include "config.h"
30 #include "link.h"
31 #include "logging.h"
32 #include "string.h"
33 #include "port.h"
34
35 struct nw_port {
36 nw_daemon* daemon;
37 int nrefs;
38
39 // Link
40 nw_link* link;
41
42 char name[IF_NAMESIZE];
43 nw_port_type_t type;
44
45 // Configuration
46 nw_config *config;
47
48 // Common attributes
49 nw_address_t address;
50 };
51
52 static const struct nw_port_type_map {
53 nw_port_type_t type;
54 const char* name;
55 } nw_port_type_map[] = {
56 { NW_PORT_DUMMY, "dummy" },
57 { NW_PORT_UNKNOWN, NULL },
58 };
59
60 static nw_port_type_t nw_port_type_from_string(const char* s) {
61 const struct nw_port_type_map* map = NULL;
62
63 for (map = nw_port_type_map; *map->name; map++) {
64 if (strcmp(map->name, s) == 0)
65 return map->type;
66 }
67
68 return NW_PORT_UNKNOWN;
69 }
70
71 static void nw_port_free(nw_port* port) {
72 if (port->link)
73 nw_link_unref(port->link);
74 if (port->config)
75 nw_config_unref(port->config);
76 if (port->daemon)
77 nw_daemon_unref(port->daemon);
78
79 free(port);
80 }
81
82 static int nw_port_setup_address(nw_port* port) {
83 int r;
84
85 // Read ADDRESS from configuration
86 const char* s = nw_config_get(port->config, "ADDRESS");
87 if (!s) {
88 ERROR("Port %s: Address isn't set\n", port->name);
89 goto ERROR;
90 }
91
92 // Parse the address
93 r = nw_address_from_string(&port->address, s);
94 if (r) {
95 ERROR("Port %s: Could not parse address: %m\n", port->name);
96 goto ERROR;
97 }
98
99 // Check if this address is usable
100 r = nw_address_is_multicast(&port->address);
101 if (r) {
102 DEBUG("Port %s: Multicast bit is set on Ethernet address\n", port->name);
103 goto ERROR;
104 }
105
106 return 0;
107
108 ERROR:
109 // Generate a random Ethernet address
110 r = nw_address_generate(&port->address);
111 if (r) {
112 ERROR("Could not generate a random Ethernet address: %m\n");
113 return r;
114 }
115
116 return 0;
117 }
118
119 static int nw_port_setup_common(nw_port* port) {
120 int r;
121
122 // Address
123 r = nw_port_setup_address(port);
124 if (r)
125 return r;
126
127 return 0;
128 }
129
130 static nw_port_type_t nw_port_setup_type(nw_port* port) {
131 const char* type = nw_config_get(port->config, "TYPE");
132 if (!type)
133 return NW_PORT_UNKNOWN;
134
135 return nw_port_type_from_string(type);
136 }
137
138 static int nw_port_setup(nw_port* port) {
139 char path[PATH_MAX];
140 int r;
141
142 // Find the link
143 port->link = nw_daemon_get_link_by_name(port->daemon, port->name);
144 if (port->link) {
145 DEBUG("%s: Found matching link %d\n", port->name, nw_link_ifindex(port->link));
146 } else {
147 DEBUG("%s: Could not find matching link\n", port->name);
148 }
149
150 // Compose the path to the main configuration file
151 r = nw_path_join(path, PORT_CONFIG_DIR, port->name);
152 if (r)
153 return r;
154
155 // Initialize the configuration
156 r = nw_config_create(&port->config, path);
157 if (r)
158 return r;
159
160 // Determine type
161 port->type = nw_port_setup_type(port);
162 if (!port->type) {
163 ERROR("Could not determine type of port %s\n", port->name);
164 return 0;
165 }
166
167 // Perform some common initialization
168 r = nw_port_setup_common(port);
169 if (r)
170 return r;
171
172 // Call any custom initialization
173 switch (port->type) {
174 // These do not need any special initialization
175 case NW_PORT_DUMMY:
176 case NW_PORT_UNKNOWN:
177 break;
178 }
179
180 return 0;
181 }
182
183 int nw_port_create(nw_port** port, nw_daemon* daemon, const char* name) {
184 int r;
185
186 // Allocate a new object
187 nw_port* p = calloc(1, sizeof(*p));
188 if (!p)
189 return 1;
190
191 // Store a reference to the daemon
192 p->daemon = nw_daemon_ref(daemon);
193
194 // Initialize reference counter
195 p->nrefs = 1;
196
197 // Store the name
198 r = nw_string_set(p->name, name);
199 if (r)
200 goto ERROR;
201
202 // Setup the port
203 r = nw_port_setup(p);
204 if (r)
205 goto ERROR;
206
207 *port = p;
208 return 0;
209
210 ERROR:
211 nw_port_free(p);
212 return r;
213 }
214
215 nw_port* nw_port_ref(nw_port* port) {
216 port->nrefs++;
217
218 return port;
219 }
220
221 nw_port* nw_port_unref(nw_port* port) {
222 if (--port->nrefs > 0)
223 return port;
224
225 nw_port_free(port);
226 return NULL;
227 }
228
229 int nw_port_save(nw_port* port) {
230 int r;
231
232 r = nw_config_write(port->config);
233 if (r)
234 return r;
235
236 return 0;
237 }
238
239 const char* nw_port_name(nw_port* port) {
240 return port->name;
241 }
242
243 char* nw_port_bus_path(nw_port* port) {
244 char* p = NULL;
245 int r;
246
247 // Encode the bus path
248 r = sd_bus_path_encode("/org/ipfire/network1/port", port->name, &p);
249 if (r < 0)
250 return NULL;
251
252 return p;
253 }
254
255 static nw_link* nw_port_get_link(nw_port* port) {
256 if (!port->link)
257 return NULL;
258
259 return nw_link_ref(port->link);
260 }
261
262 const nw_address_t* nw_port_get_address(nw_port* port) {
263 return &port->address;
264 }
265
266 int nw_port_reconfigure(nw_port* port) {
267 return 0; // XXX TODO
268 }
269
270 int nw_port_has_carrier(nw_port* port) {
271 if (!port->link)
272 return 0;
273
274 return nw_link_has_carrier(port->link);
275 }