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_read_proto(nw_config
* config
,
42 const char* key
, void* value
, void* data
) {
43 nw_port_vlan_proto_t
* proto
= (nw_port_vlan_proto_t
*)value
;
45 const char* p
= nw_config_get(config
, key
);
47 *proto
= nw_port_vlan_proto_from_string(p
);
55 static int nw_port_vlan_write_proto(nw_config
* config
,
56 const char* key
, const void* value
, void* data
) {
57 const nw_port_vlan_proto_t
* proto
= (nw_port_vlan_proto_t
*)value
;
59 return nw_config_set(config
, key
, nw_port_vlan_proto_to_string(*proto
));
62 static int nw_port_vlan_setup(nw_port
* port
) {
66 r
= NW_CONFIG_OPTION_INT(port
->config
, "VLAN_ID", &port
->vlan
.id
);
71 r
= NW_CONFIG_OPTION(port
->config
, "VLAN_PROTO", &port
->vlan
.proto
,
72 nw_port_vlan_read_proto
, nw_port_vlan_write_proto
, NULL
);
77 r
= NW_CONFIG_OPTION_STRING(port
->config
, "VLAN_PARENT", &port
->vlan
.__parent_name
);
84 static int nw_port_vlan_create_link(nw_port
* port
, sd_netlink_message
* m
) {
88 r
= sd_netlink_message_append_u16(m
, IFLA_VLAN_ID
, port
->vlan
.id
);
93 r
= sd_netlink_message_append_u16(m
, IFLA_VLAN_PROTOCOL
, htobe16(port
->vlan
.proto
));
100 static int nw_port_vlan_to_json(nw_port
* port
, struct json_object
* o
) {
101 nw_port
* parent
= NULL
;
105 r
= json_object_add_int64(o
, "VLANId", port
->vlan
.id
);
109 // Add the VLAN Protocol
110 r
= json_object_add_string(o
, "VLANProtocol",
111 nw_port_vlan_proto_to_string(port
->vlan
.proto
));
116 parent
= nw_port_get_parent_port(port
);
118 r
= json_object_add_string(o
, "VLANParentPort", nw_port_name(parent
));
125 nw_port_unref(parent
);
130 const nw_port_info_t nw_port_info_vlan
= {
136 .setup
= nw_port_vlan_setup
,
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
,
151 int nw_port_get_vlan_id(nw_port
* port
) {
155 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
159 return port
->vlan
.id
;
162 int nw_port_set_vlan_id(nw_port
* port
, int id
) {
166 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
170 // Check if the VLAN ID is within range
171 if (id
< NW_VLAN_ID_MIN
|| id
> NW_VLAN_ID_MAX
)
177 DEBUG("Port %s: Set VLAN ID to %d\n", port
->name
, port
->vlan
.id
);
182 int nw_port_set_vlan_proto(nw_port
* port
, const nw_port_vlan_proto_t proto
) {
184 case NW_VLAN_PROTO_8021Q
:
185 case NW_VLAN_PROTO_8021ad
:
186 port
->vlan
.proto
= proto
;
196 nw_port
* nw_port_get_vlan_parent(nw_port
* port
) {
200 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
204 // Try to find a reference to the parent if none exists
205 if (!port
->vlan
.parent
&& *port
->vlan
.__parent_name
)
206 port
->vlan
.parent
= nw_daemon_get_port_by_name(port
->daemon
, port
->vlan
.__parent_name
);
208 if (port
->vlan
.parent
)
209 return nw_port_ref(port
->vlan
.parent
);
215 int nw_port_set_vlan_parent(nw_port
* port
, nw_port
* parent
) {
219 r
= nw_port_check_type(port
, NW_PORT_VLAN
);
223 // Reset the former parent name
224 nw_string_empty(port
->vlan
.__parent_name
);
226 // Dereference the former parent
227 if (port
->vlan
.parent
) {
228 nw_port_unref(port
->vlan
.parent
);
229 port
->vlan
.parent
= NULL
;
232 // Store the new parent
234 port
->vlan
.parent
= nw_port_ref(parent
);
236 DEBUG("Port %s: Set VLAN parent to %s\n", port
->name
, nw_port_name(port
->vlan
.parent
));