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

Sources/qosify/ubus.c

  1 // SPDX-License-Identifier: GPL-2.0+
  2 /*
  3  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
  4  */
  5 #include <libubus.h>
  6 
  7 #include "qosify.h"
  8 
  9 static struct blob_buf b;
 10 
 11 static int
 12 qosify_ubus_add_array(struct blob_attr *attr, uint8_t val, enum qosify_map_id id)
 13 {
 14         struct blob_attr *cur;
 15         int rem;
 16 
 17         if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
 18                 return UBUS_STATUS_INVALID_ARGUMENT;
 19 
 20         blobmsg_for_each_attr(cur, attr, rem)
 21                 qosify_map_set_entry(id, false, blobmsg_get_string(cur), val);
 22 
 23         return 0;
 24 }
 25 
 26 static int
 27 qosify_ubus_set_files(struct blob_attr *attr)
 28 {
 29         struct blob_attr *cur;
 30         int rem;
 31 
 32         if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
 33                 return UBUS_STATUS_INVALID_ARGUMENT;
 34 
 35         qosify_map_clear_files();
 36 
 37         blobmsg_for_each_attr(cur, attr, rem)
 38                 qosify_map_load_file(blobmsg_get_string(cur));
 39 
 40         qosify_map_gc();
 41 
 42         return 0;
 43 }
 44 
 45 
 46 enum {
 47         CL_ADD_DSCP,
 48         CL_ADD_TIMEOUT,
 49         CL_ADD_IPV4,
 50         CL_ADD_IPV6,
 51         CL_ADD_TCP_PORT,
 52         CL_ADD_UDP_PORT,
 53         CL_ADD_DNS,
 54         __CL_ADD_MAX
 55 };
 56 
 57 static const struct blobmsg_policy qosify_add_policy[__CL_ADD_MAX] = {
 58         [CL_ADD_DSCP] = { "dscp", BLOBMSG_TYPE_STRING },
 59         [CL_ADD_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
 60         [CL_ADD_IPV4] = { "ipv4", BLOBMSG_TYPE_ARRAY },
 61         [CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY },
 62         [CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY },
 63         [CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY },
 64         [CL_ADD_DNS] = { "dns", BLOBMSG_TYPE_ARRAY },
 65 };
 66 
 67 
 68 static int
 69 qosify_ubus_reload(struct ubus_context *ctx, struct ubus_object *obj,
 70                    struct ubus_request_data *req, const char *method,
 71                    struct blob_attr *msg)
 72 {
 73         qosify_map_reload();
 74         return 0;
 75 }
 76 
 77 
 78 static int
 79 qosify_ubus_add(struct ubus_context *ctx, struct ubus_object *obj,
 80                 struct ubus_request_data *req, const char *method,
 81                 struct blob_attr *msg)
 82 {
 83         int prev_timemout = qosify_map_timeout;
 84         struct blob_attr *tb[__CL_ADD_MAX];
 85         struct blob_attr *cur;
 86         uint8_t dscp = 0xff;
 87         int ret;
 88 
 89         blobmsg_parse(qosify_add_policy, __CL_ADD_MAX, tb,
 90                       blobmsg_data(msg), blobmsg_len(msg));
 91 
 92         if (!strcmp(method, "add")) {
 93                 if ((cur = tb[CL_ADD_DSCP]) == NULL ||
 94                     qosify_map_dscp_value(blobmsg_get_string(cur), &dscp))
 95                         return UBUS_STATUS_INVALID_ARGUMENT;
 96 
 97                 if ((cur = tb[CL_ADD_TIMEOUT]) != NULL)
 98                         qosify_map_timeout = blobmsg_get_u32(cur);
 99         }
100 
101         if ((cur = tb[CL_ADD_IPV4]) != NULL &&
102             (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV4_ADDR) != 0))
103                 return ret;
104 
105         if ((cur = tb[CL_ADD_IPV6]) != NULL &&
106             (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV6_ADDR) != 0))
107                 return ret;
108 
109         if ((cur = tb[CL_ADD_TCP_PORT]) != NULL &&
110             (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_TCP_PORTS) != 0))
111                 return ret;
112 
113         if ((cur = tb[CL_ADD_UDP_PORT]) != NULL &&
114             (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0))
115                 return ret;
116 
117         if ((cur = tb[CL_ADD_DNS]) != NULL &&
118             (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_DNS) != 0))
119                 return ret;
120 
121         qosify_map_timeout = prev_timemout;
122 
123         return 0;
124 }
125 
126 enum {
127         CL_CONFIG_RESET,
128         CL_CONFIG_FILES,
129         CL_CONFIG_TIMEOUT,
130         CL_CONFIG_DSCP_UDP,
131         CL_CONFIG_DSCP_TCP,
132         CL_CONFIG_DSCP_ICMP,
133         CL_CONFIG_INTERFACES,
134         CL_CONFIG_DEVICES,
135         CL_CONFIG_CLASSES,
136         __CL_CONFIG_MAX
137 };
138 
139 static const struct blobmsg_policy qosify_config_policy[__CL_CONFIG_MAX] = {
140         [CL_CONFIG_RESET] = { "reset", BLOBMSG_TYPE_BOOL },
141         [CL_CONFIG_FILES] = { "files", BLOBMSG_TYPE_ARRAY },
142         [CL_CONFIG_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
143         [CL_CONFIG_DSCP_UDP] = { "dscp_default_udp", BLOBMSG_TYPE_STRING },
144         [CL_CONFIG_DSCP_TCP] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING },
145         [CL_CONFIG_DSCP_ICMP] = { "dscp_icmp", BLOBMSG_TYPE_STRING },
146         [CL_CONFIG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_TABLE },
147         [CL_CONFIG_DEVICES] = { "devices", BLOBMSG_TYPE_TABLE },
148         [CL_CONFIG_CLASSES] = { "classes", BLOBMSG_TYPE_TABLE },
149 };
150 
151 static int
152 qosify_ubus_config(struct ubus_context *ctx, struct ubus_object *obj,
153                    struct ubus_request_data *req, const char *method,
154                    struct blob_attr *msg)
155 {
156         struct blob_attr *tb[__CL_CONFIG_MAX];
157         struct blob_attr *cur;
158         uint8_t dscp;
159         bool reset = false;
160         int ret;
161 
162         blobmsg_parse(qosify_config_policy, __CL_CONFIG_MAX, tb,
163                       blobmsg_data(msg), blobmsg_len(msg));
164 
165         if ((cur = tb[CL_CONFIG_RESET]) != NULL)
166                 reset = blobmsg_get_bool(cur);
167 
168         if (reset)
169                 qosify_map_reset_config();
170 
171         if ((cur = tb[CL_CONFIG_CLASSES]) != NULL || reset)
172                 qosify_map_set_classes(cur);
173 
174         if ((cur = tb[CL_CONFIG_TIMEOUT]) != NULL)
175                 qosify_map_timeout = blobmsg_get_u32(cur);
176 
177         if ((cur = tb[CL_CONFIG_FILES]) != NULL &&
178             (ret = qosify_ubus_set_files(cur) != 0))
179                 return ret;
180 
181         if (map_parse_flow_config(&flow_config, msg, reset) ||
182             map_fill_dscp_value(&config.dscp_icmp, tb[CL_CONFIG_DSCP_ICMP], reset))
183                 return UBUS_STATUS_INVALID_ARGUMENT;
184 
185         map_fill_dscp_value(&dscp, tb[CL_CONFIG_DSCP_UDP], true);
186         if (dscp != 0xff)
187                 qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, dscp);
188 
189         map_fill_dscp_value(&dscp, tb[CL_CONFIG_DSCP_TCP], true);
190         if (dscp != 0xff)
191                 qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, dscp);
192 
193         qosify_map_update_config();
194 
195         qosify_iface_config_update(tb[CL_CONFIG_INTERFACES], tb[CL_CONFIG_DEVICES]);
196 
197         qosify_iface_check();
198 
199         return 0;
200 }
201 
202 
203 static int
204 qosify_ubus_dump(struct ubus_context *ctx, struct ubus_object *obj,
205                  struct ubus_request_data *req, const char *method,
206                  struct blob_attr *msg)
207 {
208         blob_buf_init(&b, 0);
209         qosify_map_dump(&b);
210         ubus_send_reply(ctx, req, b.head);
211         blob_buf_free(&b);
212 
213         return 0;
214 }
215 
216 static int
217 qosify_ubus_status(struct ubus_context *ctx, struct ubus_object *obj,
218                  struct ubus_request_data *req, const char *method,
219                  struct blob_attr *msg)
220 {
221         blob_buf_init(&b, 0);
222         qosify_iface_status(&b);
223         ubus_send_reply(ctx, req, b.head);
224         blob_buf_free(&b);
225 
226         return 0;
227 }
228 
229 static int
230 qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
231                           struct ubus_request_data *req, const char *method,
232                           struct blob_attr *msg)
233 {
234         qosify_iface_check();
235 
236         return 0;
237 }
238 
239 enum {
240         CL_DNS_HOST_NAME,
241         CL_DNS_HOST_TYPE,
242         CL_DNS_HOST_ADDR,
243         CL_DNS_HOST_TTL,
244         __CL_DNS_HOST_MAX
245 };
246 
247 static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = {
248         [CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING },
249         [CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING },
250         [CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING },
251         [CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 },
252 };
253 
254 static int
255 __qosify_ubus_add_dns_host(struct blob_attr *msg)
256 {
257         struct blob_attr *tb[__CL_DNS_HOST_MAX];
258         struct blob_attr *cur;
259         uint32_t ttl = 0;
260 
261         blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb,
262                       blobmsg_data(msg), blobmsg_len(msg));
263 
264         if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] ||
265             !tb[CL_DNS_HOST_ADDR])
266                 return UBUS_STATUS_INVALID_ARGUMENT;
267 
268         if ((cur = tb[CL_DNS_HOST_TTL]) != NULL)
269                 ttl = blobmsg_get_u32(cur);
270 
271         if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]),
272                                     blobmsg_get_string(tb[CL_DNS_HOST_ADDR]),
273                                     blobmsg_get_string(tb[CL_DNS_HOST_TYPE]),
274                                     ttl))
275                 return UBUS_STATUS_INVALID_ARGUMENT;
276 
277         return 0;
278 }
279 
280 static int
281 qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj,
282                          struct ubus_request_data *req, const char *method,
283                          struct blob_attr *msg)
284 {
285         return __qosify_ubus_add_dns_host(msg);
286 }
287 
288 static const struct ubus_method qosify_methods[] = {
289         UBUS_METHOD_NOARG("reload", qosify_ubus_reload),
290         UBUS_METHOD("add", qosify_ubus_add, qosify_add_policy),
291         UBUS_METHOD_MASK("remove", qosify_ubus_add, qosify_add_policy,
292                          ((1 << __CL_ADD_MAX) - 1) & ~(1 << CL_ADD_DSCP)),
293         UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy),
294         UBUS_METHOD_NOARG("dump", qosify_ubus_dump),
295         UBUS_METHOD_NOARG("status", qosify_ubus_status),
296         UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy),
297         UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices),
298 };
299 
300 static struct ubus_object_type qosify_object_type =
301         UBUS_OBJECT_TYPE("qosify", qosify_methods);
302 
303 static struct ubus_object qosify_object = {
304         .name = "qosify",
305         .type = &qosify_object_type,
306         .methods = qosify_methods,
307         .n_methods = ARRAY_SIZE(qosify_methods),
308 };
309 
310 static void
311 qosify_subscribe_dnsmasq(struct ubus_context *ctx)
312 {
313         static struct ubus_subscriber sub = {
314                 .cb = qosify_ubus_add_dns_host,
315         };
316         uint32_t id;
317 
318         if (!sub.obj.id &&
319             ubus_register_subscriber(ctx, &sub))
320                 return;
321 
322         if (ubus_lookup_id(ctx, "dnsmasq.dns", &id))
323                 return;
324 
325         ubus_subscribe(ctx, &sub, id);
326 }
327 
328 static void
329 qosify_ubus_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
330                      const char *type, struct blob_attr *msg)
331 {
332         static const struct blobmsg_policy policy =
333                 { "path", BLOBMSG_TYPE_STRING };
334         struct blob_attr *attr;
335         const char *path;
336 
337         blobmsg_parse(&policy, 1, &attr, blobmsg_data(msg), blobmsg_len(msg));
338 
339         if (!attr)
340                 return;
341 
342         path = blobmsg_get_string(attr);
343         if (!strcmp(path, "dnsmasq.dns"))
344                 qosify_subscribe_dnsmasq(ctx);
345         else if (!strcmp(path, "bridger"))
346                 qosify_ubus_update_bridger(false);
347 }
348 
349 
350 static void
351 ubus_connect_handler(struct ubus_context *ctx)
352 {
353         static struct ubus_event_handler ev = {
354                 .cb = qosify_ubus_event_cb
355         };
356 
357         ubus_add_object(ctx, &qosify_object);
358         ubus_register_event_handler(ctx, &ev, "ubus.object.add");
359         qosify_subscribe_dnsmasq(ctx);
360 }
361 
362 static struct ubus_auto_conn conn;
363 
364 void qosify_ubus_update_bridger(bool shutdown)
365 {
366         struct ubus_request req;
367         uint32_t id;
368         void *c;
369 
370         if (ubus_lookup_id(&conn.ctx, "bridger", &id))
371                 return;
372 
373         blob_buf_init(&b, 0);
374         blobmsg_add_string(&b, "name", "qosify");
375         c = blobmsg_open_array(&b, "devices");
376         if (!shutdown)
377                 qosify_iface_get_devices(&b);
378         blobmsg_close_array(&b, c);
379 
380         ubus_invoke_async(&conn.ctx, id, "set_blacklist", b.head, &req);
381 }
382 
383 int qosify_ubus_init(void)
384 {
385         conn.cb = ubus_connect_handler;
386         ubus_auto_connect(&conn);
387 
388         return 0;
389 }
390 
391 void qosify_ubus_stop(void)
392 {
393         qosify_ubus_update_bridger(true);
394         ubus_auto_shutdown(&conn);
395 }
396 
397 struct iface_req {
398         char *name;
399         int len;
400 };
401 
402 static void
403 netifd_if_cb(struct ubus_request *req, int type, struct blob_attr *msg)
404 {
405         struct iface_req *ifr = req->priv;
406         enum {
407                 IFS_ATTR_UP,
408                 IFS_ATTR_DEV,
409                 __IFS_ATTR_MAX
410         };
411         static const struct blobmsg_policy policy[__IFS_ATTR_MAX] = {
412                 [IFS_ATTR_UP] = { "up", BLOBMSG_TYPE_BOOL },
413                 [IFS_ATTR_DEV] = { "l3_device", BLOBMSG_TYPE_STRING },
414         };
415         struct blob_attr *tb[__IFS_ATTR_MAX];
416 
417         blobmsg_parse(policy, __IFS_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
418 
419         if (!tb[IFS_ATTR_UP] || !tb[IFS_ATTR_DEV])
420                 return;
421 
422         if (!blobmsg_get_bool(tb[IFS_ATTR_UP]))
423                 return;
424 
425         snprintf(ifr->name, ifr->len, "%s", blobmsg_get_string(tb[IFS_ATTR_DEV]));
426 }
427 
428 int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len)
429 {
430         struct iface_req req = { ifname, ifname_len };
431         char *obj_name = "network.interface.";
432         uint32_t id;
433 
434 #define PREFIX "network.interface."
435         obj_name = alloca(sizeof(PREFIX) + strlen(name) + 1);
436         sprintf(obj_name, PREFIX "%s", name);
437 #undef PREFIX
438 
439         ifname[0] = 0;
440 
441         if (ubus_lookup_id(&conn.ctx, obj_name, &id))
442                 return -1;
443 
444         blob_buf_init(&b, 0);
445         ubus_invoke(&conn.ctx, id, "status", b.head, netifd_if_cb, &req, 1000);
446 
447         if (!ifname[0])
448                 return -1;
449 
450         return 0;
451 }
452 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt