3 #include <sys/select.h>
5 #include <libubox/blob.h>
6 #include <libubox/blobmsg.h>
7 #include <libubox/list.h>
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
16 #include "configuration.h"
17 #include "interface.h"
21 #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 route_stream
*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 // Sends a babel info message on ubus socket.
58 static void babeld_ubus_babeld_info(struct ubus_context
*ctx_local
,
59 struct ubus_object
*obj
,
60 struct ubus_request_data
*req
,
61 const char *method
, struct blob_attr
*msg
) {
62 struct blob_buf b
= {0};
68 blobmsg_add_string(&b
, "babeld-version", BABELD_VERSION
);
69 blobmsg_add_string(&b
, "my-id", format_eui64(myid
));
70 if (!gethostname(host
, sizeof(host
)))
71 blobmsg_add_string(&b
, "host", host
);
73 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
75 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
78 // Appends an exported route message entry to the buffer.
79 static void babeld_add_xroute_buf(struct xroute
*xroute
, struct blob_buf
*b
) {
82 prefix
= blobmsg_open_table(b
, format_prefix(xroute
->prefix
, xroute
->plen
));
84 blobmsg_add_string(b
, "src-prefix",
85 format_prefix(xroute
->src_prefix
, xroute
->src_plen
));
86 blobmsg_add_u32(b
, "metric", xroute
->metric
);
87 blobmsg_close_table(b
, prefix
);
90 // Sends an exported routes message on ubus socket, splitting apart IPv4 and IPv6 routes.
91 static void babeld_ubus_get_xroutes(struct ubus_context
*ctx_local
,
92 struct ubus_object
*obj
,
93 struct ubus_request_data
*req
,
94 const char *method
, struct blob_attr
*msg
) {
95 struct blob_buf b
= {0};
96 struct xroute_stream
*xroutes
;
97 struct xroute_list_entry
*cur
, *tmp
;
100 LIST_HEAD(xroute_ipv4_list
);
101 LIST_HEAD(xroute_ipv6_list
);
103 xroutes
= xroute_stream();
106 struct xroute
*xroute
= xroute_stream_next(xroutes
);
110 struct xroute_list_entry
*xr
=
111 calloc(1, sizeof(struct xroute_list_entry
));
114 if (v4mapped(xroute
->prefix
)) {
115 list_add(&xr
->list
, &xroute_ipv4_list
);
117 list_add(&xr
->list
, &xroute_ipv6_list
);
120 xroute_stream_done(xroutes
);
123 blob_buf_init(&b
, 0);
124 ipv4
= blobmsg_open_table(&b
, "IPv4");
125 list_for_each_entry_safe(cur
, tmp
, &xroute_ipv4_list
, list
) {
126 babeld_add_xroute_buf(cur
->xroute
, &b
);
127 list_del(&cur
->list
);
130 blobmsg_close_table(&b
, ipv4
);
132 ipv6
= blobmsg_open_table(&b
, "IPv6");
133 list_for_each_entry_safe(cur
, tmp
, &xroute_ipv6_list
, list
) {
134 babeld_add_xroute_buf(cur
->xroute
, &b
);
135 list_del(&cur
->list
);
138 blobmsg_close_table(&b
, ipv6
);
140 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
142 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
145 // Appends an route message entry to the buffer.
146 static void babeld_add_route_buf(struct babel_route
*route
,
147 struct blob_buf
*b
) {
151 if (route
->channels_len
== 0) {
155 snprintf(channels
, sizeof(channels
), " chan (");
156 j
= strlen(channels
);
157 for (i
= 0; i
< route
->channels_len
; i
++) {
160 snprintf(channels
+ j
, sizeof(channels
) - j
, "%u",
161 (unsigned)route
->channels
[i
]);
162 j
= strlen(channels
);
164 snprintf(channels
+ j
, sizeof(channels
) - j
, ")");
167 prefix
= blobmsg_open_table(
168 b
, format_prefix(route
->src
->prefix
, route
->src
->plen
));
172 format_prefix(route
->src
->src_prefix
, route
->src
->src_plen
));
173 blobmsg_add_u32(b
, "route_metric", route_metric(route
));
174 blobmsg_add_u32(b
, "route_smoothed_metric", route_smoothed_metric(route
));
175 blobmsg_add_u32(b
, "refmetric", route
->refmetric
);
176 blobmsg_add_string(b
, "id", format_eui64(route
->src
->id
));
177 blobmsg_add_u32(b
, "seqno", (uint32_t)route
->seqno
);
178 blobmsg_add_string(b
, "channels", channels
);
179 blobmsg_add_u32(b
, "age", (int)(now
.tv_sec
- route
->time
));
180 blobmsg_add_string(b
, "via", format_address(route
->neigh
->address
));
181 if (memcmp(route
->nexthop
, route
->neigh
->address
, 16) != 0)
182 blobmsg_add_string(b
, "nexthop", format_address(route
->nexthop
));
184 blobmsg_add_u8(b
, "installed", route
->installed
);
185 blobmsg_add_u8(b
, "feasible", route_feasible(route
));
187 blobmsg_close_table(b
, prefix
);
190 // Sends received routes message on ubus socket, splitting apart IPv4 and IPv6 routes.
191 static void babeld_ubus_get_routes(struct ubus_context
*ctx_local
,
192 struct ubus_object
*obj
,
193 struct ubus_request_data
*req
,
194 const char *method
, struct blob_attr
*msg
) {
195 struct blob_buf b
= {0};
196 struct route_stream
*routes
;
197 struct route_list_entry
*cur
, *tmp
;
198 void *prefix
, *ipv4
, *ipv6
;
200 LIST_HEAD(route_ipv4_list
);
201 LIST_HEAD(route_ipv6_list
);
203 blob_buf_init(&b
, 0);
205 routes
= route_stream(ROUTE_ALL
);
208 struct babel_route
*route
= route_stream_next(routes
);
211 struct route_list_entry
*r
= calloc(1, sizeof(struct route_list_entry
));
214 if (v4mapped(route
->src
->prefix
)) {
215 list_add(&r
->list
, &route_ipv4_list
);
217 list_add(&r
->list
, &route_ipv6_list
);
220 route_stream_done(routes
);
223 blob_buf_init(&b
, 0);
224 ipv4
= blobmsg_open_table(&b
, "IPv4");
225 list_for_each_entry_safe(cur
, tmp
, &route_ipv4_list
, list
) {
226 babeld_add_route_buf(cur
->route
, &b
);
227 list_del(&cur
->list
);
230 blobmsg_close_table(&b
, ipv4
);
232 ipv6
= blobmsg_open_table(&b
, "IPv6");
233 list_for_each_entry_safe(cur
, tmp
, &route_ipv6_list
, list
) {
234 babeld_add_route_buf(cur
->route
, &b
);
235 list_del(&cur
->list
);
238 blobmsg_close_table(&b
, ipv6
);
240 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
242 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
245 // Appends an neighbour entry to the buffer.
246 static void babeld_add_neighbour_buf(struct neighbour
*neigh
,
247 struct blob_buf
*b
) {
250 neighbour
= blobmsg_open_table(b
, format_address(neigh
->address
));
251 blobmsg_add_string(b
, "dev", neigh
->ifp
->name
);
252 blobmsg_add_u32(b
, "hello-reach", neigh
->hello
.reach
);
253 blobmsg_add_u32(b
, "uhello-reach", neigh
->uhello
.reach
);
254 blobmsg_add_u32(b
, "rxcost", neighbour_rxcost(neigh
));
255 blobmsg_add_u32(b
, "txcost", neigh
->txcost
);
256 blobmsg_add_u32(b
, "rtt", format_thousands(neigh
->rtt
));
257 blobmsg_add_u32(b
, "channel", neigh
->ifp
->channel
);
258 blobmsg_add_u8(b
, "if_up", if_up(neigh
->ifp
));
259 blobmsg_close_table(b
, neighbour
);
262 // Sends neighbours message on ubus socket, splitting apart IPv4 and IPv6 neighbours.
263 static void babeld_ubus_get_neighbours(struct ubus_context
*ctx_local
,
264 struct ubus_object
*obj
,
265 struct ubus_request_data
*req
,
267 struct blob_attr
*msg
) {
268 struct blob_buf b
= {0};
269 struct neighbour
*neigh
;
270 struct neighbour_list_entry
*cur
, *tmp
;
273 LIST_HEAD(neighbour_ipv4_list
);
274 LIST_HEAD(neighbour_ipv6_list
);
276 blob_buf_init(&b
, 0);
278 FOR_ALL_NEIGHBOURS(neigh
) {
279 struct neighbour_list_entry
*n
=
280 calloc(1, sizeof(struct neighbour_list_entry
));
281 n
->neighbour
= neigh
;
282 if (v4mapped(neigh
->address
)) {
283 list_add(&n
->list
, &neighbour_ipv4_list
);
285 list_add(&n
->list
, &neighbour_ipv6_list
);
289 blob_buf_init(&b
, 0);
291 ipv4
= blobmsg_open_table(&b
, "IPv4");
292 list_for_each_entry_safe(cur
, tmp
, &neighbour_ipv4_list
, list
) {
293 babeld_add_neighbour_buf(cur
->neighbour
, &b
);
294 list_del(&cur
->list
);
297 blobmsg_close_table(&b
, ipv4
);
299 ipv6
= blobmsg_open_table(&b
, "IPv6");
300 list_for_each_entry_safe(cur
, tmp
, &neighbour_ipv6_list
, list
) {
301 babeld_add_neighbour_buf(cur
->neighbour
, &b
);
302 list_del(&cur
->list
);
305 blobmsg_close_table(&b
, ipv6
);
307 ret
= ubus_send_reply(ctx_local
, req
, b
.head
);
309 fprintf(stderr
, "Failed to send reply: %s\n", ubus_strerror(ret
));
312 // List of functions we expose via the ubus bus.
313 static const struct ubus_method babeld_methods
[] = {
314 UBUS_METHOD_NOARG("get_info", babeld_ubus_babeld_info
),
315 UBUS_METHOD_NOARG("get_xroutes", babeld_ubus_get_xroutes
),
316 UBUS_METHOD_NOARG("get_routes", babeld_ubus_get_routes
),
317 UBUS_METHOD_NOARG("get_neighbours", babeld_ubus_get_neighbours
),
320 // Definition of the ubus object type.
321 static struct ubus_object_type babeld_object_type
=
322 UBUS_OBJECT_TYPE("babeld", babeld_methods
);
324 // Object we announce via the ubus bus.
325 static struct ubus_object babeld_object
= {
327 .type
= &babeld_object_type
,
328 .methods
= babeld_methods
,
329 .n_methods
= ARRAY_SIZE(babeld_methods
),
332 // Registers handlers for babel methods in the global ubus context.
333 static bool ubus_init_object() {
336 ret
= ubus_add_object(shared_ctx
, &babeld_object
);
338 fprintf(stderr
, "Failed to add object: %s\n", ubus_strerror(ret
));
345 // Initializes the global ubus context, connecting to the bus to be able to receive and send messages.
346 static bool babeld_ubus_init(void) {
350 shared_ctx
= ubus_connect(NULL
);
357 void babeld_ubus_receive(fd_set
*readfds
) {
360 if (FD_ISSET(shared_ctx
->sock
.fd
, readfds
))
361 ubus_handle_event(shared_ctx
);
364 int babeld_ubus_add_read_sock(fd_set
*readfds
, int maxfd
) {
368 FD_SET(shared_ctx
->sock
.fd
, readfds
);
369 return MAX(maxfd
, shared_ctx
->sock
.fd
);
372 bool babeld_add_ubus() {
373 if (!babeld_ubus_init()) {
374 fprintf(stderr
, "Failed to initialize ubus!\n");
378 if (!ubus_init_object()) {
379 fprintf(stderr
, "Failed to add objects to ubus!\n");