1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
9 static struct ubus_auto_conn conn
;
10 static struct blob_buf b
;
13 ubus_network_add(struct ubus_context
*ctx
, struct ubus_object
*obj
,
14 struct ubus_request_data
*req
, const char *method
,
15 struct blob_attr
*msg
)
17 struct blob_attr
*name
;
19 blobmsg_parse(&network_policy
[NETWORK_ATTR_NAME
], 1, &name
,
20 blobmsg_data(msg
), blobmsg_len(msg
));
23 return UBUS_STATUS_INVALID_ARGUMENT
;
25 if (unetd_network_add(blobmsg_get_string(name
), msg
))
26 return UBUS_STATUS_INVALID_ARGUMENT
;
33 ubus_network_del(struct ubus_context
*ctx
, struct ubus_object
*obj
,
34 struct ubus_request_data
*req
, const char *method
,
35 struct blob_attr
*msg
)
37 struct blob_attr
*name
;
39 blobmsg_parse(&network_policy
[NETWORK_ATTR_NAME
], 1, &name
,
40 blobmsg_data(msg
), blobmsg_len(msg
));
43 return UBUS_STATUS_INVALID_ARGUMENT
;
45 if (unetd_network_remove(blobmsg_get_string(name
)))
46 return UBUS_STATUS_NOT_FOUND
;
52 __network_dump(struct blob_buf
*buf
, struct network
*net
)
54 struct network_host
*local
= net
->net_config
.local_host
;
55 struct network_peer
*peer
;
59 blobmsg_add_field(buf
, BLOBMSG_TYPE_TABLE
, "config",
60 blobmsg_data(net
->config
.data
),
61 blobmsg_len(net
->config
.data
));
64 blobmsg_add_string(buf
, "local_host", network_host_name(local
));
66 c
= blobmsg_open_table(buf
, "peers");
67 vlist_for_each_element(&net
->peers
, peer
, node
) {
68 union network_endpoint
*ep
= &peer
->state
.endpoint
;
72 p
= blobmsg_open_table(buf
, network_peer_name(peer
));
73 blobmsg_add_u8(buf
, "connected", peer
->state
.connected
);
74 if (peer
->state
.connected
) {
75 str
= blobmsg_alloc_string_buffer(buf
, "endpoint",
76 INET6_ADDRSTRLEN
+ 7);
77 addr
= network_endpoint_addr(ep
, &len
);
78 inet_ntop(ep
->sa
.sa_family
, addr
, str
, INET6_ADDRSTRLEN
);
80 snprintf(str
+ len
, INET6_ADDRSTRLEN
+ 7 - len
, ":%d",
81 ntohs(ep
->in
.sin_port
));
82 blobmsg_add_string_buffer(buf
);
85 blobmsg_close_table(buf
, p
);
87 blobmsg_close_table(buf
, c
);
91 ubus_network_get(struct ubus_context
*ctx
, struct ubus_object
*obj
,
92 struct ubus_request_data
*req
, const char *method
,
93 struct blob_attr
*msg
)
95 struct blob_attr
*name
;
99 blobmsg_parse(&network_policy
[NETWORK_ATTR_NAME
], 1, &name
,
100 blobmsg_data(msg
), blobmsg_len(msg
));
102 blob_buf_init(&b
, 0);
104 net
= avl_find_element(&networks
, blobmsg_get_string(name
), net
, node
);
106 return UBUS_STATUS_NOT_FOUND
;
108 __network_dump(&b
, net
);
110 c
= blobmsg_open_table(&b
, "networks");
111 avl_for_each_element(&networks
, net
, node
) {
112 n
= blobmsg_open_table(&b
, network_name(net
));
113 __network_dump(&b
, net
);
114 blobmsg_close_table(&b
, n
);
116 blobmsg_close_table(&b
, c
);
119 ubus_send_reply(ctx
, req
, b
.head
);
125 SERVICE_ATTR_NETWORK
,
130 static const struct blobmsg_policy service_policy
[__SERVICE_ATTR_MAX
] = {
131 [SERVICE_ATTR_NETWORK
] = { "network", BLOBMSG_TYPE_STRING
},
132 [SERVICE_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
137 ubus_service_get_network_members(struct blob_buf
*b
, struct network
*n
,
140 struct network_service
*s
;
143 s
= vlist_find(&n
->services
, name
, s
, node
);
147 for (i
= 0; i
< s
->n_members
; i
++) {
148 struct network_host
*host
= s
->members
[i
];
151 name
= blobmsg_alloc_string_buffer(b
, NULL
, INET6_ADDRSTRLEN
);
152 inet_ntop(AF_INET6
, &host
->peer
.local_addr
.in6
, name
, INET6_ADDRSTRLEN
);
153 blobmsg_add_string_buffer(b
);
159 ubus_service_get(struct ubus_context
*ctx
, struct ubus_object
*obj
,
160 struct ubus_request_data
*req
, const char *method
,
161 struct blob_attr
*msg
)
163 struct blob_attr
*tb
[__SERVICE_ATTR_MAX
];
164 struct blob_attr
*cur
;
165 struct network
*n
= NULL
;
169 blobmsg_parse(service_policy
, __SERVICE_ATTR_MAX
, tb
,
170 blobmsg_data(msg
), blobmsg_len(msg
));
172 if ((cur
= tb
[SERVICE_ATTR_NAME
]) != NULL
)
173 name
= blobmsg_get_string(cur
);
175 return UBUS_STATUS_INVALID_ARGUMENT
;
177 if ((cur
= tb
[SERVICE_ATTR_NETWORK
]) != NULL
) {
178 n
= avl_find_element(&networks
, blobmsg_get_string(cur
), n
, node
);
180 return UBUS_STATUS_INVALID_ARGUMENT
;
183 blob_buf_init(&b
, 0);
185 c
= blobmsg_open_array(&b
, "hosts");
187 ubus_service_get_network_members(&b
, n
, name
);
189 avl_for_each_element(&networks
, n
, node
)
190 ubus_service_get_network_members(&b
, n
, name
);
192 blobmsg_close_array(&b
, c
);
193 ubus_send_reply(ctx
, req
, b
.head
);
200 CONNECT_ATTR_ADDRESS
,
201 CONNECT_ATTR_TIMEOUT
,
205 static const struct blobmsg_policy connect_policy
[__CONNECT_ATTR_MAX
] = {
206 [CONNECT_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
207 [CONNECT_ATTR_ADDRESS
] = { "address", BLOBMSG_TYPE_STRING
},
208 [CONNECT_ATTR_TIMEOUT
] = { "timeout", BLOBMSG_TYPE_INT32
},
212 ubus_network_connect(struct ubus_context
*ctx
, struct ubus_object
*obj
,
213 struct ubus_request_data
*req
, const char *method
,
214 struct blob_attr
*msg
)
216 struct blob_attr
*tb
[__CONNECT_ATTR_MAX
];
217 union network_endpoint ep
= {};
218 struct blob_attr
*cur
;
220 unsigned int timeout
;
223 blobmsg_parse(connect_policy
, __CONNECT_ATTR_MAX
, tb
,
224 blobmsg_data(msg
), blobmsg_len(msg
));
226 if ((cur
= tb
[CONNECT_ATTR_NAME
]) != NULL
)
227 name
= blobmsg_get_string(cur
);
229 return UBUS_STATUS_INVALID_ARGUMENT
;
231 if ((cur
= tb
[CONNECT_ATTR_TIMEOUT
]) != NULL
)
232 timeout
= blobmsg_get_u32(cur
);
234 return UBUS_STATUS_INVALID_ARGUMENT
;
236 if ((cur
= tb
[CONNECT_ATTR_ADDRESS
]) == NULL
||
237 network_get_endpoint(&ep
, AF_UNSPEC
, blobmsg_get_string(cur
), UNETD_GLOBAL_PEX_PORT
, 0) < 0 ||
239 return UBUS_STATUS_INVALID_ARGUMENT
;
241 net
= avl_find_element(&networks
, name
, net
, node
);
243 return UBUS_STATUS_NOT_FOUND
;
245 if (net
->config
.type
!= NETWORK_TYPE_DYNAMIC
)
246 return UBUS_STATUS_INVALID_ARGUMENT
;
248 network_pex_create_host(net
, &ep
, timeout
);
254 ubus_reload(struct ubus_context
*ctx
, struct ubus_object
*obj
,
255 struct ubus_request_data
*req
, const char *method
,
256 struct blob_attr
*msg
)
260 avl_for_each_element(&networks
, net
, node
)
261 network_soft_reload(net
);
267 static const struct ubus_method unetd_methods
[] = {
268 UBUS_METHOD("network_add", ubus_network_add
, network_policy
),
269 UBUS_METHOD_MASK("network_del", ubus_network_del
, network_policy
,
270 (1 << NETWORK_ATTR_NAME
)),
271 UBUS_METHOD_MASK("network_get", ubus_network_get
, network_policy
,
272 (1 << NETWORK_ATTR_NAME
)),
273 UBUS_METHOD("network_connect", ubus_network_connect
, connect_policy
),
274 UBUS_METHOD_NOARG("reload", ubus_reload
),
275 UBUS_METHOD("service_get", ubus_service_get
, service_policy
),
278 static struct ubus_object_type unetd_object_type
=
279 UBUS_OBJECT_TYPE("unetd", unetd_methods
);
281 static struct ubus_object unetd_object
= {
283 .type
= &unetd_object_type
,
284 .methods
= unetd_methods
,
285 .n_methods
= ARRAY_SIZE(unetd_methods
),
289 ubus_connect_handler(struct ubus_context
*ctx
)
293 ret
= ubus_add_object(ctx
, &unetd_object
);
295 fprintf(stderr
, "Failed to add object: %s\n", ubus_strerror(ret
));
298 void unetd_ubus_notify(struct network
*net
)
300 blob_buf_init(&b
, 0);
301 blobmsg_add_string(&b
, "network", network_name(net
));
302 ubus_notify(&conn
.ctx
, &unetd_object
, "network_update", b
.head
, -1);
305 void unetd_ubus_netifd_update(struct blob_attr
*data
)
309 if (ubus_lookup_id(&conn
.ctx
, "network.interface", &id
))
312 ubus_invoke(&conn
.ctx
, id
, "notify_proto", data
, NULL
, NULL
, 5000);
315 void unetd_ubus_netifd_add_route(struct network
*net
, union network_endpoint
*ep
)
321 if (!net
->config
.interface
)
324 if (ubus_lookup_id(&conn
.ctx
, "network", &id
))
327 blob_buf_init(&b
, 0);
329 if (ep
->in
.sin_family
== AF_INET6
)
330 addr
= &ep
->in6
.sin6_addr
;
332 addr
= &ep
->in
.sin_addr
;
334 blobmsg_add_u8(&b
, "v6", ep
->in
.sin_family
== AF_INET6
);
335 buf
= blobmsg_alloc_string_buffer(&b
, "target", INET6_ADDRSTRLEN
);
336 inet_ntop(ep
->in
.sin_family
, addr
, buf
, INET6_ADDRSTRLEN
);
337 blobmsg_add_string_buffer(&b
);
338 blobmsg_add_string(&b
, "interface", net
->config
.interface
);
339 blobmsg_add_u8(&b
, "exclude", true);
341 ubus_invoke(&conn
.ctx
, id
, "add_host_route", b
.head
, NULL
, NULL
, -1);
344 void unetd_ubus_init(void)
346 conn
.cb
= ubus_connect_handler
;
347 ubus_auto_connect(&conn
);