2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15 * Copyright (C) 2020 embedd.ch
16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
17 * Copyright (C) 2020 John Crispin <john@phrozen.org>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
24 #include <arpa/inet.h>
28 #include <libubox/vlist.h>
29 #include <libubox/avl-cmp.h>
30 #include <libubox/usock.h>
35 static uint32_t local_id
;
36 static struct uloop_fd remote_fd
;
37 static struct uloop_timeout remote_timer
;
38 static struct uloop_timeout reload_timer
;
40 static struct blob_buf buf
;
41 static uint32_t msg_seq
;
44 struct vlist_node node
;
49 interfaces_update_cb(struct vlist_tree
*tree
,
50 struct vlist_node
*node_new
,
51 struct vlist_node
*node_old
);
53 static int remote_node_cmp(const void *k1
, const void *k2
, void *ptr
)
55 unsigned long v1
= (unsigned long) k1
;
56 unsigned long v2
= (unsigned long) k2
;
61 static VLIST_TREE(interfaces
, avl_strcmp
, interfaces_update_cb
, true, true);
62 AVL_TREE(remote_nodes
, remote_node_cmp
, true, NULL
);
65 interface_name(struct interface
*iface
)
67 return iface
->node
.avl
.key
;
71 interface_check(struct interface
*iface
)
73 iface
->ifindex
= if_nametoindex(interface_name(iface
));
74 uloop_timeout_set(&reload_timer
, 1);
78 interface_init(struct interface
*iface
)
80 interface_check(iface
);
84 interface_free(struct interface
*iface
)
86 avl_delete(&interfaces
.avl
, &iface
->node
.avl
);
91 interfaces_update_cb(struct vlist_tree
*tree
,
92 struct vlist_node
*node_new
,
93 struct vlist_node
*node_old
)
95 struct interface
*iface
;
97 if (node_new
&& node_old
) {
98 iface
= container_of(node_new
, struct interface
, node
);
100 iface
= container_of(node_old
, struct interface
, node
);
101 interface_check(iface
);
102 } else if (node_old
) {
103 iface
= container_of(node_old
, struct interface
, node
);
104 interface_free(iface
);
106 iface
= container_of(node_new
, struct interface
, node
);
107 interface_init(iface
);
111 void usteer_interface_add(const char *name
)
113 struct interface
*iface
;
116 iface
= calloc_a(sizeof(*iface
), &name_buf
, strlen(name
) + 1);
117 strcpy(name_buf
, name
);
118 vlist_add(&interfaces
, &iface
->node
, name_buf
);
121 void config_set_interfaces(struct blob_attr
*data
)
123 struct blob_attr
*cur
;
126 if (!blobmsg_check_attr_list(data
, BLOBMSG_TYPE_STRING
))
129 vlist_update(&interfaces
);
130 blobmsg_for_each_attr(cur
, data
, rem
) {
131 usteer_interface_add(blobmsg_data(cur
));
133 vlist_flush(&interfaces
);
136 void config_get_interfaces(struct blob_buf
*buf
)
138 struct interface
*iface
;
141 c
= blobmsg_open_array(buf
, "interfaces");
142 vlist_for_each_element(&interfaces
, iface
, node
) {
143 blobmsg_add_string(buf
, NULL
, interface_name(iface
));
145 blobmsg_close_array(buf
, c
);
149 interface_add_station(struct usteer_remote_node
*node
, struct blob_attr
*data
)
153 struct apmsg_sta msg
;
156 if (!parse_apmsg_sta(&msg
, data
)) {
157 MSG(DEBUG
, "Cannot parse station in message\n");
161 if (msg
.timeout
<= 0) {
162 MSG(DEBUG
, "Refuse to add an already expired station entry\n");
166 sta
= usteer_sta_get(msg
.addr
, true);
170 si
= usteer_sta_info_get(sta
, &node
->node
, &create
);
174 si
->connected
= msg
.connected
;
175 si
->signal
= msg
.signal
;
176 si
->seen
= current_time
- msg
.seen
;
177 usteer_sta_info_update_timeout(si
, msg
.timeout
);
181 remote_node_free(struct usteer_remote_node
*node
)
183 avl_delete(&remote_nodes
, &node
->avl
);
184 usteer_sta_node_cleanup(&node
->node
);
188 static struct usteer_remote_node
*
189 interface_get_node(const char *addr
, unsigned long id
, const char *name
)
191 struct usteer_remote_node
*node
;
192 int addr_len
= strlen(addr
);
195 node
= avl_find_element(&remote_nodes
, (void *) id
, node
, avl
);
196 while (node
&& node
->avl
.key
== (void *) id
) {
197 if (!strcmp(node
->name
, name
))
200 node
= avl_next_element(node
, avl
);
203 node
= calloc_a(sizeof(*node
), &buf
, addr_len
+ 1 + strlen(name
) + 1);
204 node
->avl
.key
= (void *) id
;
205 node
->node
.type
= NODE_TYPE_REMOTE
;
207 sprintf(buf
, "%s#%s", addr
, name
);
208 node
->node
.avl
.key
= buf
;
209 node
->name
= buf
+ addr_len
+ 1;
210 INIT_LIST_HEAD(&node
->node
.sta_info
);
212 avl_insert(&remote_nodes
, &node
->avl
);
218 interface_add_node(struct interface
*iface
, const char *addr
, unsigned long id
, struct blob_attr
*data
)
220 struct usteer_remote_node
*node
;
221 struct apmsg_node msg
;
222 struct blob_attr
*cur
;
225 if (!parse_apmsg_node(&msg
, data
)) {
226 MSG(DEBUG
, "Cannot parse node in message\n");
230 node
= interface_get_node(addr
, id
, msg
.name
);
232 node
->node
.freq
= msg
.freq
;
233 node
->node
.n_assoc
= msg
.n_assoc
;
234 node
->node
.max_assoc
= msg
.max_assoc
;
235 node
->node
.noise
= msg
.noise
;
236 node
->node
.load
= msg
.load
;
238 snprintf(node
->node
.ssid
, sizeof(node
->node
.ssid
), "%s", msg
.ssid
);
239 usteer_node_set_blob(&node
->node
.rrm_nr
, msg
.rrm_nr
);
240 usteer_node_set_blob(&node
->node
.script_data
, msg
.script_data
);
242 blob_for_each_attr(cur
, msg
.stations
, rem
)
243 interface_add_station(node
, cur
);
247 interface_recv_msg(struct interface
*iface
, struct in_addr
*addr
, void *buf
, int len
)
249 char addr_str
[INET_ADDRSTRLEN
];
250 struct blob_attr
*data
= buf
;
252 struct blob_attr
*cur
;
255 if (blob_pad_len(data
) != len
) {
256 MSG(DEBUG
, "Invalid message length (header: %d, real: %d)\n", blob_pad_len(data
), len
);
260 if (!parse_apmsg(&msg
, data
)) {
261 MSG(DEBUG
, "Missing fields in message\n");
265 if (msg
.id
== local_id
)
268 MSG(NETWORK
, "Received message on %s (id=%08x->%08x seq=%d len=%d)\n",
269 interface_name(iface
), msg
.id
, local_id
, msg
.seq
, len
);
271 inet_ntop(AF_INET
, addr
, addr_str
, sizeof(addr_str
));
273 blob_for_each_attr(cur
, msg
.nodes
, rem
)
274 interface_add_node(iface
, addr_str
, msg
.id
, cur
);
277 static struct interface
*
278 interface_find_by_ifindex(int index
)
280 struct interface
*iface
;
282 vlist_for_each_element(&interfaces
, iface
, node
) {
283 if (iface
->ifindex
== index
)
291 interface_recv(struct uloop_fd
*u
, unsigned int events
)
293 static char buf
[APMGR_BUFLEN
];
294 static char cmsg_buf
[( CMSG_SPACE(sizeof(struct in_pktinfo
)) + sizeof(int)) + 1];
295 static struct sockaddr_in sin
;
296 static struct iovec iov
= {
298 .iov_len
= sizeof(buf
)
300 static struct msghdr msg
= {
302 .msg_namelen
= sizeof(sin
),
305 .msg_control
= cmsg_buf
,
306 .msg_controllen
= sizeof(cmsg_buf
),
308 struct cmsghdr
*cmsg
;
312 struct in_pktinfo
*pkti
= NULL
;
313 struct interface
*iface
;
315 len
= recvmsg(u
->fd
, &msg
, 0);
329 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
330 if (cmsg
->cmsg_type
!= IP_PKTINFO
)
333 pkti
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
337 MSG(DEBUG
, "Received packet without ifindex\n");
341 iface
= interface_find_by_ifindex(pkti
->ipi_ifindex
);
343 MSG(DEBUG
, "Received packet from unconfigured interface %d\n", pkti
->ipi_ifindex
);
347 interface_recv_msg(iface
, &sin
.sin_addr
, buf
, len
);
351 static void interface_send_msg(struct interface
*iface
, struct blob_attr
*data
)
353 static size_t cmsg_data
[( CMSG_SPACE(sizeof(struct in_pktinfo
)) / sizeof(size_t)) + 1];
354 static struct sockaddr_in a
;
355 static struct iovec iov
;
356 static struct msghdr m
= {
357 .msg_name
= (struct sockaddr
*) &a
,
358 .msg_namelen
= sizeof(a
),
361 .msg_control
= cmsg_data
,
362 .msg_controllen
= CMSG_LEN(sizeof(struct in_pktinfo
)),
364 struct in_pktinfo
*pkti
;
365 struct cmsghdr
*cmsg
;
367 a
.sin_family
= AF_INET
;
368 a
.sin_port
= htons(16720);
369 a
.sin_addr
.s_addr
= ~0;
371 memset(cmsg_data
, 0, sizeof(cmsg_data
));
372 cmsg
= CMSG_FIRSTHDR(&m
);
373 cmsg
->cmsg_len
= m
.msg_controllen
;
374 cmsg
->cmsg_level
= IPPROTO_IP
;
375 cmsg
->cmsg_type
= IP_PKTINFO
;
377 pkti
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
378 pkti
->ipi_ifindex
= iface
->ifindex
;
381 iov
.iov_len
= blob_pad_len(data
);
383 if (sendmsg(remote_fd
.fd
, &m
, 0) < 0)
387 static void usteer_send_sta_info(struct sta_info
*sta
)
389 int seen
= current_time
- sta
->seen
;
392 c
= blob_nest_start(&buf
, 0);
393 blob_put(&buf
, APMSG_STA_ADDR
, sta
->sta
->addr
, 6);
394 blob_put_int8(&buf
, APMSG_STA_CONNECTED
, !!sta
->connected
);
395 blob_put_int32(&buf
, APMSG_STA_SIGNAL
, sta
->signal
);
396 blob_put_int32(&buf
, APMSG_STA_SEEN
, seen
);
397 blob_put_int32(&buf
, APMSG_STA_TIMEOUT
, config
.local_sta_timeout
- seen
);
398 blob_nest_end(&buf
, c
);
401 static void usteer_send_node(struct usteer_node
*node
, struct sta_info
*sta
)
405 c
= blob_nest_start(&buf
, 0);
407 blob_put_string(&buf
, APMSG_NODE_NAME
, usteer_node_name(node
));
408 blob_put_string(&buf
, APMSG_NODE_SSID
, node
->ssid
);
409 blob_put_int32(&buf
, APMSG_NODE_FREQ
, node
->freq
);
410 blob_put_int32(&buf
, APMSG_NODE_NOISE
, node
->noise
);
411 blob_put_int32(&buf
, APMSG_NODE_LOAD
, node
->load
);
412 blob_put_int32(&buf
, APMSG_NODE_N_ASSOC
, node
->n_assoc
);
413 blob_put_int32(&buf
, APMSG_NODE_MAX_ASSOC
, node
->max_assoc
);
415 r
= blob_nest_start(&buf
, APMSG_NODE_RRM_NR
);
416 blobmsg_add_field(&buf
, BLOBMSG_TYPE_ARRAY
, "",
417 blobmsg_data(node
->rrm_nr
),
418 blobmsg_data_len(node
->rrm_nr
));
419 blob_nest_end(&buf
, r
);
422 if (node
->script_data
)
423 blob_put(&buf
, APMSG_NODE_SCRIPT_DATA
,
424 blob_data(node
->script_data
),
425 blob_len(node
->script_data
));
427 s
= blob_nest_start(&buf
, APMSG_NODE_STATIONS
);
430 usteer_send_sta_info(sta
);
432 list_for_each_entry(sta
, &node
->sta_info
, node_list
)
433 usteer_send_sta_info(sta
);
436 blob_nest_end(&buf
, s
);
438 blob_nest_end(&buf
, c
);
442 usteer_check_timeout(void)
444 struct usteer_remote_node
*node
, *tmp
;
445 int timeout
= config
.remote_node_timeout
/ config
.remote_update_interval
;
447 avl_for_each_element_safe(&remote_nodes
, node
, avl
, tmp
) {
448 if (node
->check
++ > timeout
)
449 remote_node_free(node
);
454 usteer_update_init(void)
456 blob_buf_init(&buf
, 0);
457 blob_put_int32(&buf
, APMSG_ID
, local_id
);
458 blob_put_int32(&buf
, APMSG_SEQ
, ++msg_seq
);
460 return blob_nest_start(&buf
, APMSG_NODES
);
464 usteer_update_send(void *c
)
466 struct interface
*iface
;
468 blob_nest_end(&buf
, c
);
470 vlist_for_each_element(&interfaces
, iface
, node
)
471 interface_send_msg(iface
, buf
.head
);
475 usteer_send_sta_update(struct sta_info
*si
)
477 void *c
= usteer_update_init();
478 usteer_send_node(si
->node
, si
);
479 usteer_update_send(c
);
483 usteer_send_update_timer(struct uloop_timeout
*t
)
485 struct usteer_node
*node
;
488 MSG_T("remote_update_interval", "start remote update (interval=%u)\n",
489 config
.remote_update_interval
);
491 usteer_update_time();
492 uloop_timeout_set(t
, config
.remote_update_interval
);
494 c
= usteer_update_init();
495 avl_for_each_element(&local_nodes
, node
, avl
)
496 usteer_send_node(node
, NULL
);
498 usteer_update_send(c
);
499 usteer_check_timeout();
503 usteer_init_local_id(void)
507 f
= fopen("/dev/urandom", "r");
509 perror("fopen(/dev/urandom)");
513 if (fread(&local_id
, sizeof(local_id
), 1, f
) < 1)
521 usteer_reload_timer(struct uloop_timeout
*t
)
526 if (remote_fd
.registered
) {
527 uloop_fd_delete(&remote_fd
);
531 fd
= usock(USOCK_UDP
| USOCK_SERVER
| USOCK_NONBLOCK
|
532 USOCK_NUMERIC
| USOCK_IPV4ONLY
,
533 "0.0.0.0", APMGR_PORT_STR
);
539 if (setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
, &yes
, sizeof(yes
)) < 0)
540 perror("setsockopt(IP_PKTINFO)");
542 if (setsockopt(fd
, SOL_SOCKET
, SO_BROADCAST
, &yes
, sizeof(yes
)) < 0)
543 perror("setsockopt(SO_BROADCAST)");
546 remote_fd
.cb
= interface_recv
;
547 uloop_fd_add(&remote_fd
, ULOOP_READ
);
550 int usteer_interface_init(void)
552 if (usteer_init_local_id())
555 remote_timer
.cb
= usteer_send_update_timer
;
556 remote_timer
.cb(&remote_timer
);
558 reload_timer
.cb
= usteer_reload_timer
;
559 reload_timer
.cb(&reload_timer
);