• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ustp/ubus.c

  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