minstrel-rcd: add work-in-progress minstrel remote control daemon
[openwrt/staging/nbd.git] / package / utils / minstrel-rcd / src / client.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
3 #include "rcd.h"
4
5 static LIST_HEAD(clients);
6
7 void rcd_client_set_phy_state(struct client *cl, struct phy *phy, bool add)
8 {
9 if (!cl) {
10 list_for_each_entry(cl, &clients, list)
11 rcd_client_set_phy_state(cl, phy, add);
12 return;
13 }
14
15 if (add && !cl->init_done) {
16 rcd_phy_dump(cl, phy);
17 cl->init_done = true;
18 }
19
20 client_phy_printf(cl, phy, "0;%s\n", add ? "add" : "remove");
21 }
22
23 void rcd_client_phy_event(struct phy *phy, const char *str)
24 {
25 struct client *cl;
26
27 list_for_each_entry(cl, &clients, list)
28 client_phy_printf(cl, phy, "%s\n", str);
29 }
30
31 static void
32 client_start(struct client *cl)
33 {
34 struct phy *phy;
35
36 vlist_for_each_element(&phy_list, phy, node)
37 rcd_client_set_phy_state(cl, phy, true);
38 }
39
40 static int
41 client_handle_data(struct client *cl, char *data)
42 {
43 char *sep;
44 int len = 0;
45
46 while ((sep = strchr(data, '\n')) != NULL) {
47 len += sep - data + 1;
48 if (sep[-1] == '\r')
49 sep[-1] = 0;
50 *sep = 0;
51 rcd_phy_control(cl, data);
52 data = sep + 1;
53 }
54
55 return len;
56 }
57
58 static void
59 client_notify_read(struct ustream *s, int bytes)
60 {
61 struct client *cl = container_of(s, struct client, sfd.stream);
62 char *data;
63 int len;
64
65 while (1) {
66 data = ustream_get_read_buf(s, &len);
67 if (!data)
68 return;
69
70 len = client_handle_data(cl, data);
71 if (!len)
72 return;
73
74 ustream_consume(s, len);
75 }
76 }
77
78 static void
79 client_notify_state(struct ustream *s)
80 {
81 struct client *cl = container_of(s, struct client, sfd.stream);
82
83 if (!s->write_error && !s->eof)
84 return;
85
86 ustream_free(s);
87 close(cl->sfd.fd.fd);
88 list_del(&cl->list);
89 free(cl);
90 }
91
92 void rcd_client_accept(int fd)
93 {
94 struct ustream *us;
95 struct client *cl;
96
97 cl = calloc(1, sizeof(*cl));
98 us = &cl->sfd.stream;
99 us->notify_read = client_notify_read;
100 us->notify_state = client_notify_state;
101 us->string_data = true;
102 ustream_fd_init(&cl->sfd, fd);
103 list_add_tail(&cl->list, &clients);
104 client_start(cl);
105 }