usteer: Initial import
[project/usteer.git] / remote.c
1 /*
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.
5 *
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.
10 *
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.
14 *
15 * Copyright (C) 2020 embedd.ch
16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
17 * Copyright (C) 2020 John Crispin <john@phrozen.org>
18 */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <net/if.h>
24 #include <arpa/inet.h>
25 #include <errno.h>
26 #include <unistd.h>
27
28 #include <libubox/vlist.h>
29 #include <libubox/avl-cmp.h>
30 #include <libubox/usock.h>
31 #include "usteer.h"
32 #include "remote.h"
33 #include "node.h"
34
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;
39
40 static struct blob_buf buf;
41 static uint32_t msg_seq;
42
43 struct interface {
44 struct vlist_node node;
45 int ifindex;
46 };
47
48 static void
49 interfaces_update_cb(struct vlist_tree *tree,
50 struct vlist_node *node_new,
51 struct vlist_node *node_old);
52
53 static int remote_node_cmp(const void *k1, const void *k2, void *ptr)
54 {
55 unsigned long v1 = (unsigned long) k1;
56 unsigned long v2 = (unsigned long) k2;
57
58 return v2 - v1;
59 }
60
61 static VLIST_TREE(interfaces, avl_strcmp, interfaces_update_cb, true, true);
62 AVL_TREE(remote_nodes, remote_node_cmp, true, NULL);
63
64 static const char *
65 interface_name(struct interface *iface)
66 {
67 return iface->node.avl.key;
68 }
69
70 static void
71 interface_check(struct interface *iface)
72 {
73 iface->ifindex = if_nametoindex(interface_name(iface));
74 uloop_timeout_set(&reload_timer, 1);
75 }
76
77 static void
78 interface_init(struct interface *iface)
79 {
80 interface_check(iface);
81 }
82
83 static void
84 interface_free(struct interface *iface)
85 {
86 avl_delete(&interfaces.avl, &iface->node.avl);
87 free(iface);
88 }
89
90 static void
91 interfaces_update_cb(struct vlist_tree *tree,
92 struct vlist_node *node_new,
93 struct vlist_node *node_old)
94 {
95 struct interface *iface;
96
97 if (node_new && node_old) {
98 iface = container_of(node_new, struct interface, node);
99 free(iface);
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);
105 } else {
106 iface = container_of(node_new, struct interface, node);
107 interface_init(iface);
108 }
109 }
110
111 void usteer_interface_add(const char *name)
112 {
113 struct interface *iface;
114 char *name_buf;
115
116 iface = calloc_a(sizeof(*iface), &name_buf, strlen(name) + 1);
117 strcpy(name_buf, name);
118 vlist_add(&interfaces, &iface->node, name_buf);
119 }
120
121 void config_set_interfaces(struct blob_attr *data)
122 {
123 struct blob_attr *cur;
124 int rem;
125
126 if (!blobmsg_check_attr_list(data, BLOBMSG_TYPE_STRING))
127 return;
128
129 vlist_update(&interfaces);
130 blobmsg_for_each_attr(cur, data, rem) {
131 usteer_interface_add(blobmsg_data(cur));
132 }
133 vlist_flush(&interfaces);
134 }
135
136 void config_get_interfaces(struct blob_buf *buf)
137 {
138 struct interface *iface;
139 void *c;
140
141 c = blobmsg_open_array(buf, "interfaces");
142 vlist_for_each_element(&interfaces, iface, node) {
143 blobmsg_add_string(buf, NULL, interface_name(iface));
144 }
145 blobmsg_close_array(buf, c);
146 }
147
148 static void
149 interface_add_station(struct usteer_remote_node *node, struct blob_attr *data)
150 {
151 struct sta *sta;
152 struct sta_info *si;
153 struct apmsg_sta msg;
154 bool create;
155
156 if (!parse_apmsg_sta(&msg, data)) {
157 MSG(DEBUG, "Cannot parse station in message\n");
158 return;
159 }
160
161 if (msg.timeout <= 0) {
162 MSG(DEBUG, "Refuse to add an already expired station entry\n");
163 return;
164 }
165
166 sta = usteer_sta_get(msg.addr, true);
167 if (!sta)
168 return;
169
170 si = usteer_sta_info_get(sta, &node->node, &create);
171 if (!si)
172 return;
173
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);
178 }
179
180 static void
181 remote_node_free(struct usteer_remote_node *node)
182 {
183 avl_delete(&remote_nodes, &node->avl);
184 usteer_sta_node_cleanup(&node->node);
185 free(node);
186 }
187
188 static struct usteer_remote_node *
189 interface_get_node(const char *addr, unsigned long id, const char *name)
190 {
191 struct usteer_remote_node *node;
192 int addr_len = strlen(addr);
193 char *buf;
194
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))
198 return node;
199
200 node = avl_next_element(node, avl);
201 }
202
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;
206
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);
211
212 avl_insert(&remote_nodes, &node->avl);
213
214 return node;
215 }
216
217 static void
218 interface_add_node(struct interface *iface, const char *addr, unsigned long id, struct blob_attr *data)
219 {
220 struct usteer_remote_node *node;
221 struct apmsg_node msg;
222 struct blob_attr *cur;
223 int rem;
224
225 if (!parse_apmsg_node(&msg, data)) {
226 MSG(DEBUG, "Cannot parse node in message\n");
227 return;
228 }
229
230 node = interface_get_node(addr, id, msg.name);
231 node->check = 0;
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;
237 node->iface = iface;
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);
241
242 blob_for_each_attr(cur, msg.stations, rem)
243 interface_add_station(node, cur);
244 }
245
246 static void
247 interface_recv_msg(struct interface *iface, struct in_addr *addr, void *buf, int len)
248 {
249 char addr_str[INET_ADDRSTRLEN];
250 struct blob_attr *data = buf;
251 struct apmsg msg;
252 struct blob_attr *cur;
253 int rem;
254
255 if (blob_pad_len(data) != len) {
256 MSG(DEBUG, "Invalid message length (header: %d, real: %d)\n", blob_pad_len(data), len);
257 return;
258 }
259
260 if (!parse_apmsg(&msg, data)) {
261 MSG(DEBUG, "Missing fields in message\n");
262 return;
263 }
264
265 if (msg.id == local_id)
266 return;
267
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);
270
271 inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
272
273 blob_for_each_attr(cur, msg.nodes, rem)
274 interface_add_node(iface, addr_str, msg.id, cur);
275 }
276
277 static struct interface *
278 interface_find_by_ifindex(int index)
279 {
280 struct interface *iface;
281
282 vlist_for_each_element(&interfaces, iface, node) {
283 if (iface->ifindex == index)
284 return iface;
285 }
286
287 return NULL;
288 }
289
290 static void
291 interface_recv(struct uloop_fd *u, unsigned int events)
292 {
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 = {
297 .iov_base = buf,
298 .iov_len = sizeof(buf)
299 };
300 static struct msghdr msg = {
301 .msg_name = &sin,
302 .msg_namelen = sizeof(sin),
303 .msg_iov = &iov,
304 .msg_iovlen = 1,
305 .msg_control = cmsg_buf,
306 .msg_controllen = sizeof(cmsg_buf),
307 };
308 struct cmsghdr *cmsg;
309 int len;
310
311 do {
312 struct in_pktinfo *pkti = NULL;
313 struct interface *iface;
314
315 len = recvmsg(u->fd, &msg, 0);
316 if (len < 0) {
317 switch (errno) {
318 case EAGAIN:
319 return;
320 case EINTR:
321 continue;
322 default:
323 perror("recvmsg");
324 uloop_fd_delete(u);
325 return;
326 }
327 }
328
329 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
330 if (cmsg->cmsg_type != IP_PKTINFO)
331 continue;
332
333 pkti = (struct in_pktinfo *) CMSG_DATA(cmsg);
334 }
335
336 if (!pkti) {
337 MSG(DEBUG, "Received packet without ifindex\n");
338 continue;
339 }
340
341 iface = interface_find_by_ifindex(pkti->ipi_ifindex);
342 if (!iface) {
343 MSG(DEBUG, "Received packet from unconfigured interface %d\n", pkti->ipi_ifindex);
344 continue;
345 }
346
347 interface_recv_msg(iface, &sin.sin_addr, buf, len);
348 } while (1);
349 }
350
351 static void interface_send_msg(struct interface *iface, struct blob_attr *data)
352 {
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),
359 .msg_iov = &iov,
360 .msg_iovlen = 1,
361 .msg_control = cmsg_data,
362 .msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo)),
363 };
364 struct in_pktinfo *pkti;
365 struct cmsghdr *cmsg;
366
367 a.sin_family = AF_INET;
368 a.sin_port = htons(16720);
369 a.sin_addr.s_addr = ~0;
370
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;
376
377 pkti = (struct in_pktinfo *) CMSG_DATA(cmsg);
378 pkti->ipi_ifindex = iface->ifindex;
379
380 iov.iov_base = data;
381 iov.iov_len = blob_pad_len(data);
382
383 if (sendmsg(remote_fd.fd, &m, 0) < 0)
384 perror("sendmsg");
385 }
386
387 static void usteer_send_sta_info(struct sta_info *sta)
388 {
389 int seen = current_time - sta->seen;
390 void *c;
391
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);
399 }
400
401 static void usteer_send_node(struct usteer_node *node, struct sta_info *sta)
402 {
403 void *c, *s, *r;
404
405 c = blob_nest_start(&buf, 0);
406
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);
414 if (node->rrm_nr) {
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);
420 }
421
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));
426
427 s = blob_nest_start(&buf, APMSG_NODE_STATIONS);
428
429 if (sta) {
430 usteer_send_sta_info(sta);
431 } else {
432 list_for_each_entry(sta, &node->sta_info, node_list)
433 usteer_send_sta_info(sta);
434 }
435
436 blob_nest_end(&buf, s);
437
438 blob_nest_end(&buf, c);
439 }
440
441 static void
442 usteer_check_timeout(void)
443 {
444 struct usteer_remote_node *node, *tmp;
445 int timeout = config.remote_node_timeout / config.remote_update_interval;
446
447 avl_for_each_element_safe(&remote_nodes, node, avl, tmp) {
448 if (node->check++ > timeout)
449 remote_node_free(node);
450 }
451 }
452
453 static void *
454 usteer_update_init(void)
455 {
456 blob_buf_init(&buf, 0);
457 blob_put_int32(&buf, APMSG_ID, local_id);
458 blob_put_int32(&buf, APMSG_SEQ, ++msg_seq);
459
460 return blob_nest_start(&buf, APMSG_NODES);
461 }
462
463 static void
464 usteer_update_send(void *c)
465 {
466 struct interface *iface;
467
468 blob_nest_end(&buf, c);
469
470 vlist_for_each_element(&interfaces, iface, node)
471 interface_send_msg(iface, buf.head);
472 }
473
474 void
475 usteer_send_sta_update(struct sta_info *si)
476 {
477 void *c = usteer_update_init();
478 usteer_send_node(si->node, si);
479 usteer_update_send(c);
480 }
481
482 static void
483 usteer_send_update_timer(struct uloop_timeout *t)
484 {
485 struct usteer_node *node;
486 void *c;
487
488 MSG_T("remote_update_interval", "start remote update (interval=%u)\n",
489 config.remote_update_interval);
490
491 usteer_update_time();
492 uloop_timeout_set(t, config.remote_update_interval);
493
494 c = usteer_update_init();
495 avl_for_each_element(&local_nodes, node, avl)
496 usteer_send_node(node, NULL);
497
498 usteer_update_send(c);
499 usteer_check_timeout();
500 }
501
502 static int
503 usteer_init_local_id(void)
504 {
505 FILE *f;
506
507 f = fopen("/dev/urandom", "r");
508 if (!f) {
509 perror("fopen(/dev/urandom)");
510 return -1;
511 }
512
513 if (fread(&local_id, sizeof(local_id), 1, f) < 1)
514 return -1;
515
516 fclose(f);
517 return 0;
518 }
519
520 static void
521 usteer_reload_timer(struct uloop_timeout *t)
522 {
523 int yes = 1;
524 int fd;
525
526 if (remote_fd.registered) {
527 uloop_fd_delete(&remote_fd);
528 close(remote_fd.fd);
529 }
530
531 fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK |
532 USOCK_NUMERIC | USOCK_IPV4ONLY,
533 "0.0.0.0", APMGR_PORT_STR);
534 if (fd < 0) {
535 perror("usock");
536 return;
537 }
538
539 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0)
540 perror("setsockopt(IP_PKTINFO)");
541
542 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0)
543 perror("setsockopt(SO_BROADCAST)");
544
545 remote_fd.fd = fd;
546 remote_fd.cb = interface_recv;
547 uloop_fd_add(&remote_fd, ULOOP_READ);
548 }
549
550 int usteer_interface_init(void)
551 {
552 if (usteer_init_local_id())
553 return -1;
554
555 remote_timer.cb = usteer_send_update_timer;
556 remote_timer.cb(&remote_timer);
557
558 reload_timer.cb = usteer_reload_timer;
559 reload_timer.cb(&reload_timer);
560
561 return 0;
562 }