remote: close file on usteer_init_local_id fread fail
[project/usteer.git] / event.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 #include "usteer.h"
20 #include "event.h"
21
22 #define UEV_LOG_MAXLEN 256
23
24 static struct blob_buf b;
25 static const char * const uev_name[] = {
26 [UEV_PROBE_REQ_ACCEPT] = "probe_req_accept",
27 [UEV_PROBE_REQ_DENY] = "probe_req_deny",
28 [UEV_AUTH_REQ_ACCEPT] = "auth_req_accept",
29 [UEV_AUTH_REQ_DENY] = "auth_req_deny",
30 [UEV_ASSOC_REQ_ACCEPT] = "assoc_req_accept",
31 [UEV_ASSOC_REQ_DENY] = "assoc_req_deny",
32 [UEV_LOAD_KICK_TRIGGER] = "load_kick_trigger",
33 [UEV_LOAD_KICK_RESET] = "load_kick_reset",
34 [UEV_LOAD_KICK_MIN_CLIENTS] = "load_kick_min_clients",
35 [UEV_LOAD_KICK_NO_CLIENT] = "load_kick_no_client",
36 [UEV_LOAD_KICK_CLIENT] = "load_kick_client",
37 [UEV_SIGNAL_KICK] = "signal_kick",
38
39 };
40 static const char * const uev_reason[] = {
41 [UEV_REASON_NONE] = "none",
42 [UEV_REASON_RETRY_EXCEEDED] = "retry_exceeded",
43 [UEV_REASON_LOW_SIGNAL] = "low_signal",
44 [UEV_REASON_CONNECT_DELAY] = "connect_delay",
45 [UEV_REASON_BETTER_CANDIDATE] = "better_candidate",
46 };
47
48 static const char * const uev_select_reason[] = {
49 [UEV_SELECT_REASON_NUM_ASSOC] = "n_assoc",
50 [UEV_SELECT_REASON_SIGNAL] = "signal",
51 [UEV_SELECT_REASON_LOAD] = "load",
52 };
53
54 static void
55 usteer_event_add_node_status(struct usteer_node *node)
56 {
57 blobmsg_add_u32(&b, "load", node->load);
58 blobmsg_add_u32(&b, "assoc", node->n_assoc);
59 }
60
61 static void
62 usteer_event_send_ubus(struct uevent *ev)
63 {
64 void *c;
65 int i;
66
67 if (!usteer_obj.has_subscribers)
68 return;
69
70 blob_buf_init(&b, 0);
71
72 if (ev->node_local)
73 blobmsg_add_string(&b, "node", usteer_node_name(ev->node_local));
74
75 if (ev->sta)
76 blobmsg_printf(&b, "sta", MAC_ADDR_FMT, MAC_ADDR_DATA(ev->sta->addr));
77
78 if (ev->si_cur)
79 blobmsg_add_u32(&b, "signal", (int32_t)ev->si_cur->signal);
80
81 if (ev->reason)
82 blobmsg_add_string(&b, "reason", uev_reason[ev->reason]);
83
84 if (ev->threshold.ref) {
85 c = blobmsg_open_array(&b, "threshold");
86 blobmsg_add_u32(&b, NULL, ev->threshold.cur);
87 blobmsg_add_u32(&b, NULL, ev->threshold.ref);
88 blobmsg_close_array(&b, c);
89 }
90
91 if (ev->select_reasons) {
92 c = blobmsg_open_array(&b, "select_reason");
93 for (i = 0; i < ARRAY_SIZE(uev_select_reason); i++) {
94 if (!(ev->select_reasons & (1 << i)) ||
95 !uev_select_reason[i])
96 continue;
97
98 blobmsg_add_string(&b, NULL, uev_select_reason[i]);
99 }
100 blobmsg_close_array(&b, c);
101 }
102
103 if (ev->node_cur) {
104 c = blobmsg_open_table(&b, "local");
105 usteer_event_add_node_status(ev->node_cur);
106 blobmsg_close_table(&b, c);
107 }
108
109 if (ev->node_other) {
110 c = blobmsg_open_table(&b, "remote");
111 blobmsg_add_string(&b, "name", usteer_node_name(ev->node_other));
112 if (ev->si_other)
113 blobmsg_add_u32(&b, "signal", (int32_t)ev->si_other->signal);
114 usteer_event_add_node_status(ev->node_other);
115 blobmsg_close_table(&b, c);
116 }
117
118 if (ev->count)
119 blobmsg_add_u32(&b, "count", ev->count);
120
121 ubus_notify(ubus_ctx, &usteer_obj, uev_name[ev->type], b.head, -1);
122 }
123
124 static int
125 usteer_event_log_node(char *buf, int len, const char *prefix, struct usteer_node *node)
126 {
127 char *cur = buf;
128 char *end = buf + len;
129
130 cur += snprintf(cur, end - cur, " %sassoc=%d %sload=%d",
131 prefix, node->n_assoc,
132 prefix, node->load);
133
134 return cur - buf;
135 }
136
137 static void
138 usteer_event_log(struct uevent *ev)
139 {
140 char *str, *cur, *end;
141 int i;
142
143 if (!(config.event_log_mask & (1 << ev->type)))
144 return;
145
146 blob_buf_init(&b, 0);
147 cur = str = blobmsg_alloc_string_buffer(&b, NULL, UEV_LOG_MAXLEN);
148 end = str + UEV_LOG_MAXLEN;
149 cur += snprintf(cur, end - cur, "usteer event=%s", uev_name[ev->type]);
150 if (ev->node_local)
151 cur += snprintf(cur, end - cur, " node=%s", usteer_node_name(ev->node_local));
152 if (ev->sta)
153 cur += snprintf(cur, end - cur, " sta=" MAC_ADDR_FMT, MAC_ADDR_DATA(ev->sta->addr));
154 if (ev->reason)
155 cur += snprintf(cur, end - cur, " reason=%s", uev_reason[ev->reason]);
156 if (ev->si_cur)
157 cur += snprintf(cur, end - cur, " signal=%d", ev->si_cur->signal);
158 if (ev->threshold.ref)
159 cur += snprintf(cur, end - cur, " thr=%d/%d", ev->threshold.cur, ev->threshold.ref);
160 if (ev->count)
161 cur += snprintf(cur, end - cur, " count=%d", ev->count);
162 if (ev->node_cur)
163 cur += usteer_event_log_node(cur, end - cur, "", ev->node_cur);
164 if (ev->select_reasons) {
165 bool first = true;
166
167 cur += snprintf(cur, end - cur, " select_reason");
168 for (i = 0; i < ARRAY_SIZE(uev_select_reason); i++) {
169 if (!(ev->select_reasons & (1 << i)) ||
170 !uev_select_reason[i])
171 continue;
172
173 cur += snprintf(cur, end - cur, "%c%s", first ? '=' : ',',
174 uev_select_reason[i]);
175 first = false;
176 }
177 }
178 if (ev->node_other) {
179 cur += snprintf(cur, end - cur, " remote=%s", usteer_node_name(ev->node_other));
180 if (ev->si_other)
181 cur += snprintf(cur, end - cur, " remote_signal=%d",
182 ev->si_other->signal);
183 cur += usteer_event_log_node(cur, end - cur, "remote_", ev->node_other);
184 }
185
186 log_msg(str);
187 }
188
189 void usteer_event(struct uevent *ev)
190 {
191 if (ev->type >= ARRAY_SIZE(uev_name) || !uev_name[ev->type])
192 return;
193
194 if (ev->reason >= ARRAY_SIZE(uev_reason) || !uev_reason[ev->reason])
195 return;
196
197 if (ev->si_cur) {
198 if (!ev->node_local)
199 ev->node_local = ev->si_cur->node;
200 if (!ev->sta)
201 ev->sta = ev->si_cur->sta;
202 }
203
204 if (!ev->node_local && ev->node_cur)
205 ev->node_local = ev->node_cur;
206
207 if (ev->si_other && ev->node_cur && !ev->node_other)
208 ev->node_other = ev->si_other->node;
209
210 usteer_event_send_ubus(ev);
211 usteer_event_log(ev);
212 }
213
214 void config_set_event_log_types(struct blob_attr *attr)
215 {
216 struct blob_attr *cur;
217 int i, rem;
218
219 config.event_log_mask = 0;
220 if (!attr) {
221 static const uint32_t default_log[] = {
222 [MSG_INFO] =
223 (1 << UEV_LOAD_KICK_CLIENT) |
224 (1 << UEV_SIGNAL_KICK) |
225 (1 << UEV_AUTH_REQ_DENY) |
226 (1 << UEV_ASSOC_REQ_DENY),
227 [MSG_VERBOSE] =
228 (1 << UEV_PROBE_REQ_DENY),
229 [MSG_DEBUG] =
230 (1 << UEV_AUTH_REQ_ACCEPT) |
231 (1 << UEV_ASSOC_REQ_ACCEPT) |
232 (1 << UEV_LOAD_KICK_TRIGGER) |
233 (1 << UEV_LOAD_KICK_RESET) |
234 (1 << UEV_LOAD_KICK_MIN_CLIENTS) |
235 (1 << UEV_LOAD_KICK_NO_CLIENT),
236 };
237
238 if (config.debug_level >= MSG_DEBUG_ALL) {
239 config.event_log_mask = ~0;
240 return;
241 }
242
243 for (i = 0; i < ARRAY_SIZE(default_log) && i <= config.debug_level; i++)
244 config.event_log_mask |= default_log[i];
245
246 return;
247 }
248
249 if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
250 return;
251
252 blobmsg_for_each_attr(cur, attr, rem) {
253 const char *name = blobmsg_get_string(cur);
254
255 for (i = 0; i < ARRAY_SIZE(uev_name); i++) {
256 if (!uev_name[i] || strcmp(uev_name[i], name) != 0)
257 continue;
258
259 config.event_log_mask |= (1 << i);
260 break;
261 }
262 }
263 }
264
265 void config_get_event_log_types(struct blob_buf *buf)
266 {
267 uint32_t mask = config.event_log_mask;
268 void *c;
269 int i;
270
271 c = blobmsg_open_array(buf, "event_log_types");
272 for (i = 0; mask && i < ARRAY_SIZE(uev_name); i++) {
273 bool cur = mask & 1;
274
275 mask >>= 1;
276 if (!cur)
277 continue;
278
279 blobmsg_add_string(buf, NULL, uev_name[i]);
280 }
281 blobmsg_close_array(buf, c);
282 }