2 * ustp - OpenWrt STP/RSTP/MSTP daemon
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <libubox/uloop.h>
23 enum bridge_config_attr
{
26 BRIDGE_CONFIG_FWD_DELAY
,
27 BRIDGE_CONFIG_HELLO_TIME
,
28 BRIDGE_CONFIG_MAX_AGE
,
29 BRIDGE_CONFIG_AGEING_TIME
,
33 static const struct blobmsg_policy bridge_config_policy
[__BRIDGE_CONFIG_MAX
] = {
34 [BRIDGE_CONFIG_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
35 [BRIDGE_CONFIG_PROTO
] = { "proto", BLOBMSG_TYPE_STRING
},
36 [BRIDGE_CONFIG_FWD_DELAY
] = { "forward_delay", BLOBMSG_TYPE_INT32
},
37 [BRIDGE_CONFIG_HELLO_TIME
] = { "hello_time", BLOBMSG_TYPE_INT32
},
38 [BRIDGE_CONFIG_MAX_AGE
] = { "max_age", BLOBMSG_TYPE_INT32
},
39 [BRIDGE_CONFIG_AGEING_TIME
] = { "ageing_time", BLOBMSG_TYPE_INT32
},
43 ubus_set_bridge_config(struct blob_attr
*attr
)
45 struct blob_attr
*tb
[__BRIDGE_CONFIG_MAX
], *cur
;
46 struct bridge_config
*cfg
;
47 CIST_BridgeConfig
*bc
;
49 blobmsg_parse(bridge_config_policy
, __BRIDGE_CONFIG_MAX
, tb
,
50 blobmsg_data(attr
), blobmsg_len(attr
));
52 cur
= tb
[BRIDGE_CONFIG_NAME
];
56 cfg
= bridge_config_get(blobmsg_get_string(cur
), true);
59 bc
->protocol_version
= protoRSTP
;
60 bc
->set_protocol_version
= true;
62 if ((cur
= tb
[BRIDGE_CONFIG_PROTO
]) != NULL
) {
63 const char *proto
= blobmsg_get_string(cur
);
65 if (!strcmp(proto
, "mstp"))
66 bc
->protocol_version
= protoMSTP
;
67 else if (!strcmp(proto
, "stp"))
68 bc
->protocol_version
= protoSTP
;
71 if ((cur
= tb
[BRIDGE_CONFIG_FWD_DELAY
]) != NULL
) {
72 bc
->bridge_forward_delay
= blobmsg_get_u32(cur
);
73 bc
->set_bridge_forward_delay
= true;
76 if ((cur
= tb
[BRIDGE_CONFIG_HELLO_TIME
]) != NULL
) {
77 bc
->bridge_hello_time
= blobmsg_get_u32(cur
);
78 bc
->set_bridge_hello_time
= true;
81 if ((cur
= tb
[BRIDGE_CONFIG_AGEING_TIME
]) != NULL
) {
82 bc
->bridge_ageing_time
= blobmsg_get_u32(cur
);
83 bc
->set_bridge_ageing_time
= true;
86 if ((cur
= tb
[BRIDGE_CONFIG_MAX_AGE
]) != NULL
) {
87 bc
->bridge_max_age
= blobmsg_get_u32(cur
);
88 bc
->set_bridge_max_age
= true;
95 ubus_add_bridge(struct ubus_context
*ctx
, struct ubus_object
*obj
,
96 struct ubus_request_data
*req
, const char *method
,
97 struct blob_attr
*msg
)
99 if (!ubus_set_bridge_config(msg
))
100 return UBUS_STATUS_INVALID_ARGUMENT
;
105 enum bridge_state_attr
{
107 BRIDGE_STATE_ENABLED
,
111 static const struct blobmsg_policy bridge_state_policy
[__BRIDGE_STATE_MAX
] = {
112 [BRIDGE_STATE_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
113 [BRIDGE_STATE_ENABLED
] = { "enabled", BLOBMSG_TYPE_BOOL
},
117 ubus_bridge_state(struct ubus_context
*ctx
, struct ubus_object
*obj
,
118 struct ubus_request_data
*req
, const char *method
,
119 struct blob_attr
*msg
)
121 struct blob_attr
*tb
[__BRIDGE_STATE_MAX
];
122 struct bridge_config
*cfg
;
123 const char *bridge_name
;
124 struct worker_event ev
= {};
126 blobmsg_parse(bridge_state_policy
, __BRIDGE_STATE_MAX
, tb
,
127 blobmsg_data(msg
), blobmsg_len(msg
));
129 if (!tb
[BRIDGE_STATE_NAME
] || !tb
[BRIDGE_STATE_ENABLED
])
130 return UBUS_STATUS_INVALID_ARGUMENT
;
132 bridge_name
= blobmsg_get_string(tb
[BRIDGE_STATE_NAME
]);
133 ev
.bridge_idx
= if_nametoindex(bridge_name
);
135 return UBUS_STATUS_NOT_FOUND
;
137 if (blobmsg_get_bool(tb
[BRIDGE_STATE_ENABLED
])) {
138 cfg
= bridge_config_get(bridge_name
, false);
140 return UBUS_STATUS_NOT_FOUND
;
142 ev
.type
= WORKER_EV_BRIDGE_ADD
;
143 ev
.bridge_config
= cfg
->config
;
145 ev
.type
= WORKER_EV_BRIDGE_REMOVE
;
148 worker_queue_event(&ev
);
153 static const struct ubus_method ustp_methods
[] = {
154 UBUS_METHOD("add_bridge", ubus_add_bridge
, bridge_config_policy
),
155 UBUS_METHOD("bridge_state", ubus_bridge_state
, bridge_state_policy
),
158 static struct ubus_object_type ustp_object_type
=
159 UBUS_OBJECT_TYPE("ustp", ustp_methods
);
161 static struct ubus_object ustp_object
= {
163 .type
= &ustp_object_type
,
164 .methods
= ustp_methods
,
165 .n_methods
= ARRAY_SIZE(ustp_methods
),
169 netifd_device_cb(struct ubus_context
*ctx
, struct ubus_object
*obj
,
170 struct ubus_request_data
*req
, const char *method
,
171 struct blob_attr
*msg
)
173 if (strcmp(method
, "stp_init") != 0)
176 ubus_set_bridge_config(msg
);
181 static struct ubus_auto_conn conn
;
182 static struct ubus_subscriber netifd_sub
;
184 static void netifd_sub_cb(struct uloop_timeout
*t
)
188 if (ubus_lookup_id(&conn
.ctx
, "network.device", &id
) != 0 ||
189 ubus_subscribe(&conn
.ctx
, &netifd_sub
, id
) != 0) {
190 uloop_timeout_set(t
, 1000);
194 blob_buf_init(&b
, 0);
195 ubus_invoke(&conn
.ctx
, id
, "stp_init", b
.head
, NULL
, NULL
, 1000);
198 static struct uloop_timeout netifd_sub_timer
= {
203 netifd_device_remove_cb(struct ubus_context
*ctx
,
204 struct ubus_subscriber
*obj
, uint32_t id
)
206 uloop_timeout_set(&netifd_sub_timer
, 1000);
209 static struct ubus_subscriber netifd_sub
= {
210 .cb
= netifd_device_cb
,
211 .remove_cb
= netifd_device_remove_cb
,
215 ubus_connect_handler(struct ubus_context
*ctx
)
217 ubus_add_object(ctx
, &ustp_object
);
218 ubus_register_subscriber(ctx
, &netifd_sub
);
219 uloop_timeout_set(&netifd_sub_timer
, 1);
222 void ustp_ubus_init(void)
224 conn
.cb
= ubus_connect_handler
;
225 ubus_auto_connect(&conn
);
228 void ustp_ubus_exit(void)
232 ubus_remove_object(&conn
.ctx
, &ustp_object
);
233 ubus_unregister_subscriber(&conn
.ctx
, &netifd_sub
);
234 blob_buf_init(&b
, 0);
235 if (ubus_lookup_id(&conn
.ctx
, "network.device", &id
) == 0)
236 ubus_invoke(&conn
.ctx
, id
, "stp_init", b
.head
, NULL
, NULL
, 1000);
237 ubus_auto_shutdown(&conn
);