/* SPDX-License-Identifier: LGPL-2.1-only */
/*
 * wifiutils.h - header for common WiFi helper functions.
 *
 * Copyright (C) 2018-2024 iopsys Software Solutions AB. All rights reserved.
 *
 * Author: anjan.chanda@iopsys.eu
 */
#ifndef WIFIUTILS_H
#define WIFIUTILS_H

#include "wifidefs.h"

#define libwifi_err(...)	pr_error("libwifi: " __VA_ARGS__)
#define libwifi_warn(...)	pr_warn("libwifi: " __VA_ARGS__)
#define libwifi_info(...)	pr_info("libwifi: " __VA_ARGS__)
#define libwifi_dbg(...)	pr_debug("libwifi: " __VA_ARGS__)

uint8_t *wifi_find_ie(uint8_t *ies, size_t len, uint8_t eid);
uint8_t *wifi_find_ie_ext(uint8_t *ies, size_t len, uint8_t ext_id);

uint8_t *wifi_find_vsie(uint8_t *ies, size_t len, uint8_t *oui, uint8_t type,
						uint8_t stype);

void wifi_cap_set_from_capability_information(uint8_t *bitmap, const uint8_t *ie, size_t ie_len);
void wifi_cap_set_from_ht_capabilities_info(uint8_t *bitmap, const uint8_t *ie, size_t ie_len);
void wifi_cap_set_from_vht_capabilities_info(uint8_t *bitmap, const uint8_t *ie, size_t ie_len);
void wifi_cap_set_from_extended_capabilities(uint8_t *bitmap, const uint8_t *ie, size_t ie_len);
void wifi_cap_set_from_rm_enabled_capabilities(uint8_t *bitmap, const uint8_t *ie, size_t ie_len);
void wifi_cap_set_from_fast_bss_transition(uint8_t *bitmap, const uint8_t *ie, size_t ie_len);
void wifi_cap_set_from_ie(uint8_t *caps_bitmap, uint8_t *ie, size_t len);
void wifi_wmm_set_from_ie(struct wifi_ap_wmm_ac *ac, uint8_t *ie, size_t len);
void wifi_cap_set_from_he(uint8_t *bmp, const uint8_t *ie, size_t ielen);
void wifi_cap_set_from_eht(uint8_t *bmp, const uint8_t *ie, size_t ielen);

unsigned long wifi_mcs2rate(uint32_t mcs, uint32_t bw, uint32_t nss, enum wifi_guard gi);
uint32_t wifi_bw_enum2MHz(enum wifi_bw bw);

/** Iterator for information elements */
#define wifi_foreach_ie(e, _iebuf, _len)				\
	for ((e) = (_iebuf);						\
		(_iebuf) + (_len) - (e) - 2 - (e)[1] >= 0;		\
		(e) += 2 + (e)[1])


int wif_parse_wpa_ie(uint8_t *iebuf, size_t len, struct wifi_rsne *r);
void wifi_rsne_to_security(struct wifi_rsne *r, uint32_t *s);
int wifi_get_bss_security_from_ies(struct wifi_bss *e, uint8_t *ies, size_t len);
int wifi_oper_stds_set_from_ie(uint8_t *beacon_ies, size_t beacon_ies_len, uint8_t *std);
int wifi_ssid_advertised_set_from_ie(uint8_t *ies, size_t ies_len, bool *ssid_advertised);
int wifi_apload_set_from_ie(uint8_t *ies, size_t ies_len, struct wifi_ap_load *load);
int wifi_dtim_set_from_ie(uint8_t *ies, size_t ies_len, uint32_t *dtim);
int wifi_color_set_from_ie(uint8_t *ies, size_t ies_len, uint8_t *bsscolor);
int wifi_is_bg_rate(uint8_t rate, uint8_t* brate, uint8_t* grate);

const char * wifi_band_to_str(enum wifi_band band);
const char * wifi_bw_to_str(enum wifi_bw bw);
enum wifi_bw wifi_bw_to_enum_bw(uint16_t bw);
void correct_oper_std_by_band(enum wifi_band band, uint8_t *std);
void correct_supp_sec_by_band(enum wifi_band band, uint32_t *sec);

uint32_t wifi_get_estimated_throughput(int snr,
				       enum wifi_bw bw,
				       struct wifi_caps *caps,
				       uint8_t nss,
				       uint8_t busy);

uint16_t wifi_get_max_bandwidth_from_caps(const char *ifname, enum wifi_band band,
					  struct wifi_caps *caps, const uint8_t *cbitmap);
uint8_t wifi_standard_from_caps(const char *ifname, enum wifi_band band, struct wifi_caps *caps);

int wifi_caps_from_ies(uint8_t *ies, size_t ies_len, struct wifi_caps *cap, uint8_t *cbitmap);
int wifi_nss_from_ies(uint8_t *ies, size_t ies_len, uint8_t *nss);
int wifi_maxrate_from_ies(uint8_t *ies, size_t ies_len, uint32_t *maxrate);
int wifi_maxbw_from_ies(uint8_t *ies, size_t ies_len, enum wifi_bw *bw);
int wifi_nss_from_caps(struct wifi_caps *cap, uint8_t *nss);

int wifi_cap_from_ext_ie(uint8_t *ie, size_t ie_len, struct wifi_caps *cap);
int wifi_cap_from_ext_ie_mode(uint8_t *ie, size_t ie_len, struct wifi_caps *cap,
			       enum wifi_mode mode);

/** Helper functions to convert frequency to/from channel number */
int wifi_channel_to_freq(int chan);
int wifi_channel_to_freq_ex(int chan, enum wifi_band band);
int wifi_freq_to_channel(int freq);
enum wifi_band wifi_freq_to_band(int freq);

const int *chan2list(int chan, int bw);

/** Get list of channels for a global opclass */
int wifi_opclass_to_channels(uint32_t opclass, int *num, uint32_t *channels);

/** Get bandwidth for a global opclass */
int wifi_opclass_bandwidth(uint32_t opclass, enum wifi_bw *bw);

/** Get band for a global opclass */
int wifi_opclass_band(uint32_t opclass, enum wifi_band *band);

/** Get list of opclass entries filtered by bands and bandwidths
 *
 * @param[in] bands bitmap of 'enum wifi_band'.
 * @param[in] bandwidths bitmap of 'enum wifi_bandwidth' values.
 * @param[in|out] num_opclass number of opclass entries returned.
 * @param[out] o returned array of 'struct wifi_opclass' matching bands and bandwidths.
 * @return 0 on success, -1 on error.
 */
int wifi_get_opclass_e4table(uint32_t bands, uint32_t bandwidths,
			     size_t *num_opclass, struct wifi_opclass *o);


int wifi_get_opclass_entry(uint32_t opclass, struct wifi_opclass *entry);

uint8_t wifi_calc_txpower_percent(int8_t cur_dbm, int8_t max_dbm);




/** Generate a random wps pin */
int wifi_generate_wps_pin(unsigned long *pin);

/** Check if a wps pin is valid. Return 1 if valid; else 0 */
int wifi_is_wps_pin_valid(unsigned long pin);



#ifndef BIT
#define BIT(n)	(1U << (n))
#endif

bool __is_any_bit_set(unsigned int v, int sizeof_v, ...);
bool __is_all_bits_set(unsigned int v, int sizeof_v, ...);

#define is_any_bit_set(v, ...)	\
	__is_any_bit_set(v, 8 * sizeof(typeof(v)), __VA_ARGS__)

#define is_all_bits_set(v, ...)	\
	__is_all_bits_set(v, 8 * sizeof(typeof(v)), __VA_ARGS__)

#define is_any_bit_clear(v, ...)	\
	!__is_all_bits_set(v, 8 * sizeof(typeof(v)), __VA_ARGS__)

#define is_all_bits_clear(v, ...)	\
	!__is_any_bit_set(v, 8 * sizeof(typeof(v)), __VA_ARGS__)


#define IS_MFPR(rsn_caps)	!!(rsn_caps & BIT(6))
#define IS_MFPC(rsn_caps)	!!(rsn_caps & BIT(7))

#define IS_AKM_PSK(x)	\
		is_any_bit_set(x, WIFI_AKM_PSK, WIFI_AKM_FT_PSK, \
				WIFI_AKM_PSK_SHA256, WIFI_AKM_SAE, \
				WIFI_AKM_FT_SAE, -1)


#define IS_AKM_EAP(x)	\
		is_any_bit_set(x, WIFI_AKM_DOT1X, WIFI_AKM_FT_DOT1X, \
				WIFI_AKM_DOT1X_SHA256, WIFI_AKM_SUITE_B, \
				WIFI_AKM_SUITE_B_SHA384, \
				WIFI_AKM_FT_DOT1X_SHA384, -1)

#define IS_AKM_SAE(x)	\
		is_any_bit_set(x, WIFI_AKM_SAE, WIFI_AKM_FT_SAE, -1)


#define IS_AKM_WPA3PSK(x)	\
		is_any_bit_set(x, WIFI_AKM_SAE, -1) && \
		is_all_bits_clear(x, WIFI_AKM_PSK, WIFI_AKM_PSK_SHA256, -1)


#define IS_AKM_WPA3PSK_T(x)	\
		is_all_bits_set(x, WIFI_AKM_PSK, WIFI_AKM_SAE, -1)

#define IS_AKM_WPA2_FT_PSK(x) \
		is_all_bits_set(x, WIFI_AKM_PSK, WIFI_AKM_FT_PSK, -1)

#define IS_AKM_WPA3_FT_PSK(x)	\
		is_all_bits_set(x, WIFI_AKM_SAE, WIFI_AKM_FT_SAE, -1)

extern unsigned char microsoft_oui[];
#endif /* WIFIUTILS_H */
