/* Copyright 2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
 *
 * This program is free software; you can redistribute it and/or modify   
 * it under the terms of the GNU General Public License as published by   
 * the Free Software Foundation; either version 2 of the License, or      
 * (at your option) any later version.                                    
 *                                                                         
 * This program is distributed in the hope that it will be useful,        
 * but WITHOUT ANY WARRANTY; without even the implied warranty of         
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
 * GNU General Public License for more details.                           
 *                                                                         
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */


#include <stdio.h>			/* *printf */
#include <string.h>			/* mem* */

#include "ipset.h"

#include <linux/netfilter_ipv4/ip_set_service.h>

/* Initialize the create. */
static void
service_create_init(void *data UNUSED)
{
	struct ip_set_req_service_create *mydata = data;
	
	mydata->size = 0;
	
	return;
}

/* Function which parses command options; returns true if it ate an option */
static int
service_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{
	return 1;
}

/* Final check; exit if not ok. */
static void
service_create_final(void *data, unsigned int flags)
{
	return;
}

/* Create commandline options */
static const struct option create_opts[] = {
	{NULL},
};

/* Add, del, test parser */
static ip_set_ip_t
service_adt_parser(int cmd UNUSED, const char *arg, void *data)
{
	struct ip_set_req_service *mydata = data;
	char *saved = ipset_strdup(arg);
	char *ptr, *tmp = saved;
    unsigned int port;

	DP("service: %p %p", arg, data);

	ptr = strsep(&tmp, "/");
	mydata->protocol = parse_protocol(ptr);

	if (mydata->protocol == 0)
		exit_error(PARAMETER_PROBLEM,
			   "Can not find %s protocol", ptr);
	if (!tmp)
		exit_error(PARAMETER_PROBLEM,
			   "Protocol, src port range and dst port range must be specified: protocol/ssprts:esprts/sdprts:edprts");

	ptr = strsep(&tmp, ":");
	parse_port(ptr, &port);
    mydata->sptStart = (u_int16_t)port;

	if (!tmp)
		exit_error(PARAMETER_PROBLEM,
			   "Protocol, src port range and dst port range must be specified: protocol/ssprts:esprts/sdprts:edprts");
	
	ptr = strsep(&tmp, "/");
	parse_port(ptr, &port);
    mydata->sptEnd = (u_int16_t)port;
	
	if (!tmp)
		exit_error(PARAMETER_PROBLEM,
			   "Protocol, src port range and dst port range must be specified: protocol/ssprts:esprts/sdprts:edprts");

	ptr = strsep(&tmp, ":");
	parse_port(ptr, &port);
    mydata->dptStart = (u_int16_t)port;

	if (!tmp)
		exit_error(PARAMETER_PROBLEM,
			   "Protocol, src port range and dst port range must be specified: protocol/ssprts:esprts/sdprts:edprts");
	else
		parse_port(tmp, &port);

    mydata->dptEnd = (u_int16_t)port;

    if ( mydata->dptEnd < mydata->dptStart || mydata->sptEnd < mydata->sptStart)
        exit_error(PARAMETER_PROBLEM, "Wrong port range %d:%d/%d:%d End Port should be large than start port", 
                                        mydata->sptStart, mydata->sptEnd, mydata->dptStart, mydata->dptEnd);

	ipset_free(saved);
	return 1;	
}

/*
 * Print and save
 */

static void
service_initheader(struct set *set, const void *data)
{
	const struct ip_set_req_service_create *header = data;
	struct ip_set_req_service_create *map = set->settype->header;
		
	memset(map, 0, sizeof(struct ip_set_req_service_create));
	map->size = header->size;
}

static void
service_printheader(struct set *set, unsigned options)
{
	printf("%s %s\n", 
	       set->name,
	       set->settype->typename);

}

static void
service_printips_sorted(struct set *set, void *data,
			u_int32_t len, unsigned options,
			char dont_align)
{
	struct ip_set_req_service *ip;
	size_t offset = 0;
	char *s;

	while (offset < len) {
		ip = data + offset;
		s = protocol_to_string(ip->protocol);
		if (s != (char *) 0)
			printf("protocol: %s, sports range: %d-%d, dports:%d-%d\n", s, ip->sptStart, ip->sptEnd, ip->dptStart, ip->dptEnd);
		offset += sizeof(struct ip_set_req_service);
	}
}

static void
service_saveheader(struct set *set, unsigned options)
{
	printf("-N %s %s\n", 
	       set->name,
	       set->settype->typename);
}

static void
service_saveips(struct set *set, void *data,
		u_int32_t len, unsigned options,
		char dont_align)
{
	struct ip_set_req_service *ip;
	size_t offset = 0;
	char *s;
		
	while (offset < len) {
		ip = data + offset;
		s = protocol_to_string(ip->protocol);
		if (s != (char *) 0)
			printf("-A %s %s/%d:%d/%d:%d\n", set->name, s, ip->sptStart, ip->sptEnd, ip->dptStart, ip->dptEnd);
		offset += sizeof(struct ip_set_req_service);
	}
}

static void
service_usage(void)
{
	printf
	    ("-N set service\n"
	     "-A set PROTOCOL/SSPTS:ESPTS/SDPTS:EDPTS\n"
	     "-D set PROTOCOL/SSPTS:ESPTS/SDPTS:EDPTS\n"
	     "-T set PROTOCOL/SSPTS:ESPTS/SDPTS:EDPTS\n");
}

static struct settype settype_service = {
	.typename = SETTYPE_NAME,
	.protocol_version = IP_SET_PROTOCOL_VERSION,

	/* Create */
	.create_size = sizeof(struct ip_set_req_service_create),
	.create_init = service_create_init,
	.create_parse = service_create_parse,
	.create_final = service_create_final,
	.create_opts = create_opts,

	/* Add/del/test */
	.adt_size = sizeof(struct ip_set_req_service),
	.adt_parser = service_adt_parser,

	/* Printing */
	.header_size = sizeof(struct ip_set_req_service_create),
	.initheader = service_initheader,
	.printheader = service_printheader,
	.printips = service_printips_sorted,
	.printips_sorted = service_printips_sorted,
	.saveheader = service_saveheader,
	.saveips = service_saveips,
	
	.usage = service_usage,
};

CONSTRUCTOR(service)
{
	settype_register(&settype_service);

}
