/*
---------------------------------------------------------------------------
 $Id: tsp_local.c,v 1.3 2007/04/25 19:31:37 cnepveu Exp $
---------------------------------------------------------------------------
This source code copyright (c) Hexago Inc. 2002-2007.

  LICENSE NOTICE: You may use and modify this source code only if you
  have executed a valid license agreement with Hexago Inc. granting
  you the right to do so, the said license agreement governing such
  use and modifications.   Copyright or other intellectual property
  notices are not to be removed from the source code.
---------------------------------------------------------------------------
*/

/* LINUX */

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

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>

#define _USES_SYS_TIME_H_
#define _USES_SYS_SOCKET_H_
#define _USES_NETINET_IN_H_
#define _USES_ARPA_INET_H_

#include "platform.h"

/* get data types needed here */

#include "config.h"	/* tConf */
#include "xml_tun.h" /* tTunnel */
#include "net.h"	/* net_tools_t */
#include "tsp_net.h"/* tspClose */
#include "tsp_client.h"/*tspmain*/
#include "net_ka.h"		/* NetKeepaliveV6V4Tunnel */

/* some globals and the logging */

#include "lib.h"
#include "log.h"
#include "hex_strings.h"
#include "errors.h"

#include "tsp_tun.h"   /* linux's tun */
#include "tsp_setup.h"

/* these globals are defined by US used by alot of things in  */

char *FileName  = "gw6c.conf";
char *ScriptInterpretor = "/bin/sh";
char *ScriptExtension = "sh";
char *ScriptDir = NULL;
char *TspHomeDir = "/usr/local/etc/gw6";
char DirSeparator = '/';

int RootUid = 0;

#include <gw6cmessaging/gw6c_c_wrapper.h>
#define OPENWRT_MESSAGE_FILE "/var/run/gw6c/status.txt"
// implementation for the openwrt platform
//
// Update a text file
// for the GUI to show
//

static void openwrt_update_status_info() {
	FILE *f_config;
	
	// Open the status file for
	// total overwrite and destruction
	//
	f_config = fopen(OPENWRT_MESSAGE_FILE, "w");
	
	if (f_config == NULL)
		return;
		
	switch (gStatusInfo.eStatus) {
		case GW6C_CLISTAT__DISCONNECTEDIDLE:
			fprintf(f_config, "The tunnel is disconnected but the service is idle\n");
		break;
		case GW6C_CLISTAT__DISCONNECTEDERROR:
			fprintf(f_config, "%s\n", get_mui_string(gStatusInfo.nStatus));
		break;
		case GW6C_CLISTAT__CONNECTING:
			fprintf(f_config, "The tunnel service is connecting\n");
		break;
		case GW6C_CLISTAT__CONNECTED:
			fprintf(f_config, "Connected, routing prefix %s\n", gTunnelInfo.szDelegatedPrefix);
		break;
	}
		
	fclose(f_config);
	return;
}

error_t send_status_info( void ) { 
	openwrt_update_status_info();
	return GW6CM_UIS__NOERROR;
}

error_t send_tunnel_info( void ) {
	openwrt_update_status_info();
	return GW6CM_UIS__NOERROR;
}

error_t send_broker_list( void ) {
	openwrt_update_status_info();
	return GW6CM_UIS__NOERROR;
}

error_t send_hap6_status_info( void ) { 
  return GW6CM_UIS__NOERROR; 
}


/* Verify for ipv6 support */
static
int tspTestIPv6Support() 
{
	struct stat buf;
	if(stat("/proc/net/if_inet6",&buf) == -1) {
		Display(LOG_LEVEL_1,ELError,"tspTestIPv6Support",HEX_STR_NO_IPV6_SUPPORT_FOUND);
		Display(LOG_LEVEL_1,ELError,"tspTestIPv6Support",HEX_STR_TRY_MODPROBE_IPV6);
		return INTERFACE_SETUP_FAILED;
	}
	Display(LOG_LEVEL_2,ELInfo,"tspTestIPv6Support",HEX_STR_IPV6_SUPPORT_FOUND);

	return NO_ERROR;	
}

/* linux specific to setup an env variable */

void
tspSetEnv(char *Variable, char *Value, int Flag)
{
    setenv(Variable, Value, Flag);
	Display(LOG_LEVEL_3, ELNotice, "tspSetEnv", "%s=%s", Variable, Value);
}

// --------------------------------------------------------------------------
// Called from tsp_setup.c -> tspSetupInterface
//   Do extra platform-specific stuff before tunnel script is launched.
//
int tspSetupInterfaceLocal( tConf* pConf, tTunnel* pTun )
{
  return 0;
}

/* tspSetupTunnel() will callback here */

char *
tspGetLocalAddress(int socket, char *buffer, int size)
{
	struct sockaddr_in6 addr; /* enough place for v4 and v6 */
	struct sockaddr_in  *addr_v4 = (struct sockaddr_in *)&addr;
	struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)&addr;
	int len;

	len = sizeof addr;
	if (getsockname(socket, (struct sockaddr *)&addr, &len) < 0) {
		Display(LOG_LEVEL_3, ELError, "TryServer", HEX_STR_ERR_FIND_SRC_IP);
		return NULL;
	}

	if (addr.sin6_family == AF_INET6)
		return (char *)inet_ntop(AF_INET6, (const void*) &addr_v6->sin6_addr, buffer, size);
	else
		return (char *)inet_ntop(AF_INET, (const void*) &addr_v4->sin_addr, buffer, size);
}

/* tspSetupTunnel() will callback here */

/* start locally, ie, setup interface and any daemons or anything needed */

int tspStartLocal(SOCKET socket, tConf *c, tTunnel *t, net_tools_t *nt) 
{
	int tunfd = -1;
	int status = NO_ERROR;
	int keepalive_interval = 0;

	/* Test for root privileges */
	if(geteuid() != 0) {
		Display(LOG_LEVEL_1, ELError, "tspStartLocal", HEX_STR_FATAL_NOT_ROOT_FOR_TUN);
		return INTERFACE_SETUP_FAILED;
	}

	/* Check Ipv6 support */
	Display(LOG_LEVEL_2, ELNotice, "tspStartLocal", HEX_STR_CHECKING_LINUX_IPV6_SUPPORT);
	if(tspTestIPv6Support() == INTERFACE_SETUP_FAILED)
		return INTERFACE_SETUP_FAILED;	
	  
	/* start the tunneler service */
	if (t->keepalive_interval != NULL) {
		keepalive_interval = atoi(t->keepalive_interval);
		Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_KEEPALIVE_INTERVAL, t->keepalive_interval);
	}
	
	Display(LOG_LEVEL_3, ELInfo, "tspStartLocal", HEX_STR_GOING_DAEMON);

	if (daemon(0,0) == -1) {
		Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_CANT_FORK);
		return INTERFACE_SETUP_FAILED;
	} 

	if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) {
		if ((tunfd = TunInit(c->if_tunnel_v6udpv4)) == -1 ) {
			Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_CANT_INIT_TUN_DEV);
			return(INTERFACE_SETUP_FAILED);
		}
	}
		
	// now, run the config script
	// 
	if ( (status = tspSetupInterface(c, t) != 0) ) {
		Display(LOG_LEVEL_3, ELError, "tspStartLocal", HEX_STR_SCRIPT_FAILED);
		return INTERFACE_SETUP_FAILED;
	}
			  
	gStatusInfo.eStatus = GW6C_CLISTAT__CONNECTED;
	gStatusInfo.nStatus = GW6CM_UIS__NOERROR;
	send_status_info();

	if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6UDPV4) == 0 ) {
		status = TunMainLoop(tunfd, socket, c->keepalive,
			atoi(t->keepalive_interval), t->client_address_ipv6,
			t->keepalive_address);
		/* We got out of main loop = keepalive timeout || tunnel error */
		close(tunfd);
		tspClose(socket, nt);
		return status;
	}
			  
	else if (strcasecmp(t->type, STR_CONFIG_TUNNELMODE_V6V4) == 0 ) {
		if (keepalive_interval == 0)
			return NO_ERROR; /* if there is no keepalive, we can exit safe at this point */
		return NetKeepaliveV6V4Tunnel(t->client_address_ipv6, t->keepalive_address, keepalive_interval);
	}

	return INTERFACE_SETUP_FAILED;/* should never reach here */
}


syntax highlighted by Code2HTML, v. 0.9.1