/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Copyright (C) 2020 embedd.ch * Copyright (C) 2020 Felix Fietkau * Copyright (C) 2020 John Crispin */ #include "usteer.h" #include "remote.h" bool parse_apmsg(struct apmsg *msg, struct blob_attr *data) { static const struct blob_attr_info policy[__APMSG_MAX] = { [APMSG_ID] = { .type = BLOB_ATTR_INT32 }, [APMSG_SEQ] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODES] = { .type = BLOB_ATTR_NESTED }, [APMSG_HOST_INFO] = { .type = BLOB_ATTR_NESTED }, }; struct blob_attr *tb[__APMSG_MAX]; blob_parse(data, tb, policy, __APMSG_MAX); if (!tb[APMSG_ID] || !tb[APMSG_SEQ] || !tb[APMSG_NODES]) return false; msg->id = blob_get_int32(tb[APMSG_ID]); msg->seq = blob_get_int32(tb[APMSG_SEQ]); msg->nodes = tb[APMSG_NODES]; msg->host_info = tb[APMSG_HOST_INFO]; return true; } static int get_int32(struct blob_attr *attr) { if (!attr) return 0; return blob_get_int32(attr); } bool parse_apmsg_node(struct apmsg_node *msg, struct blob_attr *data) { static const struct blob_attr_info policy[__APMSG_NODE_MAX] = { [APMSG_NODE_NAME] = { .type = BLOB_ATTR_STRING }, [APMSG_NODE_BSSID] = { .type = BLOB_ATTR_BINARY }, [APMSG_NODE_FREQ] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODE_N_ASSOC] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODE_MAX_ASSOC] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODE_STATIONS] = { .type = BLOB_ATTR_NESTED }, [APMSG_NODE_NOISE] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODE_LOAD] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODE_RRM_NR] = { .type = BLOB_ATTR_NESTED }, [APMSG_NODE_NODE_INFO] = { .type = BLOB_ATTR_NESTED }, [APMSG_NODE_CHANNEL] = { .type = BLOB_ATTR_INT32 }, [APMSG_NODE_OP_CLASS] = { .type = BLOB_ATTR_INT32 }, }; struct blob_attr *tb[__APMSG_NODE_MAX]; struct blob_attr *cur; blob_parse(data, tb, policy, __APMSG_NODE_MAX); if (!tb[APMSG_NODE_NAME] || !tb[APMSG_NODE_BSSID] || blob_len(tb[APMSG_NODE_BSSID]) != 6 || !tb[APMSG_NODE_FREQ] || !tb[APMSG_NODE_N_ASSOC] || !tb[APMSG_NODE_STATIONS] || !tb[APMSG_NODE_SSID]) return false; msg->name = blob_data(tb[APMSG_NODE_NAME]); msg->n_assoc = blob_get_int32(tb[APMSG_NODE_N_ASSOC]); msg->freq = blob_get_int32(tb[APMSG_NODE_FREQ]); msg->stations = tb[APMSG_NODE_STATIONS]; msg->ssid = blob_data(tb[APMSG_NODE_SSID]); msg->bssid = blob_data(tb[APMSG_NODE_BSSID]); msg->noise = get_int32(tb[APMSG_NODE_NOISE]); msg->load = get_int32(tb[APMSG_NODE_LOAD]); msg->max_assoc = get_int32(tb[APMSG_NODE_MAX_ASSOC]); msg->rrm_nr = NULL; if (tb[APMSG_NODE_CHANNEL] && tb[APMSG_NODE_OP_CLASS]) { msg->channel = blob_get_int32(tb[APMSG_NODE_CHANNEL]); msg->op_class = blob_get_int32(tb[APMSG_NODE_OP_CLASS]); } cur = tb[APMSG_NODE_RRM_NR]; if (cur && blob_len(cur) >= sizeof(struct blob_attr) && blob_len(cur) >= blob_pad_len(blob_data(cur))) { int rem; msg->rrm_nr = blob_data(cur); blobmsg_for_each_attr(cur, msg->rrm_nr, rem) { if (blobmsg_check_attr(cur, false)) continue; if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING) continue; msg->rrm_nr = NULL; break; } if (msg->rrm_nr && blobmsg_type(msg->rrm_nr) != BLOBMSG_TYPE_ARRAY) msg->rrm_nr = NULL; } msg->node_info = tb[APMSG_NODE_NODE_INFO]; return true; } bool parse_apmsg_sta(struct apmsg_sta *msg, struct blob_attr *data) { static const struct blob_attr_info policy[__APMSG_STA_MAX] = { [APMSG_STA_ADDR] = { .type = BLOB_ATTR_BINARY }, [APMSG_STA_SIGNAL] = { .type = BLOB_ATTR_INT32 }, [APMSG_STA_SEEN] = { .type = BLOB_ATTR_INT32 }, [APMSG_STA_TIMEOUT] = { .type = BLOB_ATTR_INT32 }, [APMSG_STA_CONNECTED] = { .type = BLOB_ATTR_INT8 }, [APMSG_STA_LAST_CONNECTED] = { .type = BLOB_ATTR_INT32 }, }; struct blob_attr *tb[__APMSG_STA_MAX]; blob_parse(data, tb, policy, __APMSG_STA_MAX); if (!tb[APMSG_STA_ADDR] || !tb[APMSG_STA_SIGNAL] || !tb[APMSG_STA_SEEN] || !tb[APMSG_STA_TIMEOUT] || !tb[APMSG_STA_CONNECTED] || !tb[APMSG_STA_LAST_CONNECTED]) return false; if (blob_len(tb[APMSG_STA_ADDR]) != sizeof(msg->addr)) return false; memcpy(msg->addr, blob_data(tb[APMSG_STA_ADDR]), sizeof(msg->addr)); msg->signal = blob_get_int32(tb[APMSG_STA_SIGNAL]); msg->seen = blob_get_int32(tb[APMSG_STA_SEEN]); msg->timeout = blob_get_int32(tb[APMSG_STA_TIMEOUT]); msg->connected = blob_get_int8(tb[APMSG_STA_CONNECTED]); msg->last_connected = blob_get_int32(tb[APMSG_STA_LAST_CONNECTED]); return true; }