/*
 * Olivier Blin (oblin)
 * Martin Whitaker (martinw)
 *
 * Copyright 2005 Mandriva
 * Copyright 2020 Mageia
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/if.h>
#include <linux/wireless.h>

#include "automatic.h"
#include "stage1.h"
#include "log.h"
#include "utils.h"
#include "wireless.h"

#define WPA_SUPPLICANT_CONF	"/etc/wpa_supplicant.conf"
#define WPA_SUPPLICANT_CTRL	"/var/run/wpa_supplicant"
#define WPA_SUPPLICANT_LOG	"/var/log/wpa_supplicant.log"
#define WPA_SUPPLICANT_PID	"/var/run/wpa_supplicant.pid"

int wireless_open_socket()
{
	return socket(AF_INET, SOCK_DGRAM, 0);
}

int wireless_close_socket(int socket)
{
	return close(socket);
}

static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq)
{
	strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
	return ioctl(socket, request, wrq);
}

int wireless_is_aware(int socket, const char *ifname)
{
	struct iwreq wrq;
	return wireless_ioctl(socket, ifname, SIOCGIWNAME, &wrq) == 0;
}

enum return_type configure_wireless(const char *ifname)
{
	enum return_type results;
	char * security[] = { "No security", "WEP", "WPA/WPA2 Personal", NULL };
	char * security_auto[] = { "none", "wep", "wpa_psk", NULL };
	char * choice = NULL;
	char * message = NULL;
	char * questions[] = { "ESSID", "", NULL };
	char * questions_auto[] = { "essid", "" };
	char * key_mgmt = NULL;
	static char ** answers = NULL;
	FILE * fd;
	char cmd[256];
	int status;

	int wsock = wireless_open_socket();
	if (!wireless_is_aware(wsock, ifname)) {
		log_message("interface %s doesn't support wireless", ifname);
		wireless_close_socket(wsock);
		return RETURN_OK;
	}
	wireless_close_socket(wsock);

	results = ask_from_list_auto("Please select your wireless security mode.",
				     security, &choice, "wireless_security", security_auto);
	if (results != RETURN_OK) {
		return RETURN_BACK;
	}

	if (streq(choice, security[2])) {
		message = "Please enter your wireless settings. "
			  "The ESSID is your wireless network identifier. "
			  "The passphrase must be a string of between 8 and 63 ASCII characters.";
		questions[1] = "passphrase";
		questions_auto[1] = "wpa_psk";
		key_mgmt = "WPA-PSK";
	} else if (streq(choice, security[1])) {
		message = "Please enter your wireless settings. "
			  "The ESSID is your wireless network identifier. "
			  "The WEP key must be either a string of 10 or 26 hexadecimal digits, without any separators, "
			  "or a string of 5 or 13 ASCII characters enclosed in double quote marks (e.g. \"12345\").";
		questions[1] = "WEP key";
		questions_auto[1] = "wep_key";
		key_mgmt = "NONE";
	} else {
		message = "Please enter your wireless settings. "
			  "The ESSID is your wireless network identifier.";
		questions[1] = NULL;
		questions_auto[1] = NULL;
		key_mgmt = "NONE";
	}
	results = ask_from_entries_auto(message, questions, &answers, 32, questions_auto, NULL);
	if (results != RETURN_OK) {
		return RETURN_BACK;
	}

	fd = fopen(WPA_SUPPLICANT_PID, "r");
	if (fd) {
		unsigned pid = 0;
		unsigned count = fscanf(fd, "%u", &pid);
		fclose(fd);
		if (count == 1 && pid > 1) {
			log_message("terminating wpa_supplicant (pid %u)", pid);
			kill(pid, SIGQUIT);
			sleep(1);
		}
	}

	fd = fopen(WPA_SUPPLICANT_CONF, "w");
	if (fd == NULL) {
		stg1_error_message("unable to create " WPA_SUPPLICANT_CONF ": %s", strerror(errno));
		return RETURN_ERROR;
	}
	fprintf(fd, "ctrl_interface=" WPA_SUPPLICANT_CTRL "\n");
	fprintf(fd, "ap_scan=1\n");
	fprintf(fd, "network={\n");
	fprintf(fd, "  key_mgmt=%s\n", key_mgmt);
	fprintf(fd, "  scan_ssid=1\n");
	fprintf(fd, "  ssid=\"%s\"\n", answers[0]);
	if (streq(choice, security[2])) {
		fprintf(fd, "  psk=\"%s\"\n", answers[1]);
	} else if (streq(choice, security[1])) {
		fprintf(fd, "  wep_key0=%s\n", answers[1]);
	}
	fprintf(fd, "}\n");
	fclose(fd);

	snprintf(cmd, sizeof(cmd), "/usr/sbin/wpa_supplicant -D nl80211,wext -B -i %s -c %s -f %s -P %s",
		 ifname, WPA_SUPPLICANT_CONF, WPA_SUPPLICANT_LOG, WPA_SUPPLICANT_PID);
	log_message("running %s", cmd);
	status = system(cmd);
	if (status != 0) {
		stg1_error_message("unable to start wpa_supplicant daemon for interface \"%s\": %d", ifname, status);
		return RETURN_ERROR;
	}

	return RETURN_OK;
}
