#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/ax25.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include "config.h"

#define	PARAM_TXDELAY	1
#define	PARAM_PERSIST	2
#define	PARAM_SLOTTIME	3
#define	PARAM_FULLDUP	5
#define	PARAM_HARDWARE	6
#define	PARAM_RETURN	255

int main(int argc, char *argv[])
{
	unsigned char buffer[2];
	struct sockaddr sa;
	int proto = ETH_P_AX25;
	int txdelay  = -1;
	int persist  = -1;
	int slottime = -1;
	int fulldup  = -1;
	int hardware = -1;
	int kissoff  = 0;
	int port = 0;
	int found, buflen, s;

	if (ax25_config_load_ports() == -1) {
		fprintf(stderr, "kissparms: no AX.25 ports configured\n");
		return 1;
	}

	for (s = 1; s < argc; s += 2) {
		found = 0;

		if (strncmp(argv[s], "-p", 2) == 0) {
			port = atoi(argv[s + 1]) - 1;
			if (port < 0 || port >= ax25_config_num_ports()) {
				fprintf(stderr, "kissparms: invalid port number\n");
				return 1;
			}
			found = 1;
		}

		if (strncmp(argv[s], "-t", 2) == 0) {
			txdelay = atoi(argv[s + 1]) / 10;
			if (txdelay < 0 || txdelay > 255) {
				fprintf(stderr, "kissparms: invalid txdelay value\n");
				return 1;
			}
			found = 1;
		}

		if (strncmp(argv[s], "-r", 2) == 0) {
			persist = atoi(argv[s + 1]);
			if (persist < 0 || persist > 255) {
				fprintf(stderr, "kissparms: invalid persist value\n");
				return 1;
			}
			found = 1;
		}

		if (strncmp(argv[s], "-s", 2) == 0) {
			slottime = atoi(argv[s + 1]) / 10;
			if (slottime < 0 || slottime > 255) {
				fprintf(stderr, "kissparms: invalid slottime value\n");
				return 1;
			}
			found = 1;
		}

		if (strncmp(argv[s], "-f", 2) == 0) {
			if (*argv[s + 1] != 'y' && *argv[s + 1] != 'n') {
				fprintf(stderr, "kissparms: invalid full duplex setting\n");
				return 1;
			}
			fulldup = *argv[s + 1] == 'y';
			found = 1;
		}

		if (strncmp(argv[s], "-h", 2) == 0) {
			hardware = atoi(argv[s + 1]);
			if (hardware < 0 || hardware > 255) {
				fprintf(stderr, "kissparms: invalid hardware value\n");
				return 1;
			}
			found = 1;
		}

		if (strncmp(argv[s], "-exit", 5) == 0) {
			kissoff = 1;
			found = 1;
		}

		if (!found) {
			fprintf(stderr, "usage: kissparms options ...\n");
			return 1;
		}
	}

	if ((s = socket(AF_INET, SOCK_PACKET, htons(proto))) < 0) {
		perror("socket");
		return 1;
	}

	strcpy(sa.sa_data, ax25_config_get_dev(port));

	if (kissoff) {
		buffer[0] = PARAM_RETURN;
		buflen    = 1;
		if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) {
			perror("sendto");
			return 1;
		}
	} else {
		if (txdelay != -1) {
			buffer[0] = PARAM_TXDELAY;
			buffer[1] = txdelay;
			buflen    = 2;
			if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) {
				perror("sendto");
				return 1;
			}
		}
		if (persist != -1) {
			buffer[0] = PARAM_PERSIST;
			buffer[1] = persist;
			buflen    = 2;
			if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) {
				perror("sendto");
				return 1;
			}
		}
		if (slottime != -1) {
			buffer[0] = PARAM_SLOTTIME;
			buffer[1] = slottime;
			buflen    = 2;
			if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) {
				perror("sendto");
				return 1;
			}
		}
		if (fulldup != -1) {
			buffer[0] = PARAM_FULLDUP;
			buffer[1] = fulldup;
			buflen    = 2;
			if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) {
				perror("sendto");
				return 1;
			}
		}
		if (hardware != -1) {
			buffer[0] = PARAM_HARDWARE;
			buffer[1] = hardware;
			buflen    = 2;
			if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) {
				perror("sendto");
				return 1;
			}
		}
	}
	
	close(s);
	
	return 0;
}
