#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <math.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <net/if.h>
#include <sys/un.h>
#include <netpacket/packet.h>
#include <netinet/ip.h>
#include <asm/types.h>
#include <linux/if_tun.h>
#include <linux/types.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <termios.h>

#include "skb.h"

#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>

#include "list.h"
#include "kernel_compat.h"

/* poor mans assertion code to avoid using g++ */
#define assert(expression) \
{\
	if (!(expression)) {\
		fprintf(stderr, "assertion failed at %s %d\n", __func__, __LINE__);\
		exit(-1);\
	}\
}

struct packet_info;
struct global;
struct stream;
struct gps;

#include "ieee80211.h"
#include "radiotap.h"

struct station_info {
	uint8_t mac[ETH_ALEN];
	FILE *fp;
	int32_t seqno;
	u32 round;
	uint8_t mcs, bitrate;
	int json_started;

	struct list_head list;
};

#define UTC 1
#define LAT 2
#define DLAT 3
#define LON 4
#define DLON 5
#define QUAL 6
#define NUM_SAT 7
#define ALT 9

struct gps {
	struct timespec ts_sys;
	double utc;
	double lat;
	char dlat;
	double lon;
	char dlon;
	u8 quality;
	u8 num_sat;
	double hdop;
	double alt;
	char ualt;
	double geoid;
	char ugeoid;
	double age_dgps;
	int ref_id;
};

struct global {
	int mon_fd;
	u8 wlan_addr[ETH_ALEN];
	struct event_base *ev_base;
	struct event *output_timer;
	u32 output_seqno;
	s8 bitrate_legacy;
	s8 bitrate_mcs;
	u32 output_round;
	bool disable_legacy;
	bool disable_mcs;
	bool dot11p_mode;
	u32 max_rounds;
	u32 max_neighbours;
	struct timeval output_timer_interval;
	bool random_send_interval;

	u8 num_rates;
	s8 rate_order[32];
	s8 rate_chosen;
	s8 rate_sent;

	struct list_head sta_info_list;

	bool gps_available;
	int gps_fd;
	FILE *gps_fp;
	struct gps gps;
	char out_path[256];

	bool duplicates_on;
	char duplicates_ipaddr[16];
	int sock_fd;
	struct sockaddr_in serv_addr;
};

struct packet_info {
	u8 mac_src[ETH_ALEN];
	u8 mac_dst[ETH_ALEN];
	u8 ether_src[ETH_ALEN];
	u8 ether_dst[ETH_ALEN];
	u8 bitrate;
	u8 mcs;
};

#define log_printf(x, y, format, args...) printf(format, ##args)

#define ANALYSIS_PTYPE	0x4223

#define MAX_SENDS	128
#define PAYLOAD_LENGTH	300
#define DEFAULT_SEND_INTERVAL	1	/* in seconds */
#define DEFAULT_MAX_ROUNDS	16
#define DEFAULT_EXPECTED_MAX_NEIGHBOURS        8


int get_device_mac(char *devname, u8 *mac);

int rawsock_create(char *devicename);

int monitor_tx_meshmerize_packet(struct global *global, struct sk_buff *skb, struct packet_info *pinfo);

char *print_addr(u8 *addr);

void safe_exit(struct global *global);


static inline bool is_multicast_ether_addr(const u8 *addr)
{
	if (addr[0] & 0x01)
		return true;
	else
		return false;
}

void shuffle(s8 *array, size_t n);

