sta-info: add last_connected field
[project/usteer.git] / parse.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 "usteer.h"
21 #include "remote.h"
22
23 bool parse_apmsg(struct apmsg *msg, struct blob_attr *data)
24 {
25 static const struct blob_attr_info policy[__APMSG_MAX] = {
26 [APMSG_ID] = { .type = BLOB_ATTR_INT32 },
27 [APMSG_SEQ] = { .type = BLOB_ATTR_INT32 },
28 [APMSG_NODES] = { .type = BLOB_ATTR_NESTED },
29 [APMSG_HOST_INFO] = { .type = BLOB_ATTR_NESTED },
30 };
31 struct blob_attr *tb[__APMSG_MAX];
32
33 blob_parse(data, tb, policy, __APMSG_MAX);
34 if (!tb[APMSG_ID] || !tb[APMSG_SEQ] || !tb[APMSG_NODES])
35 return false;
36
37 msg->id = blob_get_int32(tb[APMSG_ID]);
38 msg->seq = blob_get_int32(tb[APMSG_SEQ]);
39 msg->nodes = tb[APMSG_NODES];
40 msg->host_info = tb[APMSG_HOST_INFO];
41
42 return true;
43 }
44
45 static int
46 get_int32(struct blob_attr *attr)
47 {
48 if (!attr)
49 return 0;
50
51 return blob_get_int32(attr);
52 }
53
54 bool parse_apmsg_node(struct apmsg_node *msg, struct blob_attr *data)
55 {
56 static const struct blob_attr_info policy[__APMSG_NODE_MAX] = {
57 [APMSG_NODE_NAME] = { .type = BLOB_ATTR_STRING },
58 [APMSG_NODE_BSSID] = { .type = BLOB_ATTR_BINARY },
59 [APMSG_NODE_FREQ] = { .type = BLOB_ATTR_INT32 },
60 [APMSG_NODE_N_ASSOC] = { .type = BLOB_ATTR_INT32 },
61 [APMSG_NODE_MAX_ASSOC] = { .type = BLOB_ATTR_INT32 },
62 [APMSG_NODE_STATIONS] = { .type = BLOB_ATTR_NESTED },
63 [APMSG_NODE_NOISE] = { .type = BLOB_ATTR_INT32 },
64 [APMSG_NODE_LOAD] = { .type = BLOB_ATTR_INT32 },
65 [APMSG_NODE_RRM_NR] = { .type = BLOB_ATTR_NESTED },
66 [APMSG_NODE_NODE_INFO] = { .type = BLOB_ATTR_NESTED },
67 };
68 struct blob_attr *tb[__APMSG_NODE_MAX];
69 struct blob_attr *cur;
70
71 blob_parse(data, tb, policy, __APMSG_NODE_MAX);
72 if (!tb[APMSG_NODE_NAME] ||
73 !tb[APMSG_NODE_BSSID] ||
74 blob_len(tb[APMSG_NODE_BSSID]) != 6 ||
75 !tb[APMSG_NODE_FREQ] ||
76 !tb[APMSG_NODE_N_ASSOC] ||
77 !tb[APMSG_NODE_STATIONS] ||
78 !tb[APMSG_NODE_SSID])
79 return false;
80
81 msg->name = blob_data(tb[APMSG_NODE_NAME]);
82 msg->n_assoc = blob_get_int32(tb[APMSG_NODE_N_ASSOC]);
83 msg->freq = blob_get_int32(tb[APMSG_NODE_FREQ]);
84 msg->stations = tb[APMSG_NODE_STATIONS];
85 msg->ssid = blob_data(tb[APMSG_NODE_SSID]);
86 msg->bssid = blob_data(tb[APMSG_NODE_BSSID]);
87
88 msg->noise = get_int32(tb[APMSG_NODE_NOISE]);
89 msg->load = get_int32(tb[APMSG_NODE_LOAD]);
90 msg->max_assoc = get_int32(tb[APMSG_NODE_MAX_ASSOC]);
91 msg->rrm_nr = NULL;
92
93 cur = tb[APMSG_NODE_RRM_NR];
94 if (cur && blob_len(cur) >= sizeof(struct blob_attr) &&
95 blob_len(cur) >= blob_pad_len(blob_data(cur))) {
96 int rem;
97
98 msg->rrm_nr = blob_data(cur);
99
100 blobmsg_for_each_attr(cur, msg->rrm_nr, rem) {
101 if (blobmsg_check_attr(cur, false))
102 continue;
103 if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
104 continue;
105 msg->rrm_nr = NULL;
106 break;
107 }
108
109 if (msg->rrm_nr &&
110 blobmsg_type(msg->rrm_nr) != BLOBMSG_TYPE_ARRAY)
111 msg->rrm_nr = NULL;
112 }
113
114 msg->node_info = tb[APMSG_NODE_NODE_INFO];
115
116 return true;
117 }
118
119 bool parse_apmsg_sta(struct apmsg_sta *msg, struct blob_attr *data)
120 {
121 static const struct blob_attr_info policy[__APMSG_STA_MAX] = {
122 [APMSG_STA_ADDR] = { .type = BLOB_ATTR_BINARY },
123 [APMSG_STA_SIGNAL] = { .type = BLOB_ATTR_INT32 },
124 [APMSG_STA_SEEN] = { .type = BLOB_ATTR_INT32 },
125 [APMSG_STA_TIMEOUT] = { .type = BLOB_ATTR_INT32 },
126 [APMSG_STA_CONNECTED] = { .type = BLOB_ATTR_INT8 },
127 [APMSG_STA_LAST_CONNECTED] = { .type = BLOB_ATTR_INT32 },
128 };
129 struct blob_attr *tb[__APMSG_STA_MAX];
130
131 blob_parse(data, tb, policy, __APMSG_STA_MAX);
132 if (!tb[APMSG_STA_ADDR] ||
133 !tb[APMSG_STA_SIGNAL] ||
134 !tb[APMSG_STA_SEEN] ||
135 !tb[APMSG_STA_TIMEOUT] ||
136 !tb[APMSG_STA_CONNECTED] ||
137 !tb[APMSG_STA_LAST_CONNECTED])
138 return false;
139
140 if (blob_len(tb[APMSG_STA_ADDR]) != sizeof(msg->addr))
141 return false;
142
143 memcpy(msg->addr, blob_data(tb[APMSG_STA_ADDR]), sizeof(msg->addr));
144 msg->signal = blob_get_int32(tb[APMSG_STA_SIGNAL]);
145 msg->seen = blob_get_int32(tb[APMSG_STA_SEEN]);
146 msg->timeout = blob_get_int32(tb[APMSG_STA_TIMEOUT]);
147 msg->connected = blob_get_int8(tb[APMSG_STA_CONNECTED]);
148 msg->last_connected = blob_get_int32(tb[APMSG_STA_LAST_CONNECTED]);
149
150 return true;
151 }