3 #include <sys/select.h>
6 #include <libubox/blob.h>
7 #include <libubox/blobmsg.h>
8 #include <libubox/list.h>
10 #include <arpa/inet.h>
12 #include <netinet/in.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
17 #include "configuration.h"
18 #include "interface.h"
22 #include "neighbour.h"
34 // Definition of header variable whether to enable ubus bindings.
35 int ubus_bindings
= 0;
37 // Shared state maintained throughout calls to handle ubus messages.
38 static struct ubus_context
*shared_ctx
;
40 // List of exported routes (to be used with ubox's list helpers).
41 struct xroute_list_entry
{
42 struct list_head list
;
43 struct xroute
*xroute
;
46 // List of received routes (to be used with ubox's list helpers).
47 struct route_list_entry
{
48 struct list_head list
;
49 struct babel_route
*route
;
52 // List of neighbours (to be used with ubox's list helpers).
53 struct neighbour_list_entry
{
54 struct list_head list
;
55 struct neighbour
*neighbour
;
58 // Sends a babel info message on ubus socket.
59 static int babeld_ubus_babeld_info(struct ubus_context
*ctx_local
,
60 struct ubus_object
*obj
,
61 struct ubus_request_data
*req
,
62 const char *method
, struct blob_attr
*msg
) {
63 struct blob_buf b
= {0};
69 blobmsg_add_string(&b
, "babeld-version", BABELD_VERSION
);
70 blobmsg_add_string(&b
, "my-id", format_eui64(myid
));
71 if (!gethostname(host
, sizeof(host
)))
72 blobmsg_add_string(&b
, "host", host
);
74 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
76 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
81 // Appends an exported route message entry to the buffer.
82 static void babeld_add_xroute_buf(struct xroute
*xroute
, struct blob_buf
*b
) {
85 prefix
= blobmsg_open_table(b
, format_prefix(xroute
->prefix
, xroute
->plen
));
87 blobmsg_add_string(b
, "src-prefix",
88 format_prefix(xroute
->src_prefix
, xroute
->src_plen
));
89 blobmsg_add_u32(b
, "metric", xroute
->metric
);
90 blobmsg_close_table(b
, prefix
);
93 // Sends an exported routes message on ubus socket, splitting apart IPv4 and
95 static int babeld_ubus_get_xroutes(struct ubus_context
*ctx_local
,
96 struct ubus_object
*obj
,
97 struct ubus_request_data
*req
,
98 const char *method
, struct blob_attr
*msg
) {
99 struct blob_buf b
= {0};
100 struct xroute_stream
*xroutes
;
101 struct xroute_list_entry
*cur
, *tmp
;
104 LIST_HEAD(xroute_ipv4_list
);
105 LIST_HEAD(xroute_ipv6_list
);
107 xroutes
= xroute_stream();
110 struct xroute
*xroute
= xroute_stream_next(xroutes
);
114 struct xroute_list_entry
*xr
=
115 calloc(1, sizeof(struct xroute_list_entry
));
118 if (v4mapped(xroute
->prefix
)) {
119 list_add(&xr
->list
, &xroute_ipv4_list
);
121 list_add(&xr
->list
, &xroute_ipv6_list
);
124 xroute_stream_done(xroutes
);
127 blob_buf_init(&b
, 0);
128 ipv4
= blobmsg_open_table(&b
, "IPv4");
129 list_for_each_entry_safe(cur
, tmp
, &xroute_ipv4_list
, list
) {
130 babeld_add_xroute_buf(cur
->xroute
, &b
);
131 list_del(&cur
->list
);
134 blobmsg_close_table(&b
, ipv4
);
136 ipv6
= blobmsg_open_table(&b
, "IPv6");
137 list_for_each_entry_safe(cur
, tmp
, &xroute_ipv6_list
, list
) {
138 babeld_add_xroute_buf(cur
->xroute
, &b
);
139 list_del(&cur
->list
);
142 blobmsg_close_table(&b
, ipv6
);
144 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
146 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
151 // Appends an route message entry to the buffer.
152 static void babeld_add_route_buf(struct babel_route
*route
,
153 struct blob_buf
*b
) {
157 if (route
->channels_len
== 0) {
161 snprintf(channels
, sizeof(channels
), " chan (");
162 j
= strlen(channels
);
163 for (i
= 0; i
< route
->channels_len
; i
++) {
166 snprintf(channels
+ j
, sizeof(channels
) - j
, "%u",
167 (unsigned)route
->channels
[i
]);
168 j
= strlen(channels
);
170 snprintf(channels
+ j
, sizeof(channels
) - j
, ")");
173 prefix
= blobmsg_open_table(
174 b
, format_prefix(route
->src
->prefix
, route
->src
->plen
));
178 format_prefix(route
->src
->src_prefix
, route
->src
->src_plen
));
179 blobmsg_add_u32(b
, "route_metric", route_metric(route
));
180 blobmsg_add_u32(b
, "route_smoothed_metric", route_smoothed_metric(route
));
181 blobmsg_add_u32(b
, "refmetric", route
->refmetric
);
182 blobmsg_add_string(b
, "id", format_eui64(route
->src
->id
));
183 blobmsg_add_u32(b
, "seqno", (uint32_t)route
->seqno
);
184 blobmsg_add_string(b
, "channels", channels
);
185 blobmsg_add_u32(b
, "age", (int)(now
.tv_sec
- route
->time
));
186 blobmsg_add_string(b
, "via", format_address(route
->neigh
->address
));
187 if (memcmp(route
->nexthop
, route
->neigh
->address
, 16) != 0)
188 blobmsg_add_string(b
, "nexthop", format_address(route
->nexthop
));
190 blobmsg_add_u8(b
, "installed", route
->installed
);
191 blobmsg_add_u8(b
, "feasible", route_feasible(route
));
193 blobmsg_close_table(b
, prefix
);
196 // Sends received routes message on ubus socket, splitting apart IPv4 and IPv6
198 static int babeld_ubus_get_routes(struct ubus_context
*ctx_local
,
199 struct ubus_object
*obj
,
200 struct ubus_request_data
*req
,
201 const char *method
, struct blob_attr
*msg
) {
202 struct blob_buf b
= {0};
203 struct route_stream
*routes
;
204 struct route_list_entry
*cur
, *tmp
;
205 void *prefix
, *ipv4
, *ipv6
;
207 LIST_HEAD(route_ipv4_list
);
208 LIST_HEAD(route_ipv6_list
);
210 blob_buf_init(&b
, 0);
212 routes
= route_stream(ROUTE_ALL
);
215 struct babel_route
*route
= route_stream_next(routes
);
218 struct route_list_entry
*r
= calloc(1, sizeof(struct route_list_entry
));
221 if (v4mapped(route
->src
->prefix
)) {
222 list_add(&r
->list
, &route_ipv4_list
);
224 list_add(&r
->list
, &route_ipv6_list
);
227 route_stream_done(routes
);
230 blob_buf_init(&b
, 0);
231 ipv4
= blobmsg_open_table(&b
, "IPv4");
232 list_for_each_entry_safe(cur
, tmp
, &route_ipv4_list
, list
) {
233 babeld_add_route_buf(cur
->route
, &b
);
234 list_del(&cur
->list
);
237 blobmsg_close_table(&b
, ipv4
);
239 ipv6
= blobmsg_open_table(&b
, "IPv6");
240 list_for_each_entry_safe(cur
, tmp
, &route_ipv6_list
, list
) {
241 babeld_add_route_buf(cur
->route
, &b
);
242 list_del(&cur
->list
);
245 blobmsg_close_table(&b
, ipv6
);
247 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
249 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
254 // Appends an neighbour entry to the buffer.
255 static void babeld_add_neighbour_buf(struct neighbour
*neigh
,
256 struct blob_buf
*b
) {
259 neighbour
= blobmsg_open_table(b
, format_address(neigh
->address
));
260 blobmsg_add_string(b
, "dev", neigh
->ifp
->name
);
261 blobmsg_add_u32(b
, "hello-reach", neigh
->hello
.reach
);
262 blobmsg_add_u32(b
, "uhello-reach", neigh
->uhello
.reach
);
263 blobmsg_add_u32(b
, "rxcost", neighbour_rxcost(neigh
));
264 blobmsg_add_u32(b
, "txcost", neigh
->txcost
);
265 blobmsg_add_string(b
, "rtt", format_thousands(neigh
->rtt
));
266 blobmsg_add_u32(b
, "channel", neigh
->ifp
->channel
);
267 blobmsg_add_u8(b
, "if_up", if_up(neigh
->ifp
));
268 blobmsg_close_table(b
, neighbour
);
271 // Sends neighbours message on ubus socket, splitting apart IPv4 and IPv6
273 static int babeld_ubus_get_neighbours(struct ubus_context
*ctx_local
,
274 struct ubus_object
*obj
,
275 struct ubus_request_data
*req
,
277 struct blob_attr
*msg
) {
278 struct blob_buf b
= {0};
279 struct neighbour
*neigh
;
280 struct neighbour_list_entry
*cur
, *tmp
;
283 LIST_HEAD(neighbour_ipv4_list
);
284 LIST_HEAD(neighbour_ipv6_list
);
286 blob_buf_init(&b
, 0);
288 FOR_ALL_NEIGHBOURS(neigh
) {
289 struct neighbour_list_entry
*n
=
290 calloc(1, sizeof(struct neighbour_list_entry
));
291 n
->neighbour
= neigh
;
292 if (v4mapped(neigh
->address
)) {
293 list_add(&n
->list
, &neighbour_ipv4_list
);
295 list_add(&n
->list
, &neighbour_ipv6_list
);
299 blob_buf_init(&b
, 0);
301 ipv4
= blobmsg_open_table(&b
, "IPv4");
302 list_for_each_entry_safe(cur
, tmp
, &neighbour_ipv4_list
, list
) {
303 babeld_add_neighbour_buf(cur
->neighbour
, &b
);
304 list_del(&cur
->list
);
307 blobmsg_close_table(&b
, ipv4
);
309 ipv6
= blobmsg_open_table(&b
, "IPv6");
310 list_for_each_entry_safe(cur
, tmp
, &neighbour_ipv6_list
, list
) {
311 babeld_add_neighbour_buf(cur
->neighbour
, &b
);
312 list_del(&cur
->list
);
315 blobmsg_close_table(&b
, ipv6
);
317 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
319 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
324 // List of functions we expose via the ubus bus.
325 static const struct ubus_method babeld_methods
[] = {
326 UBUS_METHOD_NOARG("get_info", babeld_ubus_babeld_info
),
327 UBUS_METHOD_NOARG("get_xroutes", babeld_ubus_get_xroutes
),
328 UBUS_METHOD_NOARG("get_routes", babeld_ubus_get_routes
),
329 UBUS_METHOD_NOARG("get_neighbours", babeld_ubus_get_neighbours
),
332 // Definition of the ubus object type.
333 static struct ubus_object_type babeld_object_type
=
334 UBUS_OBJECT_TYPE("babeld", babeld_methods
);
336 // Object we announce via the ubus bus.
337 static struct ubus_object babeld_object
= {
339 .type
= &babeld_object_type
,
340 .methods
= babeld_methods
,
341 .n_methods
= ARRAY_SIZE(babeld_methods
),
344 // Registers handlers for babel methods in the global ubus context.
345 static bool ubus_init_object() {
348 ret
= ubus_add_object(shared_ctx
, &babeld_object
);
350 fprintf(stderr
, "Failed to add object: %s\n", ubus_strerror(ret
));
357 // Initializes the global ubus context, connecting to the bus to be able to
358 // receive and send messages.
359 static bool babeld_ubus_init(void) {
363 shared_ctx
= ubus_connect(NULL
);
370 void ubus_notify_route(struct babel_route
*route
, int kind
) {
371 struct blob_buf b
= {0};
372 char method
[50]; // possible methods are route.change, route.add, route.flush
374 if (!babeld_object
.has_subscribers
)
383 blob_buf_init(&b
, 0);
384 babeld_add_route_buf(route
, &b
);
385 snprintf(method
, sizeof(method
), "route.%s", local_kind(kind
));
386 ubus_notify(shared_ctx
, &babeld_object
, method
, b
.head
, -1);
389 void ubus_notify_xroute(struct xroute
*xroute
, int kind
) {
390 struct blob_buf b
= {0};
391 char method
[50]; // possible methods are xroute.change, xroute.add,
394 if (!babeld_object
.has_subscribers
)
403 blob_buf_init(&b
, 0);
404 babeld_add_xroute_buf(xroute
, &b
);
405 snprintf(method
, sizeof(method
), "xroute.%s", local_kind(kind
));
406 ubus_notify(shared_ctx
, &babeld_object
, method
, b
.head
, -1);
409 void ubus_notify_neighbour(struct neighbour
*neigh
, int kind
) {
410 struct blob_buf b
= {0};
411 char method
[50]; // possible methods are neigh.change, neigh.add, neigh.flush
413 if (!babeld_object
.has_subscribers
)
422 blob_buf_init(&b
, 0);
423 babeld_add_neighbour_buf(neigh
, &b
);
424 snprintf(method
, sizeof(method
), "neigh.%s", local_kind(kind
));
425 ubus_notify(shared_ctx
, &babeld_object
, method
, b
.head
, -1);
428 void babeld_ubus_receive(fd_set
*readfds
) {
431 if (FD_ISSET(shared_ctx
->sock
.fd
, readfds
))
432 ubus_handle_event(shared_ctx
);
435 int babeld_ubus_add_read_sock(fd_set
*readfds
, int maxfd
) {
439 FD_SET(shared_ctx
->sock
.fd
, readfds
);
440 return MAX(maxfd
, shared_ctx
->sock
.fd
);
443 bool babeld_add_ubus() {
444 if (!babeld_ubus_init()) {
445 fprintf(stderr
, "Failed to initialize ubus!\n");
449 if (!ubus_init_object()) {
450 fprintf(stderr
, "Failed to add objects to ubus!\n");