/*
 * wifi_api.c - WiFi API implementation using libwifi.so
 *
 * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
 *
 * See LICENSE file for license related information.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <net/if_arp.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <arpa/inet.h>

#include <easy/easy.h>
#include <wifi.h>

#include "debug.h"
#include "util.h"
#include "timer.h"
#include "wifi_api.h"


uint8_t wifi_rssi_to_rcpi(int rssi)
{
	if (!rssi)
		return 255;

	if (rssi < -110)
		return 0;

	if (rssi > 0)
		return 220;

	return (rssi + 110) * 2;
}


int apmld_get_mlsta(const char *ifname, uint8_t *sta_macaddrs, struct wifi_mlsta *mlsta)
{
	return wifi_get_mlsta_info(ifname, sta_macaddrs, mlsta);
}

int ap_get_assoclist(const char *ifname, uint8_t *sta_macaddrs, int *num)
{
	return wifi_get_assoclist(ifname, sta_macaddrs, num);
}

int interface_get_4addr_parent(const char *ifname, char *parent)
{
	return wifi_get_4addr_parent(ifname, parent);
}


int is_affiliated_ap(const char *ifname)
{
	struct wifi_ap ap = {0};
	int ret;

	ret = wifi_ap_info(ifname, &ap);
	if (ret)
		return false;

	if (ap.bss.mlo_link_id == -1 || hwaddr_is_zero(ap.bss.mld_macaddr))
		return false;

	return true;
}

int is_wifi_interface(const char *ifname)
{
	char parent[16] = {0};
	char path[512] = {0};
	char rpath[PATH_MAX] = {0};
	struct stat s;

	if (!ifname)
		return 0;

	/* WDS interface also has WiFi mediatype */
	if (interface_get_4addr_parent(ifname, parent) == 0 &&
	    strlen(parent)) {
		return 1;
	}

	memset(&s, 0, sizeof(struct stat));
	snprintf(path, 512, "/sys/class/net/%s/phy80211", ifname);
	if (!realpath(path, rpath))
		return 0;

	if (lstat(rpath, &s) != -1) {
		if (S_ISDIR(s.st_mode)) {
			return 1;
		}
	}

	return 0;
}

int is_ap_interface(const char *ifname)
{
	enum wifi_mode mode;
	int ret;

	if (!ifname)
		return 0;

	ret = wifi_get_mode(ifname, &mode);
	if (!ret) {
		if (mode == WIFI_MODE_AP || mode == WIFI_MODE_AP_VLAN)
			return 1;
	}

	return 0;
}
