1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
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. #
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. #
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/>. #
19 #############################################################################*/
21 #include <linux/if_link.h>
23 #include <systemd/sd-netlink.h>
30 #include "port-vlan.h"
33 const nw_string_table_t nw_port_vlan_proto
[] = {
34 { NW_VLAN_PROTO_8021Q
, "802.1Q" },
35 { NW_VLAN_PROTO_8021AD
, "802.1ad" },
39 NW_STRING_TABLE_LOOKUP(nw_port_vlan_proto_t
, nw_port_vlan_proto
)
41 static int nw_port_vlan_setup(nw_port
* port
) {
45 r
= NW_CONFIG_OPTION_INT(port
->config
, "VLAN_ID", &port
->vlan
.id
);
50 r
= NW_CONFIG_OPTION_STRING_TABLE(port
->config
,
51 "VLAN_PROTO", &port
->vlan
.proto
, nw_port_vlan_proto
);
56 r
= NW_CONFIG_OPTION_STRING_BUFFER(port
->config
,
57 "VLAN_PARENT", port
->vlan
.__parent_name
);
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
);
72 switch (port
->vlan
.proto
) {
73 case NW_VLAN_PROTO_8021Q
:
74 case NW_VLAN_PROTO_8021AD
:
78 ERROR("%p: Invalid VLAN protocol\n", port
->name
);
85 static int nw_port_vlan_create_link(nw_port
* port
, sd_netlink_message
* m
) {
89 r
= sd_netlink_message_append_u16(m
, IFLA_VLAN_ID
, port
->vlan
.id
);
94 r
= sd_netlink_message_append_u16(m
, IFLA_VLAN_PROTOCOL
, htobe16(port
->vlan
.proto
));
101 static int nw_port_vlan_to_json(nw_port
* port
, struct json_object
* o
) {
102 nw_port
* parent
= NULL
;
106 r
= json_object_add_int64(o
, "VLANId", port
->vlan
.id
);
110 // Add the VLAN Protocol
111 r
= json_object_add_string(o
, "VLANProtocol",
112 nw_port_vlan_proto_to_string(port
->vlan
.proto
));
117 parent
= nw_port_get_parent_port(port
);
119 r
= json_object_add_string(o
, "VLANParentPort", nw_port_name(parent
));
126 nw_port_unref(parent
);
131 const nw_port_type_t nw_port_type_vlan
= {
135 .setup
= nw_port_vlan_setup
,
136 .validate
= nw_port_vlan_validate
,
138 .get_parent_port
= nw_port_get_vlan_parent
,
141 .create_link
= nw_port_vlan_create_link
,
144 .to_json
= nw_port_vlan_to_json
,
150 int nw_port_get_vlan_id(nw_port
* port
) {
154 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
158 return port
->vlan
.id
;
161 int nw_port_set_vlan_id(nw_port
* port
, int id
) {
165 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
169 // Check if the VLAN ID is within range
170 if (id
< NW_VLAN_ID_MIN
|| id
> NW_VLAN_ID_MAX
)
176 DEBUG("Port %s: Set VLAN ID to %d\n", port
->name
, port
->vlan
.id
);
181 int nw_port_set_vlan_proto(nw_port
* port
, const nw_port_vlan_proto_t proto
) {
183 case NW_VLAN_PROTO_8021Q
:
184 case NW_VLAN_PROTO_8021AD
:
185 port
->vlan
.proto
= proto
;
195 nw_port
* nw_port_get_vlan_parent(nw_port
* port
) {
199 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
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
);
207 if (port
->vlan
.parent
)
208 return nw_port_ref(port
->vlan
.parent
);
214 int nw_port_set_vlan_parent(nw_port
* port
, nw_port
* parent
) {
218 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
222 // Reset the former parent name
223 nw_string_empty(port
->vlan
.__parent_name
);
225 // Dereference the former parent
226 if (port
->vlan
.parent
) {
227 nw_port_unref(port
->vlan
.parent
);
228 port
->vlan
.parent
= NULL
;
231 // Store the new parent
233 port
->vlan
.parent
= nw_port_ref(parent
);
236 nw_string_set(port
->vlan
.__parent_name
, nw_port_name(parent
));
239 DEBUG("Port %s: Set VLAN parent to %s\n", port
->name
, nw_port_name(port
->vlan
.parent
));