]>
Commit | Line | Data |
---|---|---|
ff886975 MT |
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 | ||
d872e169 MT |
21 | #include <linux/if_link.h> |
22 | ||
240e331b MT |
23 | #include <systemd/sd-netlink.h> |
24 | ||
ff886975 MT |
25 | #include "config.h" |
26 | #include "daemon.h" | |
e9b0614e | 27 | #include "json.h" |
ff886975 MT |
28 | #include "logging.h" |
29 | #include "port.h" | |
30 | #include "port-vlan.h" | |
31 | #include "string.h" | |
32 | ||
644eb1c8 | 33 | const nw_string_table_t nw_port_vlan_proto[] = { |
d872e169 | 34 | { NW_VLAN_PROTO_8021Q, "802.1Q" }, |
4db7e548 | 35 | { NW_VLAN_PROTO_8021AD, "802.1ad" }, |
d872e169 MT |
36 | { -1, NULL }, |
37 | }; | |
38 | ||
39 | NW_STRING_TABLE_LOOKUP(nw_port_vlan_proto_t, nw_port_vlan_proto) | |
40 | ||
082d81a3 | 41 | static int nw_port_vlan_setup(nw_port* port) { |
ff886975 MT |
42 | int r; |
43 | ||
44 | // VLAN ID | |
082d81a3 MT |
45 | r = NW_CONFIG_OPTION_INT(port->config, "VLAN_ID", &port->vlan.id); |
46 | if (r < 0) | |
ff886975 MT |
47 | return r; |
48 | ||
d872e169 | 49 | // VLAN Protocol |
7442668a MT |
50 | r = NW_CONFIG_OPTION_STRING_TABLE(port->config, |
51 | "VLAN_PROTO", &port->vlan.proto, nw_port_vlan_proto); | |
082d81a3 | 52 | if (r < 0) |
d872e169 MT |
53 | return r; |
54 | ||
ff886975 | 55 | // Parent Port |
e633147d MT |
56 | r = NW_CONFIG_OPTION_STRING_BUFFER(port->config, |
57 | "VLAN_PARENT", port->vlan.__parent_name); | |
082d81a3 | 58 | if (r < 0) |
ff886975 MT |
59 | return r; |
60 | ||
61 | return 0; | |
62 | } | |
63 | ||
749b1a85 MT |
64 | static int nw_port_vlan_validate(nw_port* port) { |
65 | // Check if the VLAN ID is within range | |
66 | if (port->vlan.id < NW_VLAN_ID_MIN || port->vlan.id > NW_VLAN_ID_MAX) { | |
67 | ERROR("%s: Invalid VLAN ID %d\n", port->name, port->vlan.id); | |
68 | return 1; | |
69 | } | |
70 | ||
71 | // Validate protocol | |
72 | switch (port->vlan.proto) { | |
73 | case NW_VLAN_PROTO_8021Q: | |
74 | case NW_VLAN_PROTO_8021AD: | |
75 | break; | |
76 | ||
77 | default: | |
78 | ERROR("%p: Invalid VLAN protocol\n", port->name); | |
79 | return 1; | |
80 | } | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
240e331b MT |
85 | static int nw_port_vlan_create_link(nw_port* port, sd_netlink_message* m) { |
86 | int r; | |
87 | ||
88 | // Set VLAN ID | |
89 | r = sd_netlink_message_append_u16(m, IFLA_VLAN_ID, port->vlan.id); | |
90 | if (r < 0) | |
91 | return r; | |
92 | ||
d872e169 MT |
93 | // Set VLAN protocol |
94 | r = sd_netlink_message_append_u16(m, IFLA_VLAN_PROTOCOL, htobe16(port->vlan.proto)); | |
95 | if (r < 0) | |
96 | return r; | |
97 | ||
240e331b MT |
98 | return 0; |
99 | } | |
100 | ||
e9b0614e MT |
101 | static int nw_port_vlan_to_json(nw_port* port, struct json_object* o) { |
102 | nw_port* parent = NULL; | |
103 | int r; | |
104 | ||
105 | // Add the VLAN ID | |
106 | r = json_object_add_int64(o, "VLANId", port->vlan.id); | |
107 | if (r < 0) | |
108 | goto ERROR; | |
109 | ||
d872e169 MT |
110 | // Add the VLAN Protocol |
111 | r = json_object_add_string(o, "VLANProtocol", | |
112 | nw_port_vlan_proto_to_string(port->vlan.proto)); | |
113 | if (r < 0) | |
114 | goto ERROR; | |
115 | ||
e9b0614e MT |
116 | // Fetch the parent |
117 | parent = nw_port_get_parent_port(port); | |
118 | if (parent) { | |
119 | r = json_object_add_string(o, "VLANParentPort", nw_port_name(parent)); | |
120 | if (r < 0) | |
121 | goto ERROR; | |
122 | } | |
123 | ||
124 | ERROR: | |
125 | if (parent) | |
126 | nw_port_unref(parent); | |
127 | ||
128 | return r; | |
129 | } | |
130 | ||
c464b5d1 | 131 | const nw_port_type_t nw_port_type_vlan = { |
240e331b MT |
132 | .kind = "vlan", |
133 | ||
c464b5d1 MT |
134 | // Configuration |
135 | .setup = nw_port_vlan_setup, | |
749b1a85 | 136 | .validate = nw_port_vlan_validate, |
240e331b | 137 | |
c464b5d1 | 138 | .get_parent_port = nw_port_get_vlan_parent, |
240e331b | 139 | |
c464b5d1 MT |
140 | // Link |
141 | .create_link = nw_port_vlan_create_link, | |
e9b0614e | 142 | |
c464b5d1 MT |
143 | // JSON |
144 | .to_json = nw_port_vlan_to_json, | |
ff886975 MT |
145 | }; |
146 | ||
147 | /* | |
148 | VLAN | |
149 | */ | |
150 | int nw_port_get_vlan_id(nw_port* port) { | |
151 | int r; | |
152 | ||
153 | // Check type | |
154 | r = nw_port_check_type(port, NW_PORT_VLAN); | |
155 | if (r < 0) | |
156 | return r; | |
157 | ||
158 | return port->vlan.id; | |
159 | } | |
160 | ||
161 | int nw_port_set_vlan_id(nw_port* port, int id) { | |
162 | int r; | |
163 | ||
164 | // Check type | |
165 | r = nw_port_check_type(port, NW_PORT_VLAN); | |
166 | if (r < 0) | |
167 | return r; | |
168 | ||
169 | // Check if the VLAN ID is within range | |
170 | if (id < NW_VLAN_ID_MIN || id > NW_VLAN_ID_MAX) | |
171 | return -EINVAL; | |
172 | ||
173 | // Store the ID | |
174 | port->vlan.id = id; | |
175 | ||
176 | DEBUG("Port %s: Set VLAN ID to %d\n", port->name, port->vlan.id); | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
d872e169 MT |
181 | int nw_port_set_vlan_proto(nw_port* port, const nw_port_vlan_proto_t proto) { |
182 | switch (proto) { | |
183 | case NW_VLAN_PROTO_8021Q: | |
4db7e548 | 184 | case NW_VLAN_PROTO_8021AD: |
d872e169 MT |
185 | port->vlan.proto = proto; |
186 | break; | |
187 | ||
188 | default: | |
189 | return -EINVAL; | |
190 | } | |
191 | ||
192 | return 0; | |
193 | } | |
194 | ||
ff886975 MT |
195 | nw_port* nw_port_get_vlan_parent(nw_port* port) { |
196 | int r; | |
197 | ||
198 | // Check type | |
199 | r = nw_port_check_type(port, NW_PORT_VLAN); | |
200 | if (r < 0) | |
201 | return NULL; | |
202 | ||
203 | // Try to find a reference to the parent if none exists | |
204 | if (!port->vlan.parent && *port->vlan.__parent_name) | |
205 | port->vlan.parent = nw_daemon_get_port_by_name(port->daemon, port->vlan.__parent_name); | |
206 | ||
207 | if (port->vlan.parent) | |
208 | return nw_port_ref(port->vlan.parent); | |
209 | ||
210 | // No port found | |
211 | return NULL; | |
212 | } | |
213 | ||
214 | int nw_port_set_vlan_parent(nw_port* port, nw_port* parent) { | |
215 | int r; | |
216 | ||
217 | // Check type | |
218 | r = nw_port_check_type(port, NW_PORT_VLAN); | |
219 | if (r < 0) | |
220 | return r; | |
221 | ||
222 | // Reset the former parent name | |
223 | nw_string_empty(port->vlan.__parent_name); | |
224 | ||
225 | // Dereference the former parent | |
226 | if (port->vlan.parent) { | |
227 | nw_port_unref(port->vlan.parent); | |
228 | port->vlan.parent = NULL; | |
229 | } | |
230 | ||
231 | // Store the new parent | |
d200865e | 232 | if (parent) { |
ff886975 MT |
233 | port->vlan.parent = nw_port_ref(parent); |
234 | ||
d200865e MT |
235 | // Store the name |
236 | nw_string_set(port->vlan.__parent_name, nw_port_name(parent)); | |
237 | } | |
238 | ||
ff886975 MT |
239 | DEBUG("Port %s: Set VLAN parent to %s\n", port->name, nw_port_name(port->vlan.parent)); |
240 | ||
241 | return 0; | |
242 | } |