mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-30 01:52:51 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			236 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "udevmand.h"
 | |
| 
 | |
| struct avl_tree iface_tree = AVL_TREE_INIT(iface_tree, avl_strcmp, false, NULL);
 | |
| 
 | |
| struct iface_ip {
 | |
| 	struct list_head list;
 | |
| 	char ip[];
 | |
| };
 | |
| 
 | |
| struct iface {
 | |
| 	struct avl_node avl;
 | |
| 	int alive;
 | |
| 	char name[IF_NAMESIZE];
 | |
| 	struct rtnl_link_stats stats;
 | |
| 	struct rtnl_link_stats stats_old;
 | |
| 	struct list_head ipv6, ipv4;
 | |
| 	uint8_t addr[ETH_ALEN];
 | |
| };
 | |
| 
 | |
| static struct iface*
 | |
| iface_find(char *name)
 | |
| {
 | |
| 	struct iface *iface = avl_find_element(&iface_tree, name, iface, avl);
 | |
| 
 | |
| 	if (iface) {
 | |
| 		iface->alive = 1;
 | |
| 		return iface;
 | |
| 	}
 | |
| 	iface = malloc(sizeof(*iface));
 | |
| 	if (!iface)
 | |
| 		return NULL;
 | |
| 	memset(iface, 0, sizeof(*iface));
 | |
| 	iface->alive = 1;
 | |
| 	iface->avl.key = strcpy(iface->name, name);
 | |
| 	INIT_LIST_HEAD(&iface->ipv4);
 | |
| 	INIT_LIST_HEAD(&iface->ipv6);
 | |
| 	avl_insert(&iface_tree, &iface->avl);
 | |
| 	return iface;
 | |
| }
 | |
| 
 | |
| void
 | |
| iface_done(void)
 | |
| {
 | |
| 	struct iface *i, *t;
 | |
| 
 | |
| 	avl_for_each_element_safe(&iface_tree, i, avl, t) {
 | |
| 		avl_delete(&iface_tree, &i->avl);
 | |
| 		free(i);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| iface_get(void)
 | |
| {
 | |
| 	int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
 | |
| 	struct ifaddrs *ifaddr, *ifa;
 | |
| 	int n;
 | |
| 
 | |
| 	if (getifaddrs(&ifaddr) == -1) {
 | |
| 		ULOG_ERR("failed to getifaddrs\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
 | |
| 		char host[NI_MAXHOST];
 | |
| 		struct iface *iface;
 | |
| 		int family, s;
 | |
| 
 | |
| 		if (ifa->ifa_addr == NULL)
 | |
| 			continue;
 | |
| 
 | |
| 		if ((ifa->ifa_flags & IFF_UP) == 0)
 | |
| 			continue;
 | |
| 
 | |
| 		if (ifa->ifa_flags & IFF_LOOPBACK)
 | |
| 			continue;
 | |
| 
 | |
| 		family = ifa->ifa_addr->sa_family;
 | |
| 
 | |
| 		iface = iface_find(ifa->ifa_name);
 | |
| 		if (!iface)
 | |
| 			continue;
 | |
| 
 | |
| 		if (family == AF_INET || family == AF_INET6) {
 | |
| 			struct iface_ip *ip;
 | |
| 
 | |
| 			s = getnameinfo(ifa->ifa_addr,
 | |
| 					(family == AF_INET) ? sizeof(struct sockaddr_in) :
 | |
| 					sizeof(struct sockaddr_in6),
 | |
| 					host, NI_MAXHOST,
 | |
| 					NULL, 0, NI_NUMERICHOST);
 | |
| 			if (s)
 | |
| 				continue;
 | |
| 			ip = malloc(sizeof(*ip) + strlen(host) + 1);
 | |
| 			if (!ip)
 | |
| 				continue;
 | |
| 			strcpy(ip->ip, host);
 | |
| 			if (family == AF_INET)
 | |
| 				list_add(&ip->list, &iface->ipv4);
 | |
| 			else
 | |
| 				list_add(&ip->list, &iface->ipv6);
 | |
| 		} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
 | |
| 			struct rtnl_link_stats *stats = ifa->ifa_data;
 | |
| 			struct ifreq s;
 | |
| 
 | |
| 			memcpy(&iface->stats, stats, sizeof(*stats));
 | |
| 			memset(iface->addr, 0, ETH_ALEN);
 | |
| 			if (fd) {
 | |
| 				strcpy(s.ifr_name, ifa->ifa_name);
 | |
| 				if (!ioctl(fd, SIOCGIFHWADDR, &s))
 | |
| 					memcpy(iface->addr, s.ifr_addr.sa_data, ETH_ALEN);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	freeifaddrs(ifaddr);
 | |
| 	if (fd)
 | |
| 		close(fd);
 | |
| }
 | |
| 
 | |
| static void
 | |
| iface_flush(void)
 | |
| {
 | |
| 	struct iface *iface, *tmp;
 | |
| 
 | |
| 	avl_for_each_element_safe(&iface_tree, iface, avl, tmp) {
 | |
| 		struct iface_ip *ip, *tmp;
 | |
| 
 | |
| 		list_for_each_entry_safe(ip, tmp, &iface->ipv4, list) {
 | |
| 			list_del(&ip->list);
 | |
| 			free(ip);
 | |
| 		}
 | |
| 
 | |
| 		list_for_each_entry_safe(ip, tmp, &iface->ipv6, list) {
 | |
| 			list_del(&ip->list);
 | |
| 			free(ip);
 | |
| 		}
 | |
| 		if (!iface->alive) {
 | |
| 			avl_delete(&iface_tree, &iface->avl);
 | |
| 			free(iface);
 | |
| 		} else {
 | |
| 			iface->alive = 0;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int get_counter_delta(__u32 new, __u32 old)
 | |
| {
 | |
| 	uint32_t delta;
 | |
| 
 | |
| 	if (new < old)
 | |
| 		delta = UINT32_MAX - old + new;
 | |
| 	else
 | |
| 		delta = new - old;
 | |
| 
 | |
| 
 | |
| 	return delta > 0 ? delta : 0;
 | |
| }
 | |
| 
 | |
| void
 | |
| iface_dump(int delta)
 | |
| {
 | |
| 	struct iface *iface;
 | |
| 
 | |
| 	iface_get();
 | |
| 
 | |
| 	blob_buf_init(&b, 0);
 | |
| 	avl_for_each_element(&iface_tree, iface, avl) {
 | |
| 		struct iface_ip *ip;
 | |
| 		void *c, *d;
 | |
| 
 | |
| 		if (!iface->alive)
 | |
| 			continue;
 | |
| 
 | |
| 		c = blobmsg_open_table(&b, interface_resolve(iface->name));
 | |
| 		blobmsg_add_mac(&b, "hwaddr", iface->addr);
 | |
| 		if (!list_empty(&iface->ipv4)) {
 | |
| 			d = blobmsg_open_array(&b, "ipv4");
 | |
| 			list_for_each_entry(ip, &iface->ipv4, list)
 | |
| 				blobmsg_add_string(&b, NULL, ip->ip);
 | |
| 			blobmsg_close_array(&b, d);
 | |
| 		}
 | |
| 
 | |
| 		if (!list_empty(&iface->ipv4)) {
 | |
| 			d = blobmsg_open_array(&b, "ipv6");
 | |
| 			list_for_each_entry(ip, &iface->ipv6, list)
 | |
| 				blobmsg_add_string(&b, NULL, ip->ip);
 | |
| 			blobmsg_close_array(&b, d);
 | |
| 		}
 | |
| 
 | |
| 		d = blobmsg_open_table(&b, "counters");
 | |
| 		blobmsg_add_u64(&b, "rx_packets", iface->stats.rx_packets);
 | |
| 		blobmsg_add_u64(&b, "tx_packets", iface->stats.tx_packets);
 | |
| 	        blobmsg_add_u64(&b, "rx_bytes", iface->stats.rx_bytes);
 | |
| 	        blobmsg_add_u64(&b, "tx_bytes", iface->stats.tx_bytes);
 | |
| 	        blobmsg_add_u64(&b, "rx_errors", iface->stats.rx_errors);
 | |
| 	        blobmsg_add_u64(&b, "tx_errors", iface->stats.tx_errors);
 | |
| 	        blobmsg_add_u64(&b, "rx_dropped", iface->stats.rx_dropped);
 | |
| 	        blobmsg_add_u64(&b, "tx_dropped", iface->stats.tx_dropped);
 | |
| 	        blobmsg_add_u64(&b, "multicast", iface->stats.multicast);
 | |
| 	        blobmsg_add_u64(&b, "collisions", iface->stats.collisions);
 | |
| 		blobmsg_close_table(&b, d);
 | |
| 
 | |
| 		if (delta) {
 | |
| 			d = blobmsg_open_table(&b, "deltas");
 | |
| 			blobmsg_add_u32(&b, "rx_packets",
 | |
| 				get_counter_delta(iface->stats.rx_packets, iface->stats_old.rx_packets));
 | |
| 			blobmsg_add_u32(&b, "tx_packets",
 | |
| 				get_counter_delta(iface->stats.tx_packets, iface->stats_old.tx_packets));
 | |
| 		        blobmsg_add_u32(&b, "rx_bytes",
 | |
| 				get_counter_delta(iface->stats.rx_bytes, iface->stats_old.rx_bytes));
 | |
| 		        blobmsg_add_u32(&b, "tx_bytes",
 | |
| 				get_counter_delta(iface->stats.tx_bytes, iface->stats_old.tx_bytes));
 | |
| 		        blobmsg_add_u32(&b, "rx_errors",
 | |
| 				get_counter_delta(iface->stats.rx_errors, iface->stats_old.rx_errors));
 | |
| 		        blobmsg_add_u32(&b, "tx_errors",
 | |
| 				get_counter_delta(iface->stats.tx_errors, iface->stats_old.tx_errors));
 | |
| 		        blobmsg_add_u32(&b, "rx_dropped",
 | |
| 				get_counter_delta(iface->stats.rx_dropped, iface->stats_old.rx_dropped));
 | |
| 		        blobmsg_add_u32(&b, "tx_dropped",
 | |
| 				get_counter_delta(iface->stats.tx_dropped, iface->stats_old.tx_dropped));
 | |
| 		        blobmsg_add_u32(&b, "multicast",
 | |
| 				get_counter_delta(iface->stats.multicast, iface->stats_old.multicast));
 | |
| 		        blobmsg_add_u32(&b, "collisions",
 | |
| 				get_counter_delta(iface->stats.collisions, iface->stats_old.collisions));
 | |
| 			blobmsg_close_table(&b, d);
 | |
| 		}
 | |
| 		memcpy(&iface->stats_old, &iface->stats, sizeof(iface->stats));
 | |
| 
 | |
| 		bridge_dump_if(iface->name);
 | |
| 		blobmsg_close_table(&b, c);
 | |
| 	}
 | |
| 
 | |
| 	iface_flush();
 | |
| }
 | 
