diff --git a/src/host.c b/src/host.c index 7bdc6730ee43bb200adc1b9722906b00229e623c..9aa268476f88ab0ff00058b068bf12564450a217 100644 --- a/src/host.c +++ b/src/host.c @@ -319,16 +319,11 @@ struct host_node *host_topo_node_add(struct topologyd_private *priv, struct node p->is_ipaddr = 0; } else { p->is_ipaddr = 1; - if (!has_ip && p->intf_type == HOST_TYPE_WIFI && !p->is_in_assoclist) { - if (!host_get_arping_status(p->ipv4addr)) { - if (p->is_ieee1905_node == 1) - host_send_client_event(priv, p, 1); - host_change_active_state(priv, p, 1); - } else - host_change_active_state(priv, p, 0); - } } + if (p->intf_type == HOST_TYPE_WIFI) + p->age_time = time(NULL); + if (send_ev && p->active && !is_wifi && p->is_ipaddr) host_send_client_event(priv, p, 1); @@ -919,7 +914,8 @@ int host_get_wifi_data(struct topologyd_private *priv, struct host_node *p) dbg("%s: sta: is Wifi %s\n", __func__, macstr); p->intf_type = HOST_TYPE_WIFI; - host_change_active_state(priv, p, 1); + if (p->active != 1) + host_change_active_state(priv, p, 1); p->is_in_assoclist = true; break; } @@ -1067,22 +1063,14 @@ void host_arp_table_refresh(struct uloop_timeout *t) host_get_table_cb(priv); } -int host_get_arping_status(char *ipaddr_str) +void host_wifi_table_refresh(struct uloop_timeout *t) { - int ret = -1; + struct topologyd_private *priv = + container_of(t, struct topologyd_private, host_wifi_timer); dbg("Inside %s %d\n", __func__, __LINE__); - if (ipaddr_str == NULL) - return -1; - ret = host_send_arping(ipaddr_str, "br-lan", 1000, 1); - - if (ret != 0) - ret = 0; - else - ret = -1; - - return ret; + host_get_wifi_table_cb(priv); } int host_send_arp_req(char *ipaddr_str) @@ -1212,6 +1200,7 @@ void host_run_status_check(struct topologyd_private *priv) if (!priv) return; host_get_interface_type(priv); + host_send_topology_query_all(priv); for (i = 0; i < NODE_HTABLE_SIZE; i++) { if (hlist_empty(&priv->host.node_htable[i])) @@ -1243,13 +1232,8 @@ void host_run_status_check(struct topologyd_private *priv) if (p->is_in_assoclist) { host_send_client_event(priv, p, 1); } else if (p->intf_type == HOST_TYPE_WIFI && !p->is_in_assoclist) { - if (!host_get_arping_status(p->ipv4addr)) { + if (p->active == 1) host_send_client_event(priv, p, 1); - host_change_active_state(priv, p, 1); - } else { - //host_send_client_event(priv, p, 0); - host_change_active_state(priv, p, 0); - } } } } @@ -1258,7 +1242,6 @@ void host_run_status_check(struct topologyd_private *priv) } else if (p->is_ieee1905_node) memset(p->device, 0, 16); - if (host_get_ipaddr_hostname(priv, mac_str, p)) p->is_ipaddr = 0; else @@ -1280,6 +1263,7 @@ void host_run_status_check(struct topologyd_private *priv) /* Here we set the timer to check the arp request */ uloop_timeout_set(&priv->host_arp_timer, HOST_ARP_TIMER * 1000); + uloop_timeout_set(&priv->host_wifi_timer, HOST_WIFI_TIMER * 1000); } @@ -1336,6 +1320,44 @@ void host_get_table_cb(struct topologyd_private *priv) } } +void host_get_wifi_table_cb(struct topologyd_private *priv) +{ + struct host_node *p; + int i = 0; + char mac_str[18] = { 0 }; + + dbg("Inside %s %d\n", __func__, __LINE__); + if (!priv) + return; + + for (i = 0; i < NODE_HTABLE_SIZE; i++) { + if (hlist_empty(&priv->host.node_htable[i])) + continue; + + hlist_for_each_entry(p, &priv->host.node_htable[i], hlist) { + bool has_ip = p->is_ipaddr; + if (p->al_node) + continue; + if (hwaddr_is_zero(p->hwaddr)) // TODO: unlikely.. + continue; + hwaddr_ntoa(p->hwaddr, mac_str); + dbg("macstr is %s\n", mac_str); + + if (p->intf_type != HOST_TYPE_ETHER && !p->is_ieee1905_node) { + if (p->active == 1) { + time_t now; + double diff_t; + now = time(NULL); + diff_t = difftime(now, p->age_time); + if (diff_t > WIFI_TIME_OUT) + host_topo_node_del(priv, NULL, p->hwaddr, 1); + dbg("Timeout diff is ===================%f\n", diff_t); + } + } + } + } +} + void host_process_topo_notification(uint8_t *tlv, struct topologyd_private *priv) { @@ -1355,11 +1377,19 @@ void host_process_topo_notification(uint8_t *tlv, struct topologyd_private *priv dbg("Topology Notification TLV client addr " MACFMT " assoc_event 0x%02x\n", MAC2STR(hwaddr), assoc_event); if (assoc_event == 0x80) { - struct host_node *n; - - n = host_topo_node_add(priv, NULL, hwaddr, 1); - if (n->is_ipaddr) - host_send_client_event(priv, n, 1); + struct host_node *hn; + hn = host_node_lookup(priv->host.node_htable, hwaddr); + if (!hn) { + hn = host_topo_node_add(priv, NULL, hwaddr, 1); + if (hn->is_ipaddr) + host_send_client_event(priv, hn, 1); + } else { + if (hn->active == 0) { + hn = host_topo_node_add(priv, NULL, hwaddr, 1); + if (hn->is_ipaddr) + host_send_client_event(priv, hn, 1); + } + } } else host_topo_node_del(priv, NULL, hwaddr, 1); @@ -1371,6 +1401,108 @@ void host_process_topo_notification(uint8_t *tlv, struct topologyd_private *priv } } +/*Here we parse the packetstream to get the tlv structure*/ +struct tlv_assoc_client *host_process_topo_response(uint8_t *packet_stream, struct topologyd_private *priv) +{ + struct tlv_assoc_client *ret; + uint8_t *p; + uint16_t len; + uint8_t i, j; + + dbg("Inside %s %d\n", __func__, __LINE__); + + if (packet_stream == NULL || priv == NULL) + return NULL; + + ret = calloc(1, sizeof(*ret)); + if (ret == NULL) { + err("calloc failed\n"); + return NULL; + } + + p = packet_stream + 1; + _E2B(&p, &len); + + ret->tlv_type = MAP_TLV_ASSOCIATED_CLIENTS; + if (len == 0) { + free(ret); + return NULL; + } + _E1B(&p, &ret->bss_nr); + + if (ret->bss_nr > 0) { + ret->bss = calloc((ret->bss_nr), sizeof(*(ret->bss))); + if (ret->bss == NULL) { + err("calloc failed\n"); + free(ret); + return NULL; + } + for (i = 0; i < ret->bss_nr; i++) { + _EnB(&p, ret->bss[i].bssid, 6); + _E2B(&p, &ret->bss[i].assoc_clients_nr); + if (ret->bss[i].assoc_clients_nr > 0) { + ret->bss[i].clients = calloc((ret->bss[i].assoc_clients_nr), sizeof(*(ret->bss[i].clients))); + if (ret->bss[i].clients == NULL) { + err("calloc failed\n"); + free(ret->bss); + free(ret); + return NULL; + } + dbg("%s %d client nr = [%d] \n", __func__, __LINE__, ret->bss[i].assoc_clients_nr); + for (j = 0; j < ret->bss[i].assoc_clients_nr; j++) { + _EnB(&p, ret->bss[i].clients[j].client_addr, 6); + _E2B(&p, &ret->bss[i].clients[j].uptime); + } + } + } + } + + if (p - (packet_stream + 3) != len) { + // Malformed packet + err("packet length error %s %d\n", __func__, __LINE__); + for (i = 0; i < ret->bss_nr; i++) { + free(ret->bss[i].clients); + } + free(ret->bss); + free(ret); + return NULL; + } + return ret; +} + +int host_process_tlv(uint8_t *tlvs, struct topologyd_private *priv) +{ + uint8_t i, tlv_count; + uint8_t *cur_stream; + + if (tlvs == NULL || priv == NULL) + return -1; + + dbg("Inside %s %d\n", __func__, __LINE__); + tlv_count = count_tlv_present_instream_unsafe(tlvs); + + cur_stream = tlvs; + for (i = 0; i < tlv_count - 1; i++) { + uint16_t len = get_tlv_packet_len(cur_stream); + uint8_t type = get_tlv_packet_type(cur_stream); + + if (type == MAP_TLV_ASSOCIATED_CLIENTS) { + //Here parse the assoc list + dbg("Received MAP_TLV_ASSOCIATED_CLIENTS %s %d\n", __func__, __LINE__); + struct tlv_assoc_client *ret = host_process_topo_response(cur_stream, priv); + if (ret == NULL) + return -1; + //Here we call the function to mark the host mac time + host_update_wifi_time_age(priv, ret); + free(ret); + } + // Move to the next tlv + cur_stream = cur_stream + len; + } + + return 0; +} + void host_agent_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg) @@ -1398,7 +1530,7 @@ void host_agent_event_handler(struct ubus_context *ctx, } dbg("Inside host agent event handler %hu %hu %s", msg_type, msg_mid, itfr_name); - if (!(msg_type == CMDU_TYPE_TOPOLOGY_NOTIFICATION)) { + if (!(msg_type == CMDU_TYPE_TOPOLOGY_NOTIFICATION || msg_type == CMDU_TYPE_TOPOLOGY_RESPONSE)) { if (tlv != NULL) free(tlv); return; @@ -1416,6 +1548,11 @@ void host_agent_event_handler(struct ubus_context *ctx, host_process_topo_notification(tlv, priv); } break; + case CMDU_TYPE_TOPOLOGY_RESPONSE: + { + host_process_tlv(tlv, priv); + } + break; default: dbg("Event handler received default message\n"); break; @@ -1437,3 +1574,122 @@ void host_set_interface_type(struct host_node *p) (p->intf_type == HOST_TYPE_WIFI ? "wifi" : "eth")); config_set_host_option("hosts", "host", "macaddr", mac_str, "active", "1"); } + +int host_update_wifi_time_age(struct topologyd_private *priv, + struct tlv_assoc_client *p) +{ + struct host_node *hn = NULL; + if (p == NULL || priv == NULL) + return -1; + + int j = 0, k = 0; + dbg("\tbss_nr: %d\n", p->bss_nr); + for (j = 0; j < p->bss_nr; j++) { + dbg("\t\tbssid: " MACFMT "\n", + MAC2STR(p->bss[j].bssid)); + dbg("\t\tassoc_clients_nr: %d\n", + p->bss[j].assoc_clients_nr); + for (k = 0; k < p->bss[j].assoc_clients_nr; k++) { + dbg("\t\t\tclient_addr: " MACFMT "\n", + MAC2STR(p->bss[j].clients[k].client_addr)); + //Here look at the host node of this assoc client and update the time + hn = host_node_lookup(priv->host.node_htable, p->bss[j].clients[k].client_addr); + if (!hn) { + hn = host_topo_node_add(priv, NULL, p->bss[j].clients[k].client_addr, 1); + if (hn->is_ipaddr) + host_send_client_event(priv, hn, 1); + } else { + if (hn->active == 0) { + hn = host_topo_node_add(priv, NULL, p->bss[j].clients[k].client_addr, 1); + if (hn->is_ipaddr) + host_send_client_event(priv, hn, 1); + } + } + hn->age_time = time(NULL); + dbg("\t\t\tuptime: 0x%04x\n", + p->bss[j].clients[k].uptime); + } + } +} + +void host_send_topology_query_all(struct topologyd_private *priv) +{ + int i = 0; + struct node *p; + + dbg("Inside %s %d\n", __func__, __LINE__); + + //Send the query to selfnode + host_send_mid_topology_query(priv, NULL); + for (i = 0; i < NODE_HTABLE_SIZE; i++) { + if (hlist_empty(&priv->topo.node_htable[i])) + continue; + + hlist_for_each_entry(p, &priv->topo.node_htable[i], hlist) { + if (hwaddr_is_zero(p->hwaddr)) // TODO: unlikely.. + continue; + host_send_mid_topology_query(priv, p->hwaddr); + } + } +} + +static void host_mid_response_cb(struct ubus_request *req, + int mtype, struct blob_attr *msg) +{ + json_object *jroot = NULL; + char *str = NULL; + uint32_t msg_mid = 0; + + dbg("Inside %s %d\n", __func__, __LINE__); + if (!msg) + return; + + str = blobmsg_format_json_indent(msg, true, -1); + if (str) { + jroot = json_tokener_parse(str); + free(str); + } + + if (jroot) { + msg_mid = _json_obj_get_int(jroot, "mid"); + json_safe_put(jroot); + } + dbg("Inside %s %d mid = [%d]\n", __func__, __LINE__, msg_mid); + + return; +} + +int host_send_mid_topology_query(struct topologyd_private *p, uint8_t *dst_mac) +{ + int ret = 0; + uint32_t id = 0; + struct blob_buf bb = { 0 }; + char src_mac[18] = {0}; + char dest_mac[18] = {0}; + + dbg("Inside %s \n", __func__); + hwaddr_ntoa(p->selfnode.hwaddr, src_mac); + blob_buf_init(&bb, 0); + blobmsg_add_u32(&bb, "type", 2); + blobmsg_add_string(&bb, "egress", "br-lan"); + blobmsg_add_string(&bb, "source", src_mac); + if (dst_mac != NULL) { + hwaddr_ntoa(dst_mac, dest_mac); + dbg("Inside %s mac = [%s]\n", __func__, dest_mac); + blobmsg_add_string(&bb, "dst_macaddr", dest_mac); + } + + ubus_lookup_id(p->ctx, "map.1905", &id); + if (id == 0) { + blob_buf_free(&bb); + return -1; + } + + ret = ubus_invoke(p->ctx, id, "send", bb.head, + host_mid_response_cb, NULL, 1000); + if (ret) + err("Failed to get mid for host topology query\n"); + + blob_buf_free(&bb); + return ret; +} diff --git a/src/host.h b/src/host.h index 4c3115f3368a7da51cbaf791dcf61b00f2594632..fa8fc241643129b876a48aa0abf0721bce62c630 100644 --- a/src/host.h +++ b/src/host.h @@ -13,6 +13,7 @@ #include "topologyd.h" #define MAP_TLV_CLIENT_ASSOCIATION_EVENT 0x92 +#define MAP_TLV_ASSOCIATED_CLIENTS 0x84 #define HOST_NODE_MAX 500 #define HOST_MAX_IPV6ADDR 20 @@ -21,7 +22,25 @@ #define NEIGH_CMD "ip neigh show nud reachable|awk '{print $5}'|grep %s" #define ARPING_CMD "arping -I br-lan -c 1 -w 1 -D %s| grep Received| awk '{print $2}'" #define HOST_ARP_TIMER 2 +#define HOST_WIFI_TIMER 5 +#define WIFI_TIME_OUT 6 +/** + * @brief Associated Clients TLV associated structures ("Section 17.2.5 of [1]") + */ +struct tlv_assoc_client { + uint8_t tlv_type; + uint16_t tlv_len; + uint8_t bss_nr; + struct { + uint8_t bssid[6]; + uint16_t assoc_clients_nr; + struct { + uint8_t client_addr[6]; + uint16_t uptime; + } *clients; + } *bss; +}; enum host_types { HOST_TYPE_ETHER = 0, @@ -39,6 +58,11 @@ enum address_type { HOST_ADDR_DHCP, }; +struct host_topo_query { + struct topologyd_private *p; + uint8_t dst_mac[6]; +}; + struct host_node { uint8_t hwaddr[6]; //macaddress of the node char device[16]; @@ -79,6 +103,8 @@ struct host_node { int port_no; int active_connections; struct host_node *al_node; + //struct timeval age_time; // This time is used to keep track of wifi hosts + time_t age_time; }; int host_nodes(struct ubus_context *ctx, @@ -105,7 +131,9 @@ void host_agent_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg); void host_set_interface_type(struct host_node *p); -int host_get_arping_status(char *ipaddr_str); void host_arp_table_refresh(struct uloop_timeout *t); +void host_wifi_table_refresh(struct uloop_timeout *t); void host_get_network_dump(struct topologyd_private *priv); +int topologyd_send_host_topology_query(struct topologyd_private *p); +int host_send_mid_topology_query(struct topologyd_private *p, uint8_t *dest_mac); #endif /* HOSTD_H */ diff --git a/src/host_config.c b/src/host_config.c index 255902351b71e0d644dbbec579742904d66ab93f..d87fcae506e8ebab04bbc19395a0e24a69fb1b62 100644 --- a/src/host_config.c +++ b/src/host_config.c @@ -246,13 +246,9 @@ bool config_init_host_data(char *package_name, char *section, struct topologyd_p } if (p) { if (p->intf_type == HOST_TYPE_WIFI) { - if (p->ipv4addr && host_get_arping_status(p->ipv4addr)) { - dbg("%s %d client %s DID NOT answer arping, set as inactive\n", __func__, __LINE__, p->ipv4addr); - host_change_active_state(priv, p, 0); - } else { - dbg("%s %d client %s DID answer arping, set as active\n", __func__, __LINE__, p->ipv4addr); - host_change_active_state(priv, p, 1); - } + // We are changing all to zero in init so that it can be correctly changed after the + // topology extended response message + host_change_active_state(priv, p, 0); } } } diff --git a/src/host_utils.c b/src/host_utils.c index 5ec21ef365bd71e620bc480dbd793ce7cfa87c04..d46b430cec973058ac3c6554471b32daf78e4223 100644 --- a/src/host_utils.c +++ b/src/host_utils.c @@ -264,6 +264,7 @@ int host_get_netlink_ip(uint8_t *mac_addr, char *ipv4_str, char *device) if (addr_s == NULL) { /* error */ err("nl_addr2str failed\n"); + nl_object_put((struct nl_object *) neigh); nl_cache_free(cache); nl_socket_free(sk); return -1; @@ -274,11 +275,13 @@ int host_get_netlink_ip(uint8_t *mac_addr, char *ipv4_str, char *device) strncpy(ipv4_str, addr_str, 24); ifname = if_indextoname(ifindex, device); if (ifname == NULL) { + nl_object_put((struct nl_object *) neigh); nl_cache_free(cache); nl_socket_free(sk); return -1; } dbg("intfname = [%s] ipv4addr= [%s] mac=["MACFMT"]\n", device, ipv4_str, MAC2STR(hwaddr)); + nl_object_put((struct nl_object *) neigh); break; } @@ -292,3 +295,86 @@ int host_get_netlink_ip(uint8_t *mac_addr, char *ipv4_str, char *device) return 0; } + +void _E1B(uint8_t **packet_ppointer, uint8_t *memory_pointer) +{ + *memory_pointer = **packet_ppointer; + (*packet_ppointer) += 1; +} + +// Extract/insert 2 bytes +void _E2B(uint8_t **packet_ppointer, uint16_t *memory_pointer) +{ + uint16_t mem = 0; + *(((uint8_t *) &mem) + 0) = **packet_ppointer; + (*packet_ppointer)++; + *(((uint8_t *) &mem) + 1) = **packet_ppointer; + (*packet_ppointer)++; + *memory_pointer = ntohs(mem); +} + +// Extract/insert N bytes (ignore endianess) +void _EnB(uint8_t **packet_ppointer, + void *memory_pointer, + uint32_t n) +{ + memcpy(memory_pointer, *packet_ppointer, n); + (*packet_ppointer) += n; +} + +// count includes end-of-message tlv +uint8_t count_tlv_present_instream_unsafe(uint8_t *tlv_stream) +{ + uint8_t *p = tlv_stream; + uint8_t tlv_type, count = 0; + uint16_t tlv_len = 0; + + if (tlv_stream == NULL) { + err("tlv Stream is empty\n"); + return 0; + } + + do { + _E1B(&p, &tlv_type); + _E2B(&p, &tlv_len); + + p = p + tlv_len; + count++; + } while (tlv_type != TLV_TYPE_END_OF_MESSAGE); + + return count; +} + +uint16_t get_tlv_packet_len(uint8_t *tlv_stream) +{ + uint8_t *p; + uint8_t type; + uint16_t len; + + if (tlv_stream == NULL) + return 0; + + p = tlv_stream; + _E1B(&p, &type); + _E2B(&p, &len); + + // tlv packet does not have length of tlv_type(1 Byte) and + // tlv_len(2 Bytes) included + return len + 3; +} + +uint8_t get_tlv_packet_type(uint8_t *tlv_stream) +{ + uint8_t *p; + uint8_t type; + uint16_t len; + + if (tlv_stream == NULL) + return 0; + + p = tlv_stream; + _E1B(&p, &type); + _E2B(&p, &len); + + return type; +} diff --git a/src/host_utils.h b/src/host_utils.h index 375f226932139e272b1e28f5f2a1655b54ad456d..b6741b7f11a55d27dafb665ebca56fd6ebb13a0e 100644 --- a/src/host_utils.h +++ b/src/host_utils.h @@ -22,9 +22,17 @@ #define NLMSG_NEIGH 28 #define IFLIST_REPLY_BUFFER 8192 +#define TLV_TYPE_END_OF_MESSAGE 0x00 bool host_send_arping(const char *targetIP, const char *device, int toms, int is_recv); int host_get_neigh(struct nlmsghdr *nlh, char *dev, char *dest_addr, uint8_t *mac_addr); int host_get_netlink_ip(uint8_t *mac_addr, char *ipv4_str, char *device); - +uint8_t count_tlv_present_instream_unsafe(uint8_t *tlv_stream); +uint16_t get_tlv_packet_len(uint8_t *tlv_stream); +uint8_t get_tlv_packet_type(uint8_t *tlv_stream); +void _E1B(uint8_t **packet_ppointer, uint8_t *memory_pointer); +void _E2B(uint8_t **packet_ppointer, uint16_t *memory_pointer); +void _EnB(uint8_t **packet_ppointer, + void *memory_pointer, + uint32_t n); #endif diff --git a/src/topologyd.c b/src/topologyd.c index bc0651747382b947ec73c0c507aacd80607d847a..26eda1477d39c42df77c582da071b83cf5e93663 100644 --- a/src/topologyd.c +++ b/src/topologyd.c @@ -1485,6 +1485,7 @@ int topologyd_start(void) /*Here we set the cb for the arp table read timer*/ priv->host_arp_timer.cb = host_arp_table_refresh; + priv->host_wifi_timer.cb = host_wifi_table_refresh; priv->refresh_timer.cb = topologyd_periodic_refresh; priv->heartbeat.cb = topologyd_start_heartbeat; diff --git a/src/topologyd.h b/src/topologyd.h index 8adbcf7c919bc299e689dd5cc75142c14b02f1ca..5082dc450bea9173fe274091ea7889d502af8d17 100644 --- a/src/topologyd.h +++ b/src/topologyd.h @@ -229,6 +229,7 @@ struct topologyd_private { struct host_ntwk host; struct uloop_timeout host_refresh_timer; struct uloop_timeout host_arp_timer; + struct uloop_timeout host_wifi_timer; void *avahi_serv; void *simple_poll; struct json_object *wifi_stations;