1 /* 2 * ustp - OpenWrt STP/RSTP/MSTP daemon 3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> 4 * 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 8 * 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. 13 */ 14 #include <libubus.h> 15 #include <libubox/uloop.h> 16 #include "config.h" 17 #include "mstp.h" 18 #include "worker.h" 19 #include "ubus.h" 20 21 struct blob_buf b; 22 23 enum bridge_config_attr { 24 BRIDGE_CONFIG_NAME, 25 BRIDGE_CONFIG_PROTO, 26 BRIDGE_CONFIG_FWD_DELAY, 27 BRIDGE_CONFIG_HELLO_TIME, 28 BRIDGE_CONFIG_MAX_AGE, 29 BRIDGE_CONFIG_AGEING_TIME, 30 __BRIDGE_CONFIG_MAX 31 }; 32 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 }, 40 }; 41 42 static bool 43 ubus_set_bridge_config(struct blob_attr *attr) 44 { 45 struct blob_attr *tb[__BRIDGE_CONFIG_MAX], *cur; 46 struct bridge_config *cfg; 47 CIST_BridgeConfig *bc; 48 49 blobmsg_parse(bridge_config_policy, __BRIDGE_CONFIG_MAX, tb, 50 blobmsg_data(attr), blobmsg_len(attr)); 51 52 cur = tb[BRIDGE_CONFIG_NAME]; 53 if (!cur) 54 return false; 55 56 cfg = bridge_config_get(blobmsg_get_string(cur), true); 57 58 bc = &cfg->config; 59 bc->protocol_version = protoRSTP; 60 bc->set_protocol_version = true; 61 62 if ((cur = tb[BRIDGE_CONFIG_PROTO]) != NULL) { 63 const char *proto = blobmsg_get_string(cur); 64 65 if (!strcmp(proto, "mstp")) 66 bc->protocol_version = protoMSTP; 67 else if (!strcmp(proto, "stp")) 68 bc->protocol_version = protoSTP; 69 } 70 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; 74 } 75 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; 79 } 80 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; 84 } 85 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; 89 } 90 91 return true; 92 } 93 94 static int 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) 98 { 99 if (!ubus_set_bridge_config(msg)) 100 return UBUS_STATUS_INVALID_ARGUMENT; 101 102 return 0; 103 } 104 105 enum bridge_state_attr { 106 BRIDGE_STATE_NAME, 107 BRIDGE_STATE_ENABLED, 108 __BRIDGE_STATE_MAX 109 }; 110 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 }, 114 }; 115 116 static int 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) 120 { 121 struct blob_attr *tb[__BRIDGE_STATE_MAX]; 122 struct bridge_config *cfg; 123 const char *bridge_name; 124 struct worker_event ev = {}; 125 126 blobmsg_parse(bridge_state_policy, __BRIDGE_STATE_MAX, tb, 127 blobmsg_data(msg), blobmsg_len(msg)); 128 129 if (!tb[BRIDGE_STATE_NAME] || !tb[BRIDGE_STATE_ENABLED]) 130 return UBUS_STATUS_INVALID_ARGUMENT; 131 132 bridge_name = blobmsg_get_string(tb[BRIDGE_STATE_NAME]); 133 ev.bridge_idx = if_nametoindex(bridge_name); 134 if (!ev.bridge_idx) 135 return UBUS_STATUS_NOT_FOUND; 136 137 if (blobmsg_get_bool(tb[BRIDGE_STATE_ENABLED])) { 138 cfg = bridge_config_get(bridge_name, false); 139 if (!cfg) 140 return UBUS_STATUS_NOT_FOUND; 141 142 ev.type = WORKER_EV_BRIDGE_ADD; 143 ev.bridge_config = cfg->config; 144 } else { 145 ev.type = WORKER_EV_BRIDGE_REMOVE; 146 } 147 148 worker_queue_event(&ev); 149 150 return 0; 151 } 152 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), 156 }; 157 158 static struct ubus_object_type ustp_object_type = 159 UBUS_OBJECT_TYPE("ustp", ustp_methods); 160 161 static struct ubus_object ustp_object = { 162 .name = "ustp", 163 .type = &ustp_object_type, 164 .methods = ustp_methods, 165 .n_methods = ARRAY_SIZE(ustp_methods), 166 }; 167 168 static int 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) 172 { 173 if (strcmp(method, "stp_init") != 0) 174 return 0; 175 176 ubus_set_bridge_config(msg); 177 178 return 0; 179 } 180 181 static struct ubus_auto_conn conn; 182 static struct ubus_subscriber netifd_sub; 183 184 static void netifd_sub_cb(struct uloop_timeout *t) 185 { 186 uint32_t id; 187 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); 191 return; 192 } 193 194 blob_buf_init(&b, 0); 195 ubus_invoke(&conn.ctx, id, "stp_init", b.head, NULL, NULL, 1000); 196 } 197 198 static struct uloop_timeout netifd_sub_timer = { 199 .cb = netifd_sub_cb, 200 }; 201 202 static void 203 netifd_device_remove_cb(struct ubus_context *ctx, 204 struct ubus_subscriber *obj, uint32_t id) 205 { 206 uloop_timeout_set(&netifd_sub_timer, 1000); 207 } 208 209 static struct ubus_subscriber netifd_sub = { 210 .cb = netifd_device_cb, 211 .remove_cb = netifd_device_remove_cb, 212 }; 213 214 static void 215 ubus_connect_handler(struct ubus_context *ctx) 216 { 217 ubus_add_object(ctx, &ustp_object); 218 ubus_register_subscriber(ctx, &netifd_sub); 219 uloop_timeout_set(&netifd_sub_timer, 1); 220 } 221 222 void ustp_ubus_init(void) 223 { 224 conn.cb = ubus_connect_handler; 225 ubus_auto_connect(&conn); 226 } 227 228 void ustp_ubus_exit(void) 229 { 230 uint32_t id; 231 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); 238 } 239
This page was automatically generated by LXR 0.3.1. • OpenWrt