• 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_get_stats(struct ubus_context *ctx, struct ubus_object *obj,
231                       struct ubus_request_data *req, const char *method,
232                       struct blob_attr *msg)
233 {
234         static const struct blobmsg_policy policy =
235                 { "reset", BLOBMSG_TYPE_BOOL };
236         struct blob_attr *tb;
237         bool reset = false;
238 
239         blobmsg_parse(&policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
240 
241         reset = tb && blobmsg_get_u8(tb);
242 
243         blob_buf_init(&b, 0);
244         qosify_map_stats(&b, reset);
245         ubus_send_reply(ctx, req, b.head);
246         blob_buf_free(&b);
247 
248         return 0;
249 }
250 
251 static int
252 qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
253                           struct ubus_request_data *req, const char *method,
254                           struct blob_attr *msg)
255 {
256         qosify_iface_check();
257 
258         return 0;
259 }
260 
261 enum {
262         CL_DNS_HOST_NAME,
263         CL_DNS_HOST_TYPE,
264         CL_DNS_HOST_ADDR,
265         CL_DNS_HOST_TTL,
266         __CL_DNS_HOST_MAX
267 };
268 
269 static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = {
270         [CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING },
271         [CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING },
272         [CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING },
273         [CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 },
274 };
275 
276 static int
277 __qosify_ubus_add_dns_host(struct blob_attr *msg)
278 {
279         struct blob_attr *tb[__CL_DNS_HOST_MAX];
280         struct blob_attr *cur;
281         uint32_t ttl = 0;
282 
283         blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb,
284                       blobmsg_data(msg), blobmsg_len(msg));
285 
286         if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] ||
287             !tb[CL_DNS_HOST_ADDR])
288                 return UBUS_STATUS_INVALID_ARGUMENT;
289 
290         if ((cur = tb[CL_DNS_HOST_TTL]) != NULL)
291                 ttl = blobmsg_get_u32(cur);
292 
293         if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]),
294                                     blobmsg_get_string(tb[CL_DNS_HOST_ADDR]),
295                                     blobmsg_get_string(tb[CL_DNS_HOST_TYPE]),
296                                     ttl))
297                 return UBUS_STATUS_INVALID_ARGUMENT;
298 
299         return 0;
300 }
301 
302 static int
303 qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj,
304                          struct ubus_request_data *req, const char *method,
305                          struct blob_attr *msg)
306 {
307         return __qosify_ubus_add_dns_host(msg);
308 }
309 
310 static const struct ubus_method qosify_methods[] = {
311         UBUS_METHOD_NOARG("reload", qosify_ubus_reload),
312         UBUS_METHOD("add", qosify_ubus_add, qosify_add_policy),
313         UBUS_METHOD_MASK("remove", qosify_ubus_add, qosify_add_policy,
314                          ((1 << __CL_ADD_MAX) - 1) & ~(1 << CL_ADD_DSCP)),
315         UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy),
316         UBUS_METHOD_NOARG("dump", qosify_ubus_dump),
317         UBUS_METHOD_NOARG("status", qosify_ubus_status),
318         UBUS_METHOD_NOARG("get_stats", qosify_ubus_get_stats),
319         UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy),
320         UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices),
321 };
322 
323 static struct ubus_object_type qosify_object_type =
324         UBUS_OBJECT_TYPE("qosify", qosify_methods);
325 
326 static struct ubus_object qosify_object = {
327         .name = "qosify",
328         .type = &qosify_object_type,
329         .methods = qosify_methods,
330         .n_methods = ARRAY_SIZE(qosify_methods),
331 };
332 
333 static void
334 qosify_subscribe_dnsmasq(struct ubus_context *ctx)
335 {
336         static struct ubus_subscriber sub = {
337                 .cb = qosify_ubus_add_dns_host,
338         };
339         uint32_t id;
340 
341         if (!sub.obj.id &&
342             ubus_register_subscriber(ctx, &sub))
343                 return;
344 
345         if (ubus_lookup_id(ctx, "dnsmasq.dns", &id))
346                 return;
347 
348         ubus_subscribe(ctx, &sub, id);
349 }
350 
351 static void
352 qosify_ubus_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
353                      const char *type, struct blob_attr *msg)
354 {
355         static const struct blobmsg_policy policy =
356                 { "path", BLOBMSG_TYPE_STRING };
357         struct blob_attr *attr;
358         const char *path;
359 
360         blobmsg_parse(&policy, 1, &attr, blobmsg_data(msg), blobmsg_len(msg));
361 
362         if (!attr)
363                 return;
364 
365         path = blobmsg_get_string(attr);
366         if (!strcmp(path, "dnsmasq.dns"))
367                 qosify_subscribe_dnsmasq(ctx);
368         else if (!strcmp(path, "bridger"))
369                 qosify_ubus_update_bridger(false);
370 }
371 
372 
373 static void
374 ubus_connect_handler(struct ubus_context *ctx)
375 {
376         static struct ubus_event_handler ev = {
377                 .cb = qosify_ubus_event_cb
378         };
379 
380         ubus_add_object(ctx, &qosify_object);
381         ubus_register_event_handler(ctx, &ev, "ubus.object.add");
382         qosify_subscribe_dnsmasq(ctx);
383 }
384 
385 static struct ubus_auto_conn conn;
386 
387 void qosify_ubus_update_bridger(bool shutdown)
388 {
389         struct ubus_request req;
390         uint32_t id;
391         void *c;
392 
393         if (ubus_lookup_id(&conn.ctx, "bridger", &id))
394                 return;
395 
396         blob_buf_init(&b, 0);
397         blobmsg_add_string(&b, "name", "qosify");
398         c = blobmsg_open_array(&b, "devices");
399         if (!shutdown)
400                 qosify_iface_get_devices(&b);
401         blobmsg_close_array(&b, c);
402 
403         ubus_invoke_async(&conn.ctx, id, "set_blacklist", b.head, &req);
404 }
405 
406 int qosify_ubus_init(void)
407 {
408         conn.cb = ubus_connect_handler;
409         ubus_auto_connect(&conn);
410 
411         return 0;
412 }
413 
414 void qosify_ubus_stop(void)
415 {
416         qosify_ubus_update_bridger(true);
417         ubus_auto_shutdown(&conn);
418 }
419 
420 struct iface_req {
421         char *name;
422         int len;
423 };
424 
425 static void
426 netifd_if_cb(struct ubus_request *req, int type, struct blob_attr *msg)
427 {
428         struct iface_req *ifr = req->priv;
429         enum {
430                 IFS_ATTR_UP,
431                 IFS_ATTR_DEV,
432                 __IFS_ATTR_MAX
433         };
434         static const struct blobmsg_policy policy[__IFS_ATTR_MAX] = {
435                 [IFS_ATTR_UP] = { "up", BLOBMSG_TYPE_BOOL },
436                 [IFS_ATTR_DEV] = { "l3_device", BLOBMSG_TYPE_STRING },
437         };
438         struct blob_attr *tb[__IFS_ATTR_MAX];
439 
440         blobmsg_parse(policy, __IFS_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
441 
442         if (!tb[IFS_ATTR_UP] || !tb[IFS_ATTR_DEV])
443                 return;
444 
445         if (!blobmsg_get_bool(tb[IFS_ATTR_UP]))
446                 return;
447 
448         snprintf(ifr->name, ifr->len, "%s", blobmsg_get_string(tb[IFS_ATTR_DEV]));
449 }
450 
451 int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len)
452 {
453         struct iface_req req = { ifname, ifname_len };
454         char *obj_name = "network.interface.";
455         uint32_t id;
456 
457 #define PREFIX "network.interface."
458         obj_name = alloca(sizeof(PREFIX) + strlen(name) + 1);
459         sprintf(obj_name, PREFIX "%s", name);
460 #undef PREFIX
461 
462         ifname[0] = 0;
463 
464         if (ubus_lookup_id(&conn.ctx, obj_name, &id))
465                 return -1;
466 
467         blob_buf_init(&b, 0);
468         ubus_invoke(&conn.ctx, id, "status", b.head, netifd_if_cb, &req, 1000);
469 
470         if (!ifname[0])
471                 return -1;
472 
473         return 0;
474 }
475 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt