3 #include <sys/select.h>
5 #include <libubox/blob.h>
6 #include <libubox/blobmsg.h>
7 #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"
33 // Definition of header variable whether to enable ubus bindings.
34 int ubus_bindings
= 0;
36 // Shared state maintained throughout calls to handle ubus messages.
37 static struct ubus_context
*shared_ctx
;
39 // List of exported routes (to be used with ubox's list helpers).
40 struct xroute_list_entry
{
41 struct list_head list
;
42 struct xroute
*xroute
;
45 // List of received routes (to be used with ubox's list helpers).
46 struct route_list_entry
{
47 struct list_head list
;
48 struct babel_route
*route
;
51 // List of neighbours (to be used with ubox's list helpers).
52 struct neighbour_list_entry
{
53 struct list_head list
;
54 struct neighbour
*neighbour
;
57 // Definition of interface function enums (to be used with ubox's blobmsg
59 enum { INTERFACE_IFNAME
, __INTERFACE_MAX
};
61 // Definition of interface parsing (to be used with ubox's blobmsg helpers).
62 static const struct blobmsg_policy interface_policy
[__INTERFACE_MAX
] = {
63 [INTERFACE_IFNAME
] = {"ifname", BLOBMSG_TYPE_STRING
},
66 // Definition of filter function enums (to be used with ubox's blobmsg
68 enum { FILTER_IFNAME
, FILTER_TYPE
, FILTER_METRIC
, __FILTER_MAX
};
70 // Definition of filter parsing (to be used with ubox's blobmsg helpers).
71 static const struct blobmsg_policy filter_policy
[__FILTER_MAX
] = {
72 [FILTER_IFNAME
] = {"ifname", BLOBMSG_TYPE_STRING
},
73 [FILTER_TYPE
] = {"type", BLOBMSG_TYPE_INT32
},
74 [FILTER_METRIC
] = {"metric", BLOBMSG_TYPE_INT32
},
77 // Adds a filter (ubus equivalent to "filter"-function).
78 static int babeld_ubus_add_filter(struct ubus_context
*ctx_local
,
79 struct ubus_object
*obj
,
80 struct ubus_request_data
*req
,
81 const char *method
, struct blob_attr
*msg
) {
82 struct blob_attr
*tb
[__FILTER_MAX
];
83 struct blob_buf b
= {0};
84 struct filter
*filter
= NULL
;
88 blobmsg_parse(filter_policy
, __FILTER_MAX
, tb
, blob_data(msg
), blob_len(msg
));
90 if (!tb
[FILTER_IFNAME
])
91 return UBUS_STATUS_INVALID_ARGUMENT
;
94 return UBUS_STATUS_INVALID_ARGUMENT
;
96 type
= blobmsg_get_u32(tb
[FILTER_TYPE
]);
98 if (tb
[FILTER_METRIC
])
99 metric
= blobmsg_get_u32(tb
[FILTER_METRIC
]);
101 filter
= calloc(1, sizeof(struct filter
));
103 return UBUS_STATUS_UNKNOWN_ERROR
;
105 filter
->af
= AF_INET6
;
107 filter
->plen_le
= 128;
108 filter
->src_plen_le
= 128;
109 filter
->action
.add_metric
= metric
;
111 ifname
= blobmsg_get_string(tb
[FILTER_IFNAME
]);
112 filter
->ifname
= strdup(ifname
);
113 filter
->ifindex
= if_nametoindex(filter
->ifname
);
115 add_filter(filter
, type
);
117 return UBUS_STATUS_OK
;
120 // Adds an inteface (ubus equivalent to "interface"-function).
121 static int babeld_ubus_add_interface(struct ubus_context
*ctx_local
,
122 struct ubus_object
*obj
,
123 struct ubus_request_data
*req
,
125 struct blob_attr
*msg
) {
126 struct blob_attr
*tb
[__INTERFACE_MAX
];
127 struct blob_buf b
= {0};
128 struct interface
*ifp
= NULL
;
131 blobmsg_parse(interface_policy
, __INTERFACE_MAX
, tb
, blob_data(msg
),
134 if (!tb
[INTERFACE_IFNAME
])
135 return UBUS_STATUS_INVALID_ARGUMENT
;
137 ifname
= blobmsg_get_string(tb
[INTERFACE_IFNAME
]);
139 ifp
= add_interface(ifname
, NULL
);
141 return UBUS_STATUS_UNKNOWN_ERROR
;
143 return UBUS_STATUS_OK
;
146 // Sends a babel info message on ubus socket.
147 static int babeld_ubus_babeld_info(struct ubus_context
*ctx_local
,
148 struct ubus_object
*obj
,
149 struct ubus_request_data
*req
,
150 const char *method
, struct blob_attr
*msg
) {
151 struct blob_buf b
= {0};
156 blob_buf_init(&b
, 0);
157 blobmsg_add_string(&b
, "babeld-version", BABELD_VERSION
);
158 blobmsg_add_string(&b
, "my-id", format_eui64(myid
));
159 if (!gethostname(host
, sizeof(host
)))
160 blobmsg_add_string(&b
, "host", host
);
162 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
164 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
171 // Appends an exported route message entry to the buffer.
172 static void babeld_add_xroute_buf(struct xroute
*xroute
, struct blob_buf
*b
) {
175 prefix
= blobmsg_open_table(b
, format_prefix(xroute
->prefix
, xroute
->plen
));
177 blobmsg_add_string(b
, "src-prefix",
178 format_prefix(xroute
->src_prefix
, xroute
->src_plen
));
179 blobmsg_add_u32(b
, "metric", xroute
->metric
);
180 blobmsg_close_table(b
, prefix
);
183 // Sends an exported routes message on ubus socket, splitting apart IPv4 and
185 static int babeld_ubus_get_xroutes(struct ubus_context
*ctx_local
,
186 struct ubus_object
*obj
,
187 struct ubus_request_data
*req
,
188 const char *method
, struct blob_attr
*msg
) {
189 struct blob_buf b
= {0};
190 struct xroute_stream
*xroutes
;
191 struct xroute_list_entry
*cur
, *tmp
;
194 LIST_HEAD(xroute_ipv4_list
);
195 LIST_HEAD(xroute_ipv6_list
);
197 blob_buf_init(&b
, 0);
199 xroutes
= xroute_stream();
202 struct xroute
*xroute
= xroute_stream_next(xroutes
);
206 struct xroute_list_entry
*xr
=
207 calloc(1, sizeof(struct xroute_list_entry
));
210 if (v4mapped(xroute
->prefix
)) {
211 list_add(&xr
->list
, &xroute_ipv4_list
);
213 list_add(&xr
->list
, &xroute_ipv6_list
);
216 xroute_stream_done(xroutes
);
219 ipv4
= blobmsg_open_table(&b
, "IPv4");
220 list_for_each_entry_safe(cur
, tmp
, &xroute_ipv4_list
, list
) {
221 babeld_add_xroute_buf(cur
->xroute
, &b
);
222 list_del(&cur
->list
);
225 blobmsg_close_table(&b
, ipv4
);
227 ipv6
= blobmsg_open_table(&b
, "IPv6");
228 list_for_each_entry_safe(cur
, tmp
, &xroute_ipv6_list
, list
) {
229 babeld_add_xroute_buf(cur
->xroute
, &b
);
230 list_del(&cur
->list
);
233 blobmsg_close_table(&b
, ipv6
);
235 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
237 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
244 // Appends an route message entry to the buffer.
245 static void babeld_add_route_buf(struct babel_route
*route
,
246 struct blob_buf
*b
) {
250 if (route
->channels_len
== 0) {
254 snprintf(channels
, sizeof(channels
), " chan (");
255 j
= strlen(channels
);
256 for (i
= 0; i
< route
->channels_len
; i
++) {
259 snprintf(channels
+ j
, sizeof(channels
) - j
, "%u",
260 (unsigned)route
->channels
[i
]);
261 j
= strlen(channels
);
263 snprintf(channels
+ j
, sizeof(channels
) - j
, ")");
266 prefix
= blobmsg_open_table(
267 b
, format_prefix(route
->src
->prefix
, route
->src
->plen
));
271 format_prefix(route
->src
->src_prefix
, route
->src
->src_plen
));
272 blobmsg_add_u32(b
, "route_metric", route_metric(route
));
273 blobmsg_add_u32(b
, "route_smoothed_metric", route_smoothed_metric(route
));
274 blobmsg_add_u32(b
, "refmetric", route
->refmetric
);
275 blobmsg_add_string(b
, "id", format_eui64(route
->src
->id
));
276 blobmsg_add_u32(b
, "seqno", (uint32_t)route
->seqno
);
277 blobmsg_add_string(b
, "channels", channels
);
278 blobmsg_add_u32(b
, "age", (int)(now
.tv_sec
- route
->time
));
279 blobmsg_add_string(b
, "via", format_address(route
->neigh
->address
));
280 if (memcmp(route
->nexthop
, route
->neigh
->address
, 16) != 0)
281 blobmsg_add_string(b
, "nexthop", format_address(route
->nexthop
));
283 blobmsg_add_u8(b
, "installed", route
->installed
);
284 blobmsg_add_u8(b
, "feasible", route_feasible(route
));
286 blobmsg_close_table(b
, prefix
);
289 // Sends received routes message on ubus socket, splitting apart IPv4 and IPv6
291 static int babeld_ubus_get_routes(struct ubus_context
*ctx_local
,
292 struct ubus_object
*obj
,
293 struct ubus_request_data
*req
,
294 const char *method
, struct blob_attr
*msg
) {
295 struct blob_buf b
= {0};
296 struct route_stream
*routes
;
297 struct route_list_entry
*cur
, *tmp
;
298 void *prefix
, *ipv4
, *ipv6
;
300 LIST_HEAD(route_ipv4_list
);
301 LIST_HEAD(route_ipv6_list
);
303 blob_buf_init(&b
, 0);
305 routes
= route_stream(0);
308 struct babel_route
*route
= route_stream_next(routes
);
311 struct route_list_entry
*r
= calloc(1, sizeof(struct route_list_entry
));
314 if (v4mapped(route
->src
->prefix
)) {
315 list_add(&r
->list
, &route_ipv4_list
);
317 list_add(&r
->list
, &route_ipv6_list
);
320 route_stream_done(routes
);
323 ipv4
= blobmsg_open_table(&b
, "IPv4");
324 list_for_each_entry_safe(cur
, tmp
, &route_ipv4_list
, list
) {
325 babeld_add_route_buf(cur
->route
, &b
);
326 list_del(&cur
->list
);
329 blobmsg_close_table(&b
, ipv4
);
331 ipv6
= blobmsg_open_table(&b
, "IPv6");
332 list_for_each_entry_safe(cur
, tmp
, &route_ipv6_list
, list
) {
333 babeld_add_route_buf(cur
->route
, &b
);
334 list_del(&cur
->list
);
337 blobmsg_close_table(&b
, ipv6
);
339 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
341 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
348 // Appends an neighbour entry to the buffer.
349 static void babeld_add_neighbour_buf(struct neighbour
*neigh
,
350 struct blob_buf
*b
) {
353 neighbour
= blobmsg_open_table(b
, format_address(neigh
->address
));
354 blobmsg_add_string(b
, "dev", neigh
->ifp
->name
);
355 blobmsg_add_u32(b
, "hello-reach", neigh
->hello
.reach
);
356 blobmsg_add_u32(b
, "uhello-reach", neigh
->uhello
.reach
);
357 blobmsg_add_u32(b
, "rxcost", neighbour_rxcost(neigh
));
358 blobmsg_add_u32(b
, "txcost", neigh
->txcost
);
359 blobmsg_add_string(b
, "rtt", format_thousands(neigh
->rtt
));
360 blobmsg_add_u32(b
, "channel", neigh
->ifp
->channel
);
361 blobmsg_add_u8(b
, "if_up", if_up(neigh
->ifp
));
362 blobmsg_close_table(b
, neighbour
);
365 // Sends neighbours message on ubus socket, splitting apart IPv4 and IPv6
367 static int babeld_ubus_get_neighbours(struct ubus_context
*ctx_local
,
368 struct ubus_object
*obj
,
369 struct ubus_request_data
*req
,
371 struct blob_attr
*msg
) {
372 struct blob_buf b
= {0};
373 struct neighbour
*neigh
;
374 struct neighbour_list_entry
*cur
, *tmp
;
377 LIST_HEAD(neighbour_ipv4_list
);
378 LIST_HEAD(neighbour_ipv6_list
);
380 blob_buf_init(&b
, 0);
382 FOR_ALL_NEIGHBOURS(neigh
) {
383 struct neighbour_list_entry
*n
=
384 calloc(1, sizeof(struct neighbour_list_entry
));
385 n
->neighbour
= neigh
;
386 if (v4mapped(neigh
->address
)) {
387 list_add(&n
->list
, &neighbour_ipv4_list
);
389 list_add(&n
->list
, &neighbour_ipv6_list
);
393 ipv4
= blobmsg_open_table(&b
, "IPv4");
394 list_for_each_entry_safe(cur
, tmp
, &neighbour_ipv4_list
, list
) {
395 babeld_add_neighbour_buf(cur
->neighbour
, &b
);
396 list_del(&cur
->list
);
399 blobmsg_close_table(&b
, ipv4
);
401 ipv6
= blobmsg_open_table(&b
, "IPv6");
402 list_for_each_entry_safe(cur
, tmp
, &neighbour_ipv6_list
, list
) {
403 babeld_add_neighbour_buf(cur
->neighbour
, &b
);
404 list_del(&cur
->list
);
407 blobmsg_close_table(&b
, ipv6
);
409 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
411 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
418 // List of functions we expose via the ubus bus.
419 static const struct ubus_method babeld_methods
[] = {
420 UBUS_METHOD("add_interface", babeld_ubus_add_interface
, interface_policy
),
421 UBUS_METHOD("add_filter", babeld_ubus_add_filter
, filter_policy
),
422 UBUS_METHOD_NOARG("get_info", babeld_ubus_babeld_info
),
423 UBUS_METHOD_NOARG("get_xroutes", babeld_ubus_get_xroutes
),
424 UBUS_METHOD_NOARG("get_routes", babeld_ubus_get_routes
),
425 UBUS_METHOD_NOARG("get_neighbours", babeld_ubus_get_neighbours
),
428 // Definition of the ubus object type.
429 static struct ubus_object_type babeld_object_type
=
430 UBUS_OBJECT_TYPE("babeld", babeld_methods
);
432 // Object we announce via the ubus bus.
433 static struct ubus_object babeld_object
= {
435 .type
= &babeld_object_type
,
436 .methods
= babeld_methods
,
437 .n_methods
= ARRAY_SIZE(babeld_methods
),
440 // Registers handlers for babel methods in the global ubus context.
441 static bool ubus_init_object() {
444 ret
= ubus_add_object(shared_ctx
, &babeld_object
);
446 fprintf(stderr
, "Failed to add object: %s\n", ubus_strerror(ret
));
453 // Initializes the global ubus context, connecting to the bus to be able to
454 // receive and send messages.
455 static bool babeld_ubus_init(void) {
459 shared_ctx
= ubus_connect(NULL
);
466 void ubus_notify_route(struct babel_route
*route
, int kind
) {
467 struct blob_buf b
= {0};
468 char method
[50]; // possible methods are route.change, route.add, route.flush
470 if (!babeld_object
.has_subscribers
)
479 blob_buf_init(&b
, 0);
480 babeld_add_route_buf(route
, &b
);
481 snprintf(method
, sizeof(method
), "route.%s", local_kind(kind
));
482 ubus_notify(shared_ctx
, &babeld_object
, method
, b
.head
, -1);
486 void ubus_notify_xroute(struct xroute
*xroute
, int kind
) {
487 struct blob_buf b
= {0};
488 char method
[50]; // possible methods are xroute.change, xroute.add,
491 if (!babeld_object
.has_subscribers
)
500 blob_buf_init(&b
, 0);
501 babeld_add_xroute_buf(xroute
, &b
);
502 snprintf(method
, sizeof(method
), "xroute.%s", local_kind(kind
));
503 ubus_notify(shared_ctx
, &babeld_object
, method
, b
.head
, -1);
507 void ubus_notify_neighbour(struct neighbour
*neigh
, int kind
) {
508 struct blob_buf b
= {0};
509 char method
[50]; // possible methods are neigh.change, neigh.add, neigh.flush
511 if (!babeld_object
.has_subscribers
)
520 blob_buf_init(&b
, 0);
521 babeld_add_neighbour_buf(neigh
, &b
);
522 snprintf(method
, sizeof(method
), "neigh.%s", local_kind(kind
));
523 ubus_notify(shared_ctx
, &babeld_object
, method
, b
.head
, -1);
527 void babeld_ubus_receive(fd_set
*readfds
) {
530 if (FD_ISSET(shared_ctx
->sock
.fd
, readfds
))
531 ubus_handle_event(shared_ctx
);
534 int babeld_ubus_add_read_sock(fd_set
*readfds
, int maxfd
) {
538 FD_SET(shared_ctx
->sock
.fd
, readfds
);
539 return MAX(maxfd
, shared_ctx
->sock
.fd
);
542 bool babeld_add_ubus() {
543 if (!babeld_ubus_init()) {
544 fprintf(stderr
, "Failed to initialize ubus!\n");
548 if (!ubus_init_object()) {
549 fprintf(stderr
, "Failed to add objects to ubus!\n");