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 struct nw_string_table 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_read_proto(nw_config
* config
, const char* key
, void* data
) {
42 nw_port_vlan_proto_t
* proto
= (nw_port_vlan_proto_t
*)data
;
44 const char* value
= nw_config_get(config
, key
);
46 *proto
= nw_port_vlan_proto_from_string(data
);
54 static int nw_port_vlan_write_proto(nw_config
* config
, const char* key
, const void* data
) {
55 const nw_port_vlan_proto_t
* proto
= (nw_port_vlan_proto_t
*)data
;
57 return nw_config_set(config
, key
, nw_port_vlan_proto_to_string(*proto
));
60 static int nw_port_vlan_setup(nw_port
* port
) {
64 r
= NW_CONFIG_OPTION_INT(port
->config
, "VLAN_ID", &port
->vlan
.id
);
69 r
= NW_CONFIG_OPTION(port
->config
, "VLAN_PROTO", &port
->vlan
.proto
,
70 nw_port_vlan_read_proto
, nw_port_vlan_write_proto
);
75 r
= NW_CONFIG_OPTION_STRING(port
->config
, "VLAN_PARENT", &port
->vlan
.__parent_name
);
82 static int nw_port_vlan_create_link(nw_port
* port
, sd_netlink_message
* m
) {
86 r
= sd_netlink_message_append_u16(m
, IFLA_VLAN_ID
, port
->vlan
.id
);
91 r
= sd_netlink_message_append_u16(m
, IFLA_VLAN_PROTOCOL
, htobe16(port
->vlan
.proto
));
98 static int nw_port_vlan_to_json(nw_port
* port
, struct json_object
* o
) {
99 nw_port
* parent
= NULL
;
103 r
= json_object_add_int64(o
, "VLANId", port
->vlan
.id
);
107 // Add the VLAN Protocol
108 r
= json_object_add_string(o
, "VLANProtocol",
109 nw_port_vlan_proto_to_string(port
->vlan
.proto
));
114 parent
= nw_port_get_parent_port(port
);
116 r
= json_object_add_string(o
, "VLANParentPort", nw_port_name(parent
));
123 nw_port_unref(parent
);
128 const nw_port_info_t nw_port_info_vlan
= {
134 .setup
= nw_port_vlan_setup
,
136 .get_parent_port
= nw_port_get_vlan_parent
,
139 .create_link
= nw_port_vlan_create_link
,
142 .to_json
= nw_port_vlan_to_json
,
149 int nw_port_get_vlan_id(nw_port
* port
) {
153 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
157 return port
->vlan
.id
;
160 int nw_port_set_vlan_id(nw_port
* port
, int id
) {
164 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
168 // Check if the VLAN ID is within range
169 if (id
< NW_VLAN_ID_MIN
|| id
> NW_VLAN_ID_MAX
)
175 DEBUG("Port %s: Set VLAN ID to %d\n", port
->name
, port
->vlan
.id
);
180 int nw_port_set_vlan_proto(nw_port
* port
, const nw_port_vlan_proto_t proto
) {
182 case NW_VLAN_PROTO_8021Q
:
183 case NW_VLAN_PROTO_8021ad
:
184 port
->vlan
.proto
= proto
;
194 nw_port
* nw_port_get_vlan_parent(nw_port
* port
) {
198 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
202 // Try to find a reference to the parent if none exists
203 if (!port
->vlan
.parent
&& *port
->vlan
.__parent_name
)
204 port
->vlan
.parent
= nw_daemon_get_port_by_name(port
->daemon
, port
->vlan
.__parent_name
);
206 if (port
->vlan
.parent
)
207 return nw_port_ref(port
->vlan
.parent
);
213 int nw_port_set_vlan_parent(nw_port
* port
, nw_port
* parent
) {
217 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
221 // Reset the former parent name
222 nw_string_empty(port
->vlan
.__parent_name
);
224 // Dereference the former parent
225 if (port
->vlan
.parent
) {
226 nw_port_unref(port
->vlan
.parent
);
227 port
->vlan
.parent
= NULL
;
230 // Store the new parent
232 port
->vlan
.parent
= nw_port_ref(parent
);
234 DEBUG("Port %s: Set VLAN parent to %s\n", port
->name
, nw_port_name(port
->vlan
.parent
));