/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2010-2016 Intel Corporation.
 * Copyright(c) 2014 6WIND S.A.
 * All rights reserved.
 */

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>

#include "pcap_osdep.h"

int
osdep_iface_index_get(const char *name)
{
	return if_nametoindex(name);
}

int
osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
{
	struct if_msghdr *ifm;
	struct sockaddr_dl *sdl;
	int mib[6];
	size_t len = 0;
	char *buf;

	mib[0] = CTL_NET;
	mib[1] = AF_ROUTE;
	mib[2] = 0;
	mib[3] = AF_LINK;
	mib[4] = NET_RT_IFLIST;
	mib[5] = if_nametoindex(if_name);

	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
		return -1;

	if (len == 0)
		return -1;

	buf = malloc(len);
	if (!buf)
		return -1;

	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
		free(buf);
		return -1;
	}
	ifm = (struct if_msghdr *)buf;
	sdl = (struct sockaddr_dl *)(ifm + 1);

	memcpy(mac->addr_bytes, LLADDR(sdl), RTE_ETHER_ADDR_LEN);

	free(buf);
	return 0;
}

int
osdep_iface_link_status(const char *if_name)
{
	struct ifmediareq ifmr;
	int fd, status = 0;

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd == -1)
		return -1;

	memset(&ifmr, 0, sizeof(ifmr));
	strlcpy(ifmr.ifm_name, if_name, sizeof(ifmr.ifm_name));

	if (ioctl(fd, SIOCGIFMEDIA, &ifmr) == 0) {
		/* IFM_AVALID means status is valid, IFM_ACTIVE means link up */
		if ((ifmr.ifm_status & IFM_AVALID) &&
		    (ifmr.ifm_status & IFM_ACTIVE))
			status = 1;
	} else {
		status = -1;
	}

	close(fd);
	return status;
}
