#include <errno.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include "nl80211.h"
#include "iw.h"

SECTION(ap);

static int handle_start_ap(struct nl80211_state *state,
			   struct nl_msg *msg, int argc, char **argv,
			   enum id_input id)
{
	struct chandef chandef;
	int res, parsed;
	char *end;
	int val, len;
	char buf[2304];

	if (argc < 6)
		return 1;

	/* SSID */
	NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]);
	argv++;
	argc--;

	/* chandef */
	res = parse_freqchan(&chandef, false, argc, argv, &parsed);
	if (res)
		return res;
	argc -= parsed;
	argv += parsed;
	res = put_chandef(msg, &chandef);
	if (res)
		return res;

	/* beacon interval */
	val = strtoul(argv[0], &end, 10);
	if (*end != '\0')
		return -EINVAL;

	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, val);
	argv++;
	argc--;

	/* dtim */
	val = strtoul(argv[0], &end, 10);
	if (*end != '\0')
		return -EINVAL;

	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, val);
	argv++;
	argc--;

	if (strcmp(argv[0], "hidden-ssid") == 0) {
		argc--;
		argv++;
		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
			    NL80211_HIDDEN_SSID_ZERO_LEN);
	} else if (strcmp(argv[0], "zeroed-ssid") == 0) {
		argc--;
		argv++;
		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
	}

	/* beacon head must be provided */
	if (strcmp(argv[0], "head") != 0)
		return 1;
	argv++;
	argc--;

	len = strlen(argv[0]);
	if (!len || (len % 2))
		return -EINVAL;

	if (!hex2bin(&argv[0][0], buf))
		return -EINVAL;

	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, (len / 2), &buf);
	argv++;
	argc--;

	if (!argc)
		return 0;

	/* tail is optional */
	if (strcmp(argv[0], "tail") == 0) {
		argv++;
		argc--;

		if (!argc)
			return -EINVAL;

		len = strlen(argv[0]);
		if (!len || (len % 2))
			return -EINVAL;

		if (!hex2bin(&argv[0][0], buf))
			return -EINVAL;

		NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, (len / 2), &buf);
		argv++;
		argc--;
	}

	if (!argc)
		return 0;

	/* inactivity time (optional) */
	if (strcmp(argv[0], "inactivity-time") == 0) {
		argv++;
		argc--;

		if (!argc)
			return -EINVAL;
		len = strlen(argv[0]);
		if (!len)
			return -EINVAL;

		val = strtoul(argv[0], &end, 10);
		if (*end != '\0')
			return -EINVAL;

		NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT, val);
		argv++;
		argc--;
	}

	if (!argc) {
		return 0;
	}

	if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0)
		return 1;

	argv++;
	argc--;

	return parse_keys(msg, &argv, &argc);
 nla_put_failure:
	return -ENOSPC;
}
COMMAND(ap, start, "",
	NL80211_CMD_NEW_BEACON, 0, CIB_NETDEV, handle_start_ap,
	"<SSID> <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]"
	" <beacon interval in TU> <DTIM period> [hidden-ssid|zeroed-ssid] head"
	" <beacon head in hexadecimal> [tail <beacon tail in hexadecimal>]"
	" [inactivity-time <inactivity time in seconds>] [key0:abcde d:1:6162636465]\n");

static int handle_stop_ap(struct nl80211_state *state,
			  struct nl_msg *msg,
			  int argc, char **argv,
			  enum id_input id)
{
	return 0;
}
COMMAND(ap, stop, "",
	NL80211_CMD_DEL_BEACON, 0, CIB_NETDEV, handle_stop_ap,
	"Stop AP functionality\n");
