1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
9 static struct blob_buf b
;
12 qosify_ubus_add_array(struct blob_attr
*attr
, uint8_t val
, enum qosify_map_id id
)
14 struct blob_attr
*cur
;
17 if (blobmsg_check_array(attr
, BLOBMSG_TYPE_STRING
) < 0)
18 return UBUS_STATUS_INVALID_ARGUMENT
;
20 blobmsg_for_each_attr(cur
, attr
, rem
)
21 qosify_map_set_entry(id
, false, blobmsg_get_string(cur
), val
);
27 qosify_ubus_set_files(struct blob_attr
*attr
)
29 struct blob_attr
*cur
;
32 if (blobmsg_check_array(attr
, BLOBMSG_TYPE_STRING
) < 0)
33 return UBUS_STATUS_INVALID_ARGUMENT
;
35 qosify_map_clear_files();
37 blobmsg_for_each_attr(cur
, attr
, rem
)
38 qosify_map_load_file(blobmsg_get_string(cur
));
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
},
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
)
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
)
83 int prev_timemout
= qosify_map_timeout
;
84 struct blob_attr
*tb
[__CL_ADD_MAX
];
85 struct blob_attr
*cur
;
89 blobmsg_parse(qosify_add_policy
, __CL_ADD_MAX
, tb
,
90 blobmsg_data(msg
), blobmsg_len(msg
));
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
;
97 if ((cur
= tb
[CL_ADD_TIMEOUT
]) != NULL
)
98 qosify_map_timeout
= blobmsg_get_u32(cur
);
101 if ((cur
= tb
[CL_ADD_IPV4
]) != NULL
&&
102 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_IPV4_ADDR
) != 0))
105 if ((cur
= tb
[CL_ADD_IPV6
]) != NULL
&&
106 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_IPV6_ADDR
) != 0))
109 if ((cur
= tb
[CL_ADD_TCP_PORT
]) != NULL
&&
110 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_TCP_PORTS
) != 0))
113 if ((cur
= tb
[CL_ADD_UDP_PORT
]) != NULL
&&
114 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_UDP_PORTS
) != 0))
117 if ((cur
= tb
[CL_ADD_DNS
]) != NULL
&&
118 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_DNS
) != 0))
121 qosify_map_timeout
= prev_timemout
;
133 CL_CONFIG_INTERFACES
,
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
},
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
)
156 struct blob_attr
*tb
[__CL_CONFIG_MAX
];
157 struct blob_attr
*cur
;
162 blobmsg_parse(qosify_config_policy
, __CL_CONFIG_MAX
, tb
,
163 blobmsg_data(msg
), blobmsg_len(msg
));
165 if ((cur
= tb
[CL_CONFIG_RESET
]) != NULL
)
166 reset
= blobmsg_get_bool(cur
);
169 qosify_map_reset_config();
171 if ((cur
= tb
[CL_CONFIG_CLASSES
]) != NULL
|| reset
)
172 qosify_map_set_classes(cur
);
174 if ((cur
= tb
[CL_CONFIG_TIMEOUT
]) != NULL
)
175 qosify_map_timeout
= blobmsg_get_u32(cur
);
177 if ((cur
= tb
[CL_CONFIG_FILES
]) != NULL
&&
178 (ret
= qosify_ubus_set_files(cur
) != 0))
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
;
185 map_fill_dscp_value(&dscp
, tb
[CL_CONFIG_DSCP_UDP
], true);
187 qosify_map_set_dscp_default(CL_MAP_UDP_PORTS
, dscp
);
189 map_fill_dscp_value(&dscp
, tb
[CL_CONFIG_DSCP_TCP
], true);
191 qosify_map_set_dscp_default(CL_MAP_TCP_PORTS
, dscp
);
193 qosify_map_update_config();
195 qosify_iface_config_update(tb
[CL_CONFIG_INTERFACES
], tb
[CL_CONFIG_DEVICES
]);
197 qosify_iface_check();
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
)
208 blob_buf_init(&b
, 0);
210 ubus_send_reply(ctx
, req
, b
.head
);
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
)
221 blob_buf_init(&b
, 0);
222 qosify_iface_status(&b
);
223 ubus_send_reply(ctx
, req
, b
.head
);
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
)
234 qosify_iface_check();
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
},
255 __qosify_ubus_add_dns_host(struct blob_attr
*msg
)
257 struct blob_attr
*tb
[__CL_DNS_HOST_MAX
];
258 struct blob_attr
*cur
;
261 blobmsg_parse(qosify_dns_policy
, __CL_DNS_HOST_MAX
, tb
,
262 blobmsg_data(msg
), blobmsg_len(msg
));
264 if (!tb
[CL_DNS_HOST_NAME
] || !tb
[CL_DNS_HOST_TYPE
] ||
265 !tb
[CL_DNS_HOST_ADDR
])
266 return UBUS_STATUS_INVALID_ARGUMENT
;
268 if ((cur
= tb
[CL_DNS_HOST_TTL
]) != NULL
)
269 ttl
= blobmsg_get_u32(cur
);
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
]),
275 return UBUS_STATUS_INVALID_ARGUMENT
;
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
)
285 return __qosify_ubus_add_dns_host(msg
);
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
),
300 static struct ubus_object_type qosify_object_type
=
301 UBUS_OBJECT_TYPE("qosify", qosify_methods
);
303 static struct ubus_object qosify_object
= {
305 .type
= &qosify_object_type
,
306 .methods
= qosify_methods
,
307 .n_methods
= ARRAY_SIZE(qosify_methods
),
311 ubus_connect_handler(struct ubus_context
*ctx
)
313 ubus_add_object(ctx
, &qosify_object
);
316 static struct ubus_auto_conn conn
;
318 int qosify_ubus_init(void)
320 conn
.cb
= ubus_connect_handler
;
321 ubus_auto_connect(&conn
);
326 void qosify_ubus_stop(void)
328 ubus_auto_shutdown(&conn
);
337 netifd_if_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
339 struct iface_req
*ifr
= req
->priv
;
345 static const struct blobmsg_policy policy
[__IFS_ATTR_MAX
] = {
346 [IFS_ATTR_UP
] = { "up", BLOBMSG_TYPE_BOOL
},
347 [IFS_ATTR_DEV
] = { "l3_device", BLOBMSG_TYPE_STRING
},
349 struct blob_attr
*tb
[__IFS_ATTR_MAX
];
351 blobmsg_parse(policy
, __IFS_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_len(msg
));
353 if (!tb
[IFS_ATTR_UP
] || !tb
[IFS_ATTR_DEV
])
356 if (!blobmsg_get_bool(tb
[IFS_ATTR_UP
]))
359 snprintf(ifr
->name
, ifr
->len
, "%s", blobmsg_get_string(tb
[IFS_ATTR_DEV
]));
362 int qosify_ubus_check_interface(const char *name
, char *ifname
, int ifname_len
)
364 struct iface_req req
= { ifname
, ifname_len
};
365 char *obj_name
= "network.interface.";
368 #define PREFIX "network.interface."
369 obj_name
= alloca(sizeof(PREFIX
) + strlen(name
) + 1);
370 sprintf(obj_name
, PREFIX
"%s", name
);
375 if (ubus_lookup_id(&conn
.ctx
, obj_name
, &id
))
378 blob_buf_init(&b
, 0);
379 ubus_invoke(&conn
.ctx
, id
, "status", b
.head
, netifd_if_cb
, &req
, 1000);