diff --git a/src/Makefile b/src/Makefile index 37fb88a72cc7dcaaef39228b197982ccce9e50e6..3112326ef1e47cc0c68a7d62decea6ec42fa69b3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,9 +4,10 @@ CFLAGS+=-I. -D_GNU_SOURCE CFLAGS+= -g3 -Wall -pthread OBJS = main.o debug.o config.o json_utils.o nodes.o topo_ieee1905.o topologyd.o mdns_avahi.o -OBJS+= host.o host_nodes.o host_config.o +OBJS+= host_nodes.o host_config.o host_utils.o host.o LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -pthread -leasy -lieee1905 -lavahi-core -lavahi-common +LIBS+= -I/usr/include/libnl3 -lnl-3 -lnl-route-3 .PHONY: all check clean FORCE diff --git a/src/host.c b/src/host.c index a3a2a6cec2de39fb707e6108eebeb6ab3adcbab8..6036f02b3a7438c9ffb586a8c511c2f1a3b87bbb 100644 --- a/src/host.c +++ b/src/host.c @@ -29,6 +29,7 @@ #include "debug.h" #include "config.h" #include "json_utils.h" +#include "host_utils.h" extern const char *ubus_socket; @@ -83,7 +84,7 @@ char *topology_stringify_types(enum host_types type) static void uobjx_lookup(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv) { const char *token = "wifi.ap"; - char *p, *mac; + char *p; struct u_list *str = (struct u_list *)priv; p = strstr(obj->path, token); @@ -91,8 +92,6 @@ static void uobjx_lookup(struct ubus_context *ctx, struct ubus_object_data *obj, strcpy(str->ifname[str->count], obj->path); str->count = str->count + 1; } -fail: - return; } static int host_get_wifi_nodes(struct ubus_context *ctx, struct u_list *c) @@ -181,7 +180,6 @@ void host_dump_node_nbr(struct topologyd_private *priv, struct blob_buf *b) if (hwaddr_is_zero(p->hwaddr) || memcmp(hwaddr, p->hwaddr, 6)) // TODO: unlikely.. continue; - printf("%s %d\n", __func__, __LINE__); table1 = blobmsg_open_table(b, NULL); hwaddr_ntoa(p->hwaddr, mac_str); @@ -230,64 +228,6 @@ void host_dump_node_nbr(struct topologyd_private *priv, struct blob_buf *b) uci_free_context(ctx); } -struct host_node *host_topo_node_init(struct topologyd_private *priv, uint8_t *mac_addr) -{ - struct host_node *p = NULL; - char mac_str[18] = { 0 }; - time_t tmp_t; - struct tm *info; - char str_tm[20]; - - dbg("Inside %s %d\n", __func__, __LINE__); - - if (!priv) - return -1; - - if (priv->host.num_nodes >= HOST_NODE_MAX) { - err("Number of host more than MAX limit!\n"); - return -1; - } - - if (mac_addr != NULL) { - int ret; - - p = host_node_lookup(priv->host.node_htable, mac_addr); - if (!p) { - p = host_node_add(priv->host.node_htable, mac_addr); - if (p == NULL) - return -1; - } - - /* Here we need to write this info in the config file - */ - hwaddr_ntoa(mac_addr, mac_str); - config_add_default_host_mac("hosts", "host", mac_str); - host_change_active_state(priv, p, 0); - - ret = host_get_wifi_data(priv, p); - //if (ret != 0) - // err("Unable to fetch interface type\n"); - if (p->intf_type == HOST_TYPE_WIFI) - config_set_host_option("hosts", "host", "macaddr", mac_str, "interface_type", "wifi"); - else/* if (p->intf_type == HOST_TYPE_ETHER) */{ - config_set_host_option("hosts", "host", "macaddr", mac_str, "interface_type", "eth"); - } - - ret = host_get_ipaddr_hostname(priv, mac_str, p); - if (ret != 0) { - printf("%s %d\n", __func__, __LINE__); - err("Unable to fetch ip adddress and host name\n"); - p->is_ipaddr = 0; - } else { - printf("%s %d\n", __func__, __LINE__); - p->is_ipaddr = 1; - } - - - } - return p; -} - struct host_node *host_topo_node_add(struct topologyd_private *priv, struct node *node, uint8_t *mac_addr, uint8_t is_wifi) { struct host_node *p = NULL; @@ -295,7 +235,7 @@ struct host_node *host_topo_node_add(struct topologyd_private *priv, struct node time_t tmp_t; struct tm *info; char str_tm[32] = {0}; - int ret = 0, i = 0; + int ret = 0; dbg("Inside %s %d\n", __func__, __LINE__); @@ -310,12 +250,8 @@ struct host_node *host_topo_node_add(struct topologyd_private *priv, struct node if (node != NULL) { bool send_ev = false; - if (!memcmp(node->hwaddr, priv->ieee1905_macaddr, 6)) { - p = &priv->selfnode; - //Here the node is the selfnode - //self node does not get added in the hosts - return 0; - } + if (!memcmp(node->hwaddr, priv->ieee1905_macaddr, 6)) + return NULL; /* Add node if not present in host. * @@ -344,39 +280,21 @@ struct host_node *host_topo_node_add(struct topologyd_private *priv, struct node info = localtime(&tmp_t); strftime(str_tm, sizeof(str_tm), "%Y-%m-%dT%H:%M:%SZ", info); config_set_host_option("hosts", "host", "macaddr", mac_str, "active_last_change", str_tm); - //TODO Here Adding the ipv4 address and hostname and ipv6 address - //As these params will come in the Higher layer response it needs to be - //populated from there - - /* This is a ieee1905 node so we get the interface type via the - * * topology response media type - * */ - //if (p->intf_type != HOST_TYPE_WIFI) host_get_wifi_data(priv, p); - //if (ret != 0) - // err("Unable to fetch interface type\n"); - // if (p->intf_type == HOST_TYPE_WIFI) - // config_set_host_option("hosts", "host", "macaddr", mac_str, "interface_type", "wifi"); - // else/* if (p->intf_type == HOST_TYPE_ETHER) */{ - // config_set_host_option("hosts", "host", "macaddr", mac_str, "interface_type", "eth"); - // } bool has_ip = p->is_ipaddr; ret = host_get_ipaddr_hostname(priv, mac_str, p); if (ret != 0) { - printf("%s %d\n", __func__, __LINE__); err("Unable to fetch ip adddress and host name\n"); p->is_ipaddr = 0; } else { - printf("%s %d\n", __func__, __LINE__); p->is_ipaddr = 1; if (!has_ip && p->intf_type == HOST_TYPE_WIFI && !p->is_in_assoclist) { if (!host_get_arping_status(p->ipv4addr)) { host_send_client_event(priv, p, 1); host_change_active_state(priv, p, 1); - } - else + } else host_change_active_state(priv, p, 0); } } @@ -435,18 +353,15 @@ struct host_node *host_topo_node_add(struct topologyd_private *priv, struct node ret = host_get_ipaddr_hostname(priv, mac_str, p); if (ret != 0) { - printf("%s %d\n", __func__, __LINE__); err("Unable to fetch ip adddress and host name\n"); p->is_ipaddr = 0; } else { - printf("%s %d\n", __func__, __LINE__); p->is_ipaddr = 1; if (!has_ip && p->intf_type == HOST_TYPE_WIFI && !p->is_in_assoclist) { if (!host_get_arping_status(p->ipv4addr)) { //host_send_client_event(priv, p, 1); host_change_active_state(priv, p, 1); - } - else + } else host_change_active_state(priv, p, 0); } } @@ -466,20 +381,15 @@ struct host_node *host_topo_node_del(struct topologyd_private *priv, struct node { struct host_node *p = NULL; char mac_str[18] = { 0 }; - time_t tmp_t; - struct tm *info; - char str_tm[20]; dbg("Inside %s %d\n", __func__, __LINE__); if (!priv) - return -1; + return NULL; if (node != NULL) { if (!memcmp(node->hwaddr, priv->ieee1905_macaddr, 6)) { - p = &priv->selfnode; - //Here the node is the selfnode - //self node does not get added in the hosts + //self node does not get deleted in the hosts return NULL; } @@ -635,12 +545,10 @@ out_str: void host_get_network(struct topologyd_private *priv, struct host_node *p) { struct json_object *interfaces; - char *json_str; int i = 0, len = 0; - int ret = 0; if (!priv || !p) - return ; + return; if (!json_object_is_type(priv->network_dump, json_type_object)) return; @@ -728,7 +636,7 @@ static void host_get_network_dump(struct topologyd_private *priv) status = ubus_lookup_id(priv->ctx, "network.interface", &id); if (status != UBUS_STATUS_OK) { err("object 'interfacedump' not present!\n"); - return OBJECT_INVALID; + return; } ret = ubus_invoke(priv->ctx, id, "dump", bb.head, @@ -736,7 +644,7 @@ static void host_get_network_dump(struct topologyd_private *priv) if (ret) { dbg("Failed to get network.interface dump (ret = %d)\n", ret); blob_buf_free(&bb); - return -1; + return; } blob_buf_free(&bb); @@ -767,50 +675,6 @@ static int active_connections(char *ipaddr) return connum; } -static void get_dhcp_options(struct host_node *host) -{ - FILE *opts; - char line[2048]; - char macaddr[24]; - char vcid[128]; - char clid[128]; - char ucid[128]; - - /* /var/dhcp.client.options format */ - /* <MACADDR> vcid=<VENDOR_CLASS_ID> clid=<CLIENT_ID> ucid=<USER_CLASS_ID> */ - /* vcid: Option 60, clid: Option 61, ucid: Option 77 */ - opts = fopen("/var/dhcp.client.options", "r"); - - if (opts != NULL) { - while (fgets(line, sizeof(line), opts) != NULL) { - uint8_t hwaddr[6] = {0}; - - remove_newline(line); - sscanf(line, "%24s vcid=%128s clid=%128s ucid=%128s", - macaddr, - vcid, - clid, - ucid); - - hwaddr_aton(macaddr, hwaddr); - - if (!memcmp(hwaddr, host->hwaddr, 6)) { - if (strcmp(vcid, "-") != 0) - strncpy(host->dhcpopts.vcid, vcid, 128); - - if (strcmp(clid, "-") != 0) - strncpy(host->dhcpopts.clid, clid, 128); - - if (strcmp(ucid, "-") != 0) - strncpy(host->dhcpopts.ucid, ucid, 128); - - break; - } - } - fclose(opts); - } -} - static unsigned long long get_netdev_stats(char *device, char *stat) { FILE *snfile; @@ -846,7 +710,6 @@ void get_bridge_info(struct host_node *host, char *device) host->port_no = 0; if (strstr(device, "br-")) { chrCmd(brinfo, 16, "brctl showmacs %s | grep %s | awk '{print$1\":\"$4}'", device, macstr); - printf("brinfo %s\n", brinfo); sscanf(brinfo, "%d:%d.%d", &host->port_no, &aging, &timer); } } @@ -861,7 +724,7 @@ static void get_ethernet_interface(struct host_node *host, char *bridge, int por char path_portno[512]; unsigned int pno = 0; - dbg("Inside %s %d \n", __func__, __LINE__); + dbg("Inside %s %d\n", __func__, __LINE__); if (portno == 0 || !host) return; @@ -879,7 +742,6 @@ static void get_ethernet_interface(struct host_node *host, char *bridge, int por pfile = fopen(path_portno, "r"); if (pfile != NULL) { - printf("%s %d\n", __func__, __LINE__); fscanf(pfile, "0x%x", &pno); fclose(pfile); } @@ -950,74 +812,48 @@ int get_ifmask(char *ifname, char *buf) int host_get_ipaddr_hostname(struct topologyd_private *priv, char *macaddr_str, struct host_node *p) { - FILE *arpt; - char line[256]; - int clidx = 0; - int hw, flag; - char mask[256]; - int i, j; int ret = -1; - char macaddr[18] = { 0 }; - char ip_addr[24] = { 0 }; char device[16] = { 0 }; - - dbg("Inside %s %d mac=[%s]\n", __func__, __LINE__, macaddr_str); + char ipv4_address[24] = { 0 }; if (!macaddr_str || !p) return ret; - // Walk through ARP table to get the ip address - arpt = fopen("/proc/net/arp", "r"); - if (arpt != NULL) { - while (fgets(line, sizeof(line), arpt) != NULL) { - remove_newline(line); - if (sscanf(line, "%24s 0x%d 0x%d %24s %256s %32s", - ip_addr, &hw, &flag, macaddr, mask, device)) { - dbg("macaddr_str %s macaddr %s, ip %s\n", macaddr_str, macaddr, ip_addr); - // Search the MAC address entry in the arp table - if (strncmp(macaddr_str, macaddr, 18) == 0) { - char mask[24] = {0}, addr[24] = {0}; - - // Append DHCPv4 information: Hostname, IPv4 Address and Lease Time - ret = host_append_dhcpv4_info(macaddr, p); - if (ret != 0) { - strncpy(p->ipv4addr, ip_addr, 24); - strncpy(p->ipv4addr_list[0], ip_addr, 24); - p->leasetmrmn = 0; - p->addrsrc = HOST_ADDR_STATIC; - p->ipv4addr_count = 1; - } else { - p->addrsrc = HOST_ADDR_DHCP; - //get_dhcp_options(p); - } - dbg("device %s\n", device); - host_get_network(priv, p); - get_bridge_info(p, device); - - if (p->intf_type == HOST_TYPE_ETHER || !strlen(p->device)) { - strncpy(p->device, device, 16); - get_ethernet_interface(p, device, p->port_no); - //if (!strncmp(p->device, "wds", 3)) - // p->intf_type = HOST_TYPE_WIFI; - p->stats.tx_bytes = get_netdev_stats(p->device, "rx_bytes"); - p->stats.rx_bytes = get_netdev_stats(p->device, "tx_bytes"); - p->stats.tx_packets = get_netdev_stats(p->device, "rx_packets"); - p->stats.rx_packets = get_netdev_stats(p->device, "tx_packets"); - } - p->active_connections = active_connections(p->ipv4addr); - - dbg("%s %d ipv4addr = [%s]\n", __func__, __LINE__, p->ipv4addr); - // Append DHCPv6 information: IPv6 Address, DUID, Lease Time - if (strlen(p->hostname) > 1) - host_append_dhcpv6_info(p); - ret = 0; - break; - } - } - } - fclose(arpt); + ret = host_get_netlink_ip(p->hwaddr, ipv4_address, device); + + if (ret != 0) + return ret; + + strncpy(p->ipv4addr, ipv4_address, 24); + dbg("The IPv4 address is %s mac is %s device is %s\n", p->ipv4addr, macaddr_str, device); + ret = host_append_dhcpv4_info(macaddr_str, p); + if (ret != 0) { + strncpy(p->ipv4addr_list[0], p->ipv4addr, 24); + p->leasetmrmn = 0; + p->addrsrc = HOST_ADDR_STATIC; + p->ipv4addr_count = 1; + } else { + p->addrsrc = HOST_ADDR_DHCP; } + host_get_network(priv, p); + get_bridge_info(p, device); + + if (p->intf_type == HOST_TYPE_ETHER || !strlen(p->device)) { + strncpy(p->device, device, 16); + get_ethernet_interface(p, device, p->port_no); + p->stats.tx_bytes = get_netdev_stats(p->device, "rx_bytes"); + p->stats.rx_bytes = get_netdev_stats(p->device, "tx_bytes"); + p->stats.tx_packets = get_netdev_stats(p->device, "rx_packets"); + p->stats.rx_packets = get_netdev_stats(p->device, "tx_packets"); + } + p->active_connections = active_connections(p->ipv4addr); + dbg("%s %d ipv4addr = [%s]\n", __func__, __LINE__, p->ipv4addr); + // Append DHCPv6 information: IPv6 Address, DUID, Lease Time + if (strlen(p->hostname) > 1) + host_append_dhcpv6_info(p); + ret = 0; + dbg("Inside %s %d mac=[%s] macinterface =[%d]\n", __func__, __LINE__, macaddr_str, p->intf_type); return ret; } @@ -1135,9 +971,7 @@ void host_gather_stations(struct ubus_request *req, int type, struct blob_attr * struct json_object *sta_array; struct json_object *priv_stations; char *json_str; - const char *macstr; int i = 0, len = 0, priv_len = 0; - int ret = 0; json_object_object_get_ex(p->wifi_stations, "stations", &priv_stations); if (!priv_stations) @@ -1160,8 +994,7 @@ void host_gather_stations(struct ubus_request *req, int type, struct blob_attr * len = json_object_array_length(sta_array); for (i = 0; i < len; i++) { - struct json_object *sta_obj, *sta_obj_macaddr, *jobj_ptr, *stat_obj; - unsigned char macaddr[6] = {0}; + struct json_object *sta_obj; sta_obj = json_object_array_get_idx(sta_array, i); json_object_array_put_idx(priv_stations, priv_len++, json_object_get(sta_obj)); @@ -1211,13 +1044,6 @@ void host_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg) { - int ret = 0; - struct cmdu_cstruct *cstruct = NULL; - uint16_t msg_type = 0; - uint16_t msg_mid = 0; - uint8_t *tlv = NULL; - uint32_t len = 0; - char itfr_name[256] = {0}; char *str; struct topologyd_private *priv = @@ -1266,9 +1092,9 @@ void host_wifi_sta_event_handler(void *c, struct blob_attr *msg) static const struct blobmsg_policy data_attr[1] = { [0] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, }; - char mac_str[18] = {0}, bssid_str[18] = {0}; - uint8_t mac[6] = {0}, bssid[6] = {0}; + char mac_str[18] = {0}; + uint8_t mac[6] = {0}; blobmsg_parse(data_attr, 1, data, blobmsg_data(tb[2]), blobmsg_data_len(tb[2])); @@ -1281,11 +1107,8 @@ void host_wifi_sta_event_handler(void *c, struct blob_attr *msg) if (!hwaddr_aton(mac_str, mac)) return; - if (add) { - struct host_node *n; - - n = host_topo_node_add(p, NULL, mac, 1); - } + if (add) + host_topo_node_add(p, NULL, mac, 1); else if (del) host_topo_node_del(p, NULL, mac, 1); @@ -1298,10 +1121,6 @@ int host_get_interface_type(struct topologyd_private *priv) struct u_list c; int i = 0; int ret = 0; - char mac_str[18] = { 0 }; - time_t tmp_t; - struct tm *info; - char str_tm[20]; if (priv->wifi_stations) { json_object_put(priv->wifi_stations); @@ -1349,40 +1168,49 @@ void host_periodic_refresh(struct uloop_timeout *t) uloop_timeout_set(&priv->host_refresh_timer, HOST_REFRESH_TIMER * 1000); } +void host_arp_table_refresh(struct uloop_timeout *t) +{ + struct topologyd_private *priv = + container_of(t, struct topologyd_private, host_arp_timer); + + dbg("Inside %s %d\n", __func__, __LINE__); + + host_get_table_cb(priv); +} + int host_get_arping_status(char *ipaddr_str) { - char cmd[256] = {0}; - FILE *fp = NULL; - char *line = NULL; - size_t len = 0; - int found = 0; int ret = -1; dbg("Inside %s %d\n", __func__, __LINE__); if (ipaddr_str == NULL) return -1; + ret = host_send_arping(ipaddr_str, "br-lan", 1000, 1); - snprintf(cmd, 256, ARPING_CMD, ipaddr_str); + if (ret != 0) + ret = 0; + else + ret = -1; - fp = popen(cmd, "r"); - if (fp == NULL) { - err("unable to execute command"); + return ret; +} + +int host_send_arp_req(char *ipaddr_str) +{ + int ret = -1; + + dbg("Inside %s %d\n", __func__, __LINE__); + + if (ipaddr_str == NULL) return -1; - } - dbg("Inside %s %d command is %s\n", __func__, __LINE__, cmd); - while (getline(&line, &len, fp) != -1) { - if (len < 2) { - free(line); - len = 0; - continue; - } - ret = strncmp(line, "1", 1); - break; - } - free(line); - pclose(fp); + ret = host_send_arping(ipaddr_str, "br-lan", 1000, 0); + if (ret != 0) + ret = 0; + else + ret = -1; + return ret; } @@ -1429,44 +1257,6 @@ int host_get_neigh_status(uint8_t *mac_addr) return 0; } -int host_check_ip_addr(struct host_node *p) -{ - - char mac_str[18] = { 0 }; - int ret = -1, i = 0; - - dbg("Inside %s %d\n", __func__, __LINE__); - - if (p == NULL) - return -1; - - hwaddr_ntoa(p->hwaddr, mac_str); - for (i = 0; i < p->ipv4addr_count; i++) - config_del_host_list("hosts", "host", "macaddr", mac_str, - "ipv4address", p->ipv4addr_list[i]); - for (i = 0; i < p->ipv6addr_count; i++) - config_del_host_list("hosts", "host", "macaddr", mac_str, - "ipv6address", p->ipv6addr[i]); - //ret = host_get_ipaddr_hostname(priv, mac_str, p); - if (ret != 0) - err("Unable to fetch ip adddress and host name\n"); - else { - p->is_ipaddr = 1; - config_set_host_option("hosts", "host", "macaddr", mac_str, - "ipaddress", p->ipv4addr); - config_set_host_option("hosts", "host", "macaddr", mac_str, - "hostname", p->hostname); - - for (i = 0; i < p->ipv4addr_count; i++) - config_set_host_list("hosts", "host", "macaddr", mac_str, - "ipv4address", p->ipv4addr_list[i]); - for (i = 0; i < p->ipv6addr_count; i++) - config_set_host_list("hosts", "host", "macaddr", - mac_str, "ipv6address", p->ipv6addr[i]); - } - return ret; -} - /* { "topology.host": {"action":"connect","macaddr":"fe:ce:90:d7:5e:64","ipaddr":"192.168.1.157","network":"lan"} } { "topology.host": {"action":"disconnect","macaddr":"fe:ce:90:d7:5e:64","ipaddr":"192.168.1.157","network":"lan"} } @@ -1474,7 +1264,7 @@ int host_check_ip_addr(struct host_node *p) void host_send_client_event(struct topologyd_private *priv, struct host_node *p, uint8_t state) { - char mac[18] = {0}, src_mac[18] = {0}; + char mac[18] = {0}; struct blob_buf bb = {0}; if (!p || !priv) @@ -1509,9 +1299,9 @@ void host_change_active_state(struct topologyd_private *priv, struct host_node * config_add_default_host_mac("hosts", "host", mac_str); if (state == 0x0) config_set_host_option("hosts", "host", "macaddr", mac_str, "active", "0"); - else { + else config_set_host_option("hosts", "host", "macaddr", mac_str, "active", "1"); - } + tmp_t = p->active_last_change; info = localtime(&tmp_t); strftime(str_tm, sizeof(str_tm), "%Y-%m-%dT%H:%M:%SZ", info); @@ -1528,9 +1318,6 @@ void host_run_status_check(struct topologyd_private *priv) struct host_node *p; int i = 0, ret = -1; char mac_str[18] = { 0 }; - time_t tmp_t; - struct tm *info; - char str_tm[20]; dbg("Inside %s %d\n", __func__, __LINE__); if (!priv) @@ -1552,20 +1339,7 @@ void host_run_status_check(struct topologyd_private *priv) continue; hwaddr_ntoa(p->hwaddr, mac_str); - /*Here we check if the node has received the - * ip adddress - */ - //if (p->is_ipaddr == 0) { - // dbg("node %s does not have an ip address!\n", mac_str); - // ret = host_get_ipaddr_hostname(priv, mac_str, p); - // if (ret != 0) - // err("Unable to fetch ip adddress and host name\n"); - // else - // p->is_ipaddr = true; - //} - /*Here we check the status of the eth node in - * the ip neigh - */ + if (p->intf_type != HOST_TYPE_ETHER && !p->is_ieee1905_node) { memset(p->device, 0, 16); host_get_wifi_data(priv, p); @@ -1584,8 +1358,7 @@ void host_run_status_check(struct topologyd_private *priv) if (!host_get_arping_status(p->ipv4addr)) { host_send_client_event(priv, p, 1); host_change_active_state(priv, p, 1); - } - else { + } else { //host_send_client_event(priv, p, 0); host_change_active_state(priv, p, 0); } @@ -1603,6 +1376,53 @@ void host_run_status_check(struct topologyd_private *priv) else p->is_ipaddr = 1; + char ipv4addr[24] = { 0 }; + + if (strncmp(p->ipv4addr, ipv4addr, 24)) { + ret = host_send_arp_req(p->ipv4addr); + } else { + dbg("ETH node is unreachable " MACFMT "\n", MAC2STR(p->hwaddr)); + if (p->active != 0) { + host_send_client_event(priv, p, 0); + host_change_active_state(priv, p, 0); + } + } + } + } + /* Here we set the timer to check the arp request + */ + uloop_timeout_set(&priv->host_arp_timer, HOST_ARP_TIMER * 1000); + +} + +void host_get_table_cb(struct topologyd_private *priv) +{ + struct host_node *p; + int i = 0, ret = -1; + 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); + + if (p->intf_type != HOST_TYPE_ETHER && !p->is_ieee1905_node) + continue; + ret = host_get_neigh_status(p->hwaddr); if (ret == 0 && has_ip) { /*Here the node is rechable so @@ -1617,34 +1437,11 @@ void host_run_status_check(struct topologyd_private *priv) } } else { /*Here as the status is not reachable - * we need to do arping to the node - * to get the status and turn unreachable accordingly */ - char ipv4addr[24] = { 0 }; - - if (strncmp(p->ipv4addr, ipv4addr, 24)) { - ret = host_get_arping_status(p->ipv4addr); - if (ret != 0) { - dbg("ETH node is unreachable " MACFMT "\n", MAC2STR(p->hwaddr)); - if (p->active != 0) { - host_send_client_event(priv, p, 0); - host_change_active_state(priv, p, 0); - } - } else { - if (p->active != 1) { - dbg("ETH node is reachable " MACFMT "\n", MAC2STR(p->hwaddr)); - host_send_client_event(priv, p, 1); - host_change_active_state(priv, p, 1); - } else if (!has_ip) - host_send_client_event(priv, p, 1); - - } - } else { - dbg("ETH node is unreachable " MACFMT "\n", MAC2STR(p->hwaddr)); - if (p->active != 0) { - host_send_client_event(priv, p, 0); - host_change_active_state(priv, p, 0); - } + dbg("ETH node is unreachable " MACFMT "\n", MAC2STR(p->hwaddr)); + if (p->active != 0) { + host_send_client_event(priv, p, 0); + host_change_active_state(priv, p, 0); } } } @@ -1653,11 +1450,6 @@ void host_run_status_check(struct topologyd_private *priv) void host_process_topo_notification(uint8_t *tlv, struct topologyd_private *priv) { - int i = 0, j = 0; - uint8_t *ptr; - uint8_t *p, *ret; - uint8_t temp = 0; - uint16_t tlv_length = 0; if (tlv == NULL || priv == NULL) return; @@ -1689,7 +1481,6 @@ void host_process_topo_notification(uint8_t *tlv, struct topologyd_private *priv dbg(" received a default tlv\n"); break; } - i++; } void host_agent_event_handler(struct ubus_context *ctx, diff --git a/src/host.h b/src/host.h index 8b4cbf779350cf74de345c65c3c23257e6ea8671..aa04d24b39fa4d9a853161af158f860034de003c 100644 --- a/src/host.h +++ b/src/host.h @@ -21,6 +21,7 @@ #define HOST_REFRESH_TIMER 15 #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 enum host_types { @@ -81,8 +82,6 @@ struct host_node { struct host_node *al_node; }; -struct host_node *host_topo_node_init(struct topologyd_private *priv, - uint8_t *mac_addr); int host_nodes(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, @@ -111,4 +110,5 @@ void host_agent_event_handler(struct ubus_context *ctx, 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); #endif /* HOSTD_H */ diff --git a/src/host_config.c b/src/host_config.c index bc76e0d4c175d476cae36c01523860af180e275c..255902351b71e0d644dbbec579742904d66ab93f 100644 --- a/src/host_config.c +++ b/src/host_config.c @@ -62,7 +62,7 @@ struct uci_section *config_add_section(struct uci_context *ctx, { struct uci_section *section = NULL; struct uci_ptr ptr = {0}; - int rv = -1, ret = 0; + int rv = -1; char name_section[50] = { 0 }; dbg("Inside %s %d\n", __func__, __LINE__); @@ -90,8 +90,7 @@ struct uci_section *config_add_section(struct uci_context *ctx, ptr.p = pkg; ptr.s = section; ptr.value = name_section; - ret = uci_rename(ctx, &ptr); - + uci_rename(ctx, &ptr); rv = uci_save(ctx, pkg); if (rv) goto out_pkg; @@ -118,7 +117,6 @@ int config_add_default_host_mac(const char *config, const char *type, struct uci_context *ctx; struct uci_package *pkg; struct uci_section *section; - int rv = -1; dbg("Inside %s %d\n", __func__, __LINE__); @@ -136,7 +134,6 @@ int config_add_default_host_mac(const char *config, const char *type, return -1; uci_commit(ctx, &pkg, false); -out_pkg: uci_unload(ctx, pkg); out_uci: uci_free_context(ctx); @@ -198,109 +195,6 @@ bool config_set_host_option(char *package_name, return false; } -bool config_del_host_list(char *package_name, - char *section_type, char *search_key, char *search_val, - char *option, char *value) -{ - struct uci_context *ctx; - struct uci_package *pkg; - struct uci_element *e, *x; - - dbg("Inside %s %d\n", __func__, __LINE__); - - if (!package_name || !search_val || !option || !value) - return false; - - ctx = uci_alloc_context(); - if (!ctx) - return false; - - if (uci_load(ctx, package_name, &pkg)) { - uci_free_context(ctx); - return false; - } - - uci_foreach_element(&pkg->sections, e) { - struct uci_section *s = uci_to_section(e); - - if (!strcmp(s->type, section_type)) { - struct uci_option *opt = uci_lookup_option(ctx, s, - search_key); - if (!opt || opt->type != UCI_TYPE_STRING) - continue; - if (strcmp(opt->v.string, search_val) == 0) { - struct uci_ptr ptr = {0}; - - ptr.value = value; - ptr.package = package_name; - ptr.section = s->e.name; - ptr.option = option; - ptr.target = UCI_TYPE_OPTION; - if (uci_del_list(ctx, &ptr) == UCI_OK) - uci_save(ctx, ptr.p); - break; - } - } - } - uci_commit(ctx, &pkg, false); - uci_unload(ctx, pkg); - uci_free_context(ctx); - return false; -} - -bool config_set_host_list(char *package_name, - char *section_type, char *search_key, char *search_val, - char *option, char *value) -{ - struct uci_context *ctx; - struct uci_package *pkg; - struct uci_element *e; - - dbg("Inside %s %d\n", __func__, __LINE__); - - if (!package_name || !search_val || !option || !value) - return false; - - config_del_host_list(package_name, section_type, search_key, - search_val, option, value); - - ctx = uci_alloc_context(); - if (!ctx) - return false; - - if (uci_load(ctx, package_name, &pkg)) { - uci_free_context(ctx); - return false; - } - - uci_foreach_element(&pkg->sections, e) { - struct uci_section *s = uci_to_section(e); - - if (!strcmp(s->type, section_type)) { - struct uci_option *opt = uci_lookup_option(ctx, s, - search_key); - if (!opt || opt->type != UCI_TYPE_STRING) - continue; - if (strcmp(opt->v.string, search_val) == 0) { - struct uci_ptr ptr = {0}; - - ptr.value = value; - ptr.package = package_name; - ptr.section = s->e.name; - ptr.option = option; - ptr.target = UCI_TYPE_OPTION; - if (uci_add_list(ctx, &ptr) == UCI_OK) - uci_save(ctx, ptr.p); - break; - } - } - } - uci_commit(ctx, &pkg, false); - uci_unload(ctx, pkg); - uci_free_context(ctx); - return false; -} - bool config_init_host_data(char *package_name, char *section, struct topologyd_private *priv) { diff --git a/src/host_config.h b/src/host_config.h index fdec2c7938a9f9d94cbc7294826ad8d4a037d552..503f072f65f0a714c2cd7e805654a25eb60aae5a 100644 --- a/src/host_config.h +++ b/src/host_config.h @@ -21,10 +21,4 @@ int config_add_default_host_mac(const char *config, const char *type, bool config_set_host_option(char *package_name, char *section_type, char *search_key, char *search_val, char *option, char *value); -bool config_set_host_list(char *package_name, - char *section_type, char *search_key, char *search_val, - char *option, char *value); -bool config_del_host_list(char *package_name, - char *section_type, char *search_key, char *search_val, - char *option, char *value); #endif /* HOSTD_CONFIG_H */ diff --git a/src/host_utils.c b/src/host_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..87c9fab82d7f1e3cdfa72f7adcfb60fa7ded9e6a --- /dev/null +++ b/src/host_utils.c @@ -0,0 +1,281 @@ +/* + * host_utils.c -- utils for host + * + * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> + * Author: Sukru Senli sukru.senli@inteno.se + * Author: Nevadita Chatterjee nevadita.chatterjee@iopsys.eu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#define _GNU_SOURCE +#include "host_utils.h" + +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + + +struct in_addr src; +struct in_addr dst; +struct sockaddr_ll me; +struct sockaddr_ll he; +int sock_fd; + +typedef struct nl_req_s nl_req_t; + +struct nl_req_s { + struct nlmsghdr hdr; + struct rtgenmsg gen; +}; + +static int +send_pack(struct in_addr *src_addr, struct in_addr *dst_addr, struct sockaddr_ll *ME, struct sockaddr_ll *HE) +{ + int err; + unsigned char buf[256]; + struct arphdr *ah = (struct arphdr *) buf; + unsigned char *p = (unsigned char *) (ah + 1); + + ah->ar_hrd = htons(ARPHRD_ETHER); + ah->ar_pro = htons(ETH_P_IP); + ah->ar_hln = ME->sll_halen; + ah->ar_pln = 4; + ah->ar_op = htons(ARPOP_REQUEST); + + p = (unsigned char *)mempcpy((void *)p, (const void *)ME->sll_addr, (size_t)ah->ar_hln); + p = (unsigned char *)mempcpy((void *)p, (const void *)src_addr, 4); + + p = (unsigned char *)mempcpy((void *)p, (const void *)HE->sll_addr, (size_t)ah->ar_hln); + p = (unsigned char *)mempcpy((void *)p, (const void *)dst_addr, 4); + + err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); + return err; +} + +static bool +recv_pack(char *buf, int len, struct sockaddr_ll *FROM) +{ + struct arphdr *ah = (struct arphdr *) buf; + unsigned char *p = (unsigned char *) (ah + 1); + struct in_addr src_ip, dst_ip; + + /* Filter out wild packets */ + if (FROM->sll_pkttype != PACKET_HOST + && FROM->sll_pkttype != PACKET_BROADCAST + && FROM->sll_pkttype != PACKET_MULTICAST) + return false; + + /* Only these types are recognized */ + if (ah->ar_op != htons(ARPOP_REPLY)) + return false; + + /* ARPHRD check and this darned FDDI hack here :-( */ + if (ah->ar_hrd != htons(FROM->sll_hatype) + && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) + return false; + + /* Protocol must be IP. */ + if (ah->ar_pro != htons(ETH_P_IP) + || (ah->ar_pln != 4) + || (ah->ar_hln != me.sll_halen) + || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) + return false; + + (src_ip.s_addr) = *(uint32_t *)(p + ah->ar_hln); + (dst_ip.s_addr) = *(uint32_t *)(p + ah->ar_hln + 4 + ah->ar_hln); + + if (dst.s_addr != src_ip.s_addr) + return false; + + if ((src.s_addr != dst_ip.s_addr) || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln))) + return false; + + return true; +} + + +bool +host_send_arping(const char *targetIP, const char *device, int toms, int is_recv) +{ + struct sockaddr_in saddr; + struct ifreq ifr; + int probe_fd; + char packet[64]; + struct sockaddr_ll from; + struct timeval timeout; + + dbg("Inside %s %d\n", __func__, __LINE__); + + sock_fd = socket(AF_PACKET, SOCK_DGRAM, 0); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, device, IF_NAMESIZE); + + if (ioctl(sock_fd, SIOCGIFINDEX, &ifr, sizeof(ifr)) < 0) { + close(sock_fd); + return false; + } + + me.sll_family = AF_PACKET; + me.sll_ifindex = ifr.ifr_ifindex; + me.sll_protocol = htons(ETH_P_ARP); + bind(sock_fd, (struct sockaddr *) &me, sizeof(me)); + + socklen_t mlen = sizeof(me); + + getsockname(sock_fd, (struct sockaddr *) &me, &mlen); + + he = me; + memset(he.sll_addr, -1, he.sll_halen); + + inet_pton(AF_INET, targetIP, &(dst.s_addr)); + + /* Get the sender IP address */ + probe_fd = socket(AF_INET, SOCK_DGRAM, 0); + setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + socklen_t slen = sizeof(saddr); + + saddr.sin_port = htons(1025); + saddr.sin_addr = dst; + connect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); + getsockname(probe_fd, (struct sockaddr *) &saddr, &slen); + src = saddr.sin_addr; + close(probe_fd); + + send_pack(&src, &dst, &me, &he); + + /*Here we are just sending the arp packet and returning*/ + if (is_recv != 1) + return 1; + + socklen_t alen = sizeof(from); + bool connected = false; + int cc = -1; + + fd_set read_fds, write_fds, except_fds; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); + FD_SET(sock_fd, &read_fds); + + + timeout.tv_sec = 0; + timeout.tv_usec = toms * 1000; + + if (select(sock_fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1) + cc = recvfrom(sock_fd, packet, sizeof(packet), 0, (struct sockaddr *) &from, &alen); + + if (cc >= 0) + connected = recv_pack(packet, cc, &from); + + close(sock_fd); + dbg("Inside %s %d connected %d\n", __func__, __LINE__, connected); + return connected; +} + +int host_get_netlink_ip(uint8_t *mac_addr, char *ipv4_str, char *device) +{ + struct rtnl_neigh *neigh; + struct nl_object *nobj; + struct nl_cache *cache; + uint32_t ifindex = 0; + struct nl_sock *sk; + int i, num; + int ret; + char *ifname = NULL; + + dbg("Inside %s %d\n", __func__, __LINE__); + sk = nl_socket_alloc(); + if (!sk) { + err("Unable to open nl event socket\n"); + return -1; + } + + if (nl_connect(sk, NETLINK_ROUTE) < 0) { + nl_socket_free(sk); + return -1; + } + + ret = rtnl_neigh_alloc_cache(sk, &cache); + if (ret) { + nl_socket_free(sk); + return -1; + } + + + num = nl_cache_nitems(cache); + nobj = nl_cache_get_first(cache); + neigh = (struct rtnl_neigh *)nobj; + + for (i = 0; i < num; i++) { + struct nl_addr *lladdr; + struct nl_addr *ipaddr; + struct ip_address ip = {0}; + uint8_t hwaddr[6] = {0}; + char addr_str[24]; + + nl_object_get((struct nl_object *) neigh); + + ifindex = rtnl_neigh_get_ifindex(neigh); + lladdr = rtnl_neigh_get_lladdr(neigh); + if (lladdr) + memcpy(hwaddr, nl_addr_get_binary_addr(lladdr), + nl_addr_get_len(lladdr)); + + if (hwaddr_is_zero(hwaddr)) { + nl_object_put((struct nl_object *) neigh); + nobj = nl_cache_get_next(nobj); + neigh = (struct rtnl_neigh *)nobj; + continue; + } + + ipaddr = rtnl_neigh_get_dst(neigh); + if (ipaddr) { + ip.family = nl_addr_get_family(ipaddr); + if (ip.family == AF_INET6 || ip.family == AF_INET) { + memcpy(&ip.addr, nl_addr_get_binary_addr(ipaddr), + nl_addr_get_len(ipaddr)); + } + } + + char *addr_s = nl_addr2str(ipaddr, addr_str, sizeof(addr_str)); + + if (addr_s == NULL) { + /* error */ + err("nl_addr2str failed\n"); + return -1; + } + + ret = memcmp(hwaddr, mac_addr, 6); + if (ret == 0) { + strncpy(ipv4_str, addr_str, 24); + ifname = if_indextoname(ifindex, device); + if (ifname == NULL) + return -1; + dbg("intfname = [%s] ipv4addr= [%s] mac=["MACFMT"]\n", device, ipv4_str, MAC2STR(hwaddr)); + break; + } + + nl_object_put((struct nl_object *) neigh); + nobj = nl_cache_get_next(nobj); + neigh = (struct rtnl_neigh *)nobj; + } + + nl_cache_free(cache); + nl_socket_free(sk); + + return 0; +} diff --git a/src/host_utils.h b/src/host_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..375f226932139e272b1e28f5f2a1655b54ad456d --- /dev/null +++ b/src/host_utils.h @@ -0,0 +1,30 @@ +#ifndef HOST_UTILS_H +#define HOST_UTILS_H + +#include <sys/socket.h> +#include <sys/types.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <netpacket/packet.h> +#include <net/ethernet.h> +#include <net/if_arp.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <stdbool.h> +#include <unistd.h> +#include "debug.h" +#include <fcntl.h> +#include <libubus.h> +#include <easy/easy.h> +#include <linux/rtnetlink.h> + +#define NLMSG_NEIGH 28 +#define IFLIST_REPLY_BUFFER 8192 + +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); + +#endif diff --git a/src/topologyd.c b/src/topologyd.c index 840cacc3548ef47e828add0af2fe6297579f102d..df0d359777acbad635e159143ea8b7ee970a77e3 100644 --- a/src/topologyd.c +++ b/src/topologyd.c @@ -304,11 +304,13 @@ void topologyd_process_topology_response(struct cmdu_cstruct *cstruct, struct to iface_node = host_node_lookup(priv->host.node_htable, tlv->local_interfaces[j].mac_address); if (iface_node) { struct host_node *node; + int rv = -1; dbg("%s %d we found a node\n", __func__, __LINE__); node = host_node_lookup(priv->host.node_htable, n.hwaddr); - if (node) { + rv = memcmp(node->hwaddr, iface_node->hwaddr, 6); + if (node && rv) { iface_node->ignore = true; iface_node->al_node = node; if (tlv->local_interfaces[j].media_type == @@ -1478,6 +1480,9 @@ int topologyd_start(void) //Here start the host refresh timer priv->host_refresh_timer.cb = host_periodic_refresh; + /*Here we set the cb for the arp table read timer*/ + priv->host_arp_timer.cb = host_arp_table_refresh; + priv->refresh_timer.cb = topologyd_periodic_refresh; priv->heartbeat.cb = topologyd_start_heartbeat; priv->topo.changelog = (struct topology_changelog *) calloc diff --git a/src/topologyd.h b/src/topologyd.h index b0e903d9df983ed7106c03421d95e69fa3cf8073..9f996e6ab9477411a212a8e78900fd0fd308aafc 100644 --- a/src/topologyd.h +++ b/src/topologyd.h @@ -229,6 +229,7 @@ struct topologyd_private { struct topology topo; struct host_ntwk host; struct uloop_timeout host_refresh_timer; + struct uloop_timeout host_arp_timer; void *avahi_serv; void *simple_poll; struct json_object *wifi_stations;