
/*
 *********************************************************
 *   Copyright 2003, CyberTAN  Inc.  All Rights Reserved *
 *********************************************************

 This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
 the contents of this file may not be disclosed to third parties,
 copied or duplicated in any form without the prior written
 permission of CyberTAN Inc.

 This software should be used as a reference only, and it not
 intended for production use!


 THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE.  CYBERTAN
 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
*/

/*
 * Miscellaneous services
 *
 * Copyright 2001-2003, Broadcom Corporation
 * All Rights Reserved.
 * 
 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
 *
 * $Id: services.c,v 1.57 2004/02/19 06:11:09 amin Exp $
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <wait.h>
#include <sys/types.h>
#include <signal.h>

#include <bcmnvram.h>
#include <bcmconfig.h>
#include <netconf.h>
#include <shutils.h>
#include <utils.h>
#include <cy_conf.h>
#include <code_pattern.h>
#include <rc.h>
#include <sveasoft.h>

#define IFUP (IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST)

void load_vpn_modules(void)
{
 if ((nvram_match("pptp_pass", "1") || nvram_match("l2tp_pass", "1") || nvram_match("ipsec_pass", "1")) && nvram_invmatch("pptpd_enable","1")) {
  eval("/sbin/insmod","ip_conntrack_proto_gre");
  eval("/sbin/insmod","ip_nat_proto_gre");
 }
 if (nvram_match("pptp_pass", "1") && nvram_invmatch("pptpd_enable","1")) {
  eval("/sbin/insmod","ip_conntrack_pptp");
  eval("/sbin/insmod","ip_nat_pptp");
 }
}

void unload_vpn_modules(void)
{
  eval("/sbin/rmmod","ip_nat_proto_gre");
  eval("/sbin/rmmod","ip_nat_pptp");
  eval("/sbin/rmmod","ip_conntrack_pptp");
  eval("/sbin/rmmod","ip_conntrack_proto_gre");
}

int
adjust_dhcp_range(void)
{
	struct in_addr ipaddr, netaddr, netmask;

	char *lan_ipaddr = nvram_safe_get("lan_ipaddr");
	char *lan_netmask = nvram_safe_get("lan_netmask");
	char *dhcp_num = nvram_safe_get("dhcp_num");
	char *dhcp_start = nvram_safe_get("dhcp_start");

	int legal_start_ip, legal_end_ip, legal_total_ip, dhcp_start_ip;
	int set_dhcp_start_ip=0, set_dhcp_num=0;
	int adjust_ip = 0, adjust_num = 0;

	inet_aton(lan_ipaddr, &netaddr);
        inet_aton(lan_netmask, &netmask);
        inet_aton(dhcp_start, &ipaddr);
	
	legal_total_ip = 254 - get_single_ip(lan_netmask,3);
	legal_start_ip = (get_single_ip(lan_ipaddr,3) & get_single_ip(lan_netmask,3)) + 1;
	legal_end_ip = legal_start_ip + legal_total_ip - 1;
	dhcp_start_ip = atoi(dhcp_start);

	dprintf("legal_total_ip=[%d] legal_start_ip=[%d] legal_end_ip=[%d] dhcp_start_ip=[%d]\n", 
		legal_total_ip, legal_start_ip, legal_end_ip, dhcp_start_ip);

        if ((dhcp_start_ip > legal_end_ip) || (dhcp_start_ip < legal_start_ip)){
		dprintf("Illegal DHCP Start IP: We need to adjust DHCP Start ip.\n");
		set_dhcp_start_ip = legal_start_ip;
		adjust_ip = 1;
		if(atoi(dhcp_num) > legal_total_ip){
			dprintf("DHCP num is exceed, we need to adjust.");
			set_dhcp_num = legal_total_ip;
			adjust_num = 1;
		}
	}
	else{
		dprintf("Legal DHCP Start IP: We need to check DHCP num.\n");
		if((atoi(dhcp_num) + dhcp_start_ip) > legal_end_ip){
			dprintf("DHCP num is exceed, we need to adjust.\n");
			set_dhcp_num = legal_end_ip - dhcp_start_ip + 1;
			adjust_num = 1;
		}
	}

	if(adjust_ip){
		char ip[20];
		dprintf("set_dhcp_start_ip=[%d]\n", set_dhcp_start_ip);
		snprintf(ip, sizeof(ip), "%d", set_dhcp_start_ip);
		nvram_set("dhcp_start", ip);
	}
	if(adjust_num){
		char num[5];
		dprintf("set_dhcp_num=[%d]\n", set_dhcp_num);
		snprintf(num, sizeof(num), "%d", set_dhcp_num);
		nvram_set("dhcp_num", num);
	}

	return 1;
}

int
start_dhcpd(void)
{
	struct dns_lists *dns_list = NULL;
        FILE *fp;
	int i=0;
	char sigusr1[] = "-XX";
	char name[100];


	if (nvram_match("router_disable", "1") || nvram_invmatch("lan_proto", "dhcp")){
		stop_dhcpd();
		return 0;
	}

	/* Automatically adjust DHCP Start IP and num when LAN IP or netmask is changed */
	adjust_dhcp_range();

	dprintf("%s %d.%d.%d.%s %s %s\n",
		nvram_safe_get("lan_ifname"),
		get_single_ip(nvram_safe_get("lan_ipaddr"),0),
		get_single_ip(nvram_safe_get("lan_ipaddr"),1),
		get_single_ip(nvram_safe_get("lan_ipaddr"),2),
		nvram_safe_get("dhcp_start"),
		nvram_safe_get("dhcp_end"),
		nvram_safe_get("lan_lease"));

	/* Touch leases file */
	if (!(fp = fopen("/tmp/udhcpd.leases", "a"))) {
		perror("/tmp/udhcpd.leases");
		return errno;
	}
	fclose(fp);

	/* Write configuration file based on current information */
	if (!(fp = fopen("/tmp/udhcpd.conf", "w"))) {
		perror("/tmp/udhcpd.conf");
		return errno;
	}
	fprintf(fp, "pidfile /var/run/udhcpd.pid\n");
	fprintf(fp, "start %d.%d.%d.%s\n", get_single_ip(nvram_safe_get("lan_ipaddr"),0),
					   get_single_ip(nvram_safe_get("lan_ipaddr"),1),
					   get_single_ip(nvram_safe_get("lan_ipaddr"),2),
					   nvram_safe_get("dhcp_start"));
	fprintf(fp, "end %d.%d.%d.%d\n", get_single_ip(nvram_safe_get("lan_ipaddr"),0),
			      		 get_single_ip(nvram_safe_get("lan_ipaddr"),1),
			 	         get_single_ip(nvram_safe_get("lan_ipaddr"),2),
					 atoi(nvram_safe_get("dhcp_start")) + atoi(nvram_safe_get("dhcp_num")) - 1);
	fprintf(fp, "max_leases 254\n");	// Need to adjust ?
	fprintf(fp, "interface %s\n", nvram_safe_get("lan_ifname"));
	fprintf(fp, "remaining yes\n");
	fprintf(fp, "auto_time 30\n");		// N seconds to update lease table
	fprintf(fp, "lease_file /tmp/udhcpd.leases\n");
	fprintf(fp, "statics_file /tmp/udhcpd.statics\n");

	if( nvram_invmatch("lan_netmask", "")  && nvram_invmatch("lan_netmask", "0.0.0.0"))
		fprintf(fp, "option subnet %s\n", nvram_safe_get("lan_netmask"));
	
	if( nvram_invmatch("lan_ipaddr", "") && nvram_invmatch("lan_ipaddr", "0.0.0.0"))
		fprintf(fp, "option router %s\n", nvram_safe_get("lan_ipaddr"));
	
	if ( nvram_invmatch("wan_wins", "") && nvram_invmatch("wan_wins", "0.0.0.0"))
		fprintf(fp, "option wins %s\n", nvram_get("wan_wins"));
	
	// Wolf add - keep lease within reasonable timeframe
	if (atoi(nvram_safe_get("dhcp_lease")) < 10) {
		nvram_set("dhcp_lease","10");
		nvram_commit();
	}
	if (atoi(nvram_safe_get("dhcp_lease")) > 5760) {
		nvram_set("dhcp_lease","5760");
		nvram_commit();
	}

	fprintf(fp, "option lease %d\n", atoi(nvram_safe_get("dhcp_lease")) ? atoi(nvram_safe_get("dhcp_lease"))*60 : 86400);
		
	dns_list = get_dns_list();
	
	if(!dns_list || dns_list->num_servers == 0){
		
		if ( nvram_invmatch("lan_ipaddr", "") )
                	fprintf(fp, "option dns %s\n", nvram_safe_get("lan_ipaddr"));

	}
	else if (nvram_match("local_dns", "1")) {
		
		if(dns_list && ( nvram_invmatch("lan_ipaddr", "") || strlen(dns_list->dns_server[0]) > 0|| strlen(dns_list->dns_server[1]) > 0 || strlen(dns_list->dns_server[2]) > 0)){
		
			fprintf(fp, "option dns");
			
			if( nvram_invmatch("lan_ipaddr", ""))
                		fprintf(fp, " %s", nvram_safe_get("lan_ipaddr"));
		
			if(strlen(dns_list->dns_server[0]) > 0)
                		fprintf(fp, " %s", dns_list->dns_server[0]);
				
			if(strlen(dns_list->dns_server[1]) > 0)
                		fprintf(fp, " %s", dns_list->dns_server[1]);
				
			if(strlen(dns_list->dns_server[2]) > 0)
                		fprintf(fp, " %s", dns_list->dns_server[2]);					
		
                	fprintf(fp, "\n");		
		}				
	}
	else{
		
		if(dns_list && (strlen(dns_list->dns_server[0]) > 0 || strlen(dns_list->dns_server[1]) > 0 || strlen(dns_list->dns_server[2]) > 0)){
		
			fprintf(fp, "option dns");
		
			if(strlen(dns_list->dns_server[0]) > 0)
                		fprintf(fp, " %s", dns_list->dns_server[0]);
				
			if(strlen(dns_list->dns_server[1]) > 0)
                		fprintf(fp, " %s", dns_list->dns_server[1]);
				
			if(strlen(dns_list->dns_server[2]) > 0)
                		fprintf(fp, " %s", dns_list->dns_server[2]);					
		
                	fprintf(fp, "\n");		
		}
	}

	if(dns_list)    free(dns_list);
	
	//snprintf(name, sizeof(name), "%s_domain", nvram_safe_get("dhcp_domain"));
	
 	if (nvram_invmatch("wan_domain", ""))
		fprintf(fp, "option domain %s\n", nvram_safe_get("wan_domain"));
	else if (nvram_invmatch("wan_get_domain", ""))
		fprintf(fp, "option domain %s\n", nvram_safe_get("wan_get_domain"));

	/* Sveasoft addition - additional options */
	if (nvram_invmatch("dhcpd_options", "")){
		char *host_key = nvram_safe_get("dhcpd_options");
		i = 0;
		do{
			if(host_key[i] != 0x0D)
				fprintf(fp, "%c", host_key[i]);
		} while(host_key[++i]);
	}
	/* end Sveasoft addition */
	fclose(fp);

	/* Sveasoft addition - create static leases file */
	// Static for router
	if (!(fp = fopen("/tmp/udhcpd.statics", "w"))) {
		perror("/tmp/udhcpd.statics");
		return errno;
	}

	if(nvram_match("local_dns", "1") )
		fprintf(fp, "%s %s %s\n", nvram_safe_get("lan_ipaddr"), nvram_safe_get("et0macaddr"), nvram_safe_get("router_name"));

	if (nvram_invmatch("dhcpd_statics", "")){
		char *host_key = nvram_safe_get("dhcpd_statics");
		i = 0;
		do{
			if(host_key[i] != 0x0D)
				fprintf(fp, "%c", host_key[i]);
		} while(host_key[++i]);
	}
	fclose(fp);
	/* end Sveasoft addition */

	dns_to_resolv();	
	
	eval("udhcpd", "/tmp/udhcpd.conf");

	/* Dump static leases to udhcpd.leases so they can be read by dnsmasq */
	sprintf(sigusr1, "-%d", SIGUSR1);
	eval("killall", sigusr1, "udhcpd");

	dprintf("done\n");
	return 0;
}

int
stop_dhcpd(void)
{
	char sigusr1[] = "-XX";
	int ret;

/*
* Process udhcpd handles two signals - SIGTERM and SIGUSR1
*
*  - SIGUSR1 saves all leases in /tmp/udhcpd.leases
*  - SIGTERM causes the process to be killed
*
* The SIGUSR1+SIGTERM behavior is what we like so that all current client
* leases will be honorred when the dhcpd restarts and all clients can extend
* their leases and continue their current IP addresses. Otherwise clients
* would get NAK'd when they try to extend/rebind their leases and they
* would have to release current IP and to request a new one which causes
* a no-IP gap in between.
*/
	sprintf(sigusr1, "-%d", SIGUSR1);
	eval("killall", sigusr1, "udhcpd");
	sleep(1);
	ret = eval("killall", "udhcpd");

	dprintf("done\n");
	return ret;
}

int
start_dns(void)
{
        FILE *fp;
 	int ret;
	int i;
 	char name[100];

	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("dnsmasq_enable", "0")){
	  stop_dns();
	  return 0;
	}

	/* Write configuration file based on current information */
	if (!(fp = fopen("/tmp/dnsmasq.conf", "w"))) {
		perror("/tmp/dnsmasq.conf");
		return errno;
	}

	if(nvram_match("chilli_enable","1"))
		fprintf(fp, "interface=%s\n", nvram_safe_get("wl0_ifname"));	
	fprintf(fp, "interface=%s\n", nvram_safe_get("lan_ifname"));
	fprintf(fp, "resolv-file=/tmp/resolv.dnsmasq\n");
	fprintf(fp, "dhcp-leasefile=/tmp/udhcpd.leases\n");

	/* DHCP domain */
	snprintf(name, sizeof(name), "%s_domain", nvram_safe_get("dhcp_domain"));
 	if (nvram_invmatch(name, "")) {
		fprintf(fp, "domain=%s\n", nvram_safe_get(name));
	}

	/* Additional options */
	if (nvram_invmatch("dnsmasq_options", "")){
		char *host_key = nvram_safe_get("dnsmasq_options");
		i = 0;
		do{
			if(host_key[i] != 0x0D)
				fprintf(fp, "%c", host_key[i]);
		} while(host_key[++i]);
	}
	fclose(fp);

	dns_to_resolv();
	
	ret = eval("dnsmasq", "--conf-file", "/tmp/dnsmasq.conf");

  	dprintf("done\n");
	return ret;
}	

int
stop_dns(void)
{
	int ret = eval("killall", "dnsmasq");
	unlink("/tmp/resolv.dnsmasq");

	dprintf("done\n");
	return ret;
}	

int
stop_dns_clear_resolv(void)
{
        FILE *fp_w;
        int ret = eval("killall", "dnsmasq");
     
        /* Save DNS to resolv.conf */
        if (!(fp_w = fopen(RESOLV_FILE, "w"))) {
                perror(RESOLV_FILE);
                return errno;
        }
        fprintf(fp_w, "");
        fclose(fp_w);
                                                                                                                             
        dprintf("done\n");
        return ret;
}

int
start_httpd(void)
{
	int ret;

	ret = eval("httpd", "-d", "/www");
	
	if (nvram_match("httpsd_enable", "1")) {
		ret = eval("httpd", "-S", "-d", "/www");
	}

	dprintf("done\n");
	return ret;
}

int
stop_httpd(void)
{
	int ret = eval("killall", "httpd");

	dprintf("done\n");
	return ret;
}

int
start_upnp(void)
{
	char *wan_ifname = get_wan_face();
	int ret;

	if (!nvram_invmatch("upnp_enable", "0")){
		stop_upnp();
		return 0;
	}

	ret = eval("killall", "-SIGUSR1", "upnp");
	if (ret != 0) {
	    ret = eval("upnp", "-D",
		       "-L", nvram_safe_get("lan_ifname"),
		       "-W", wan_ifname);

	}
	dprintf("done\n");
	return ret;
}

int
stop_upnp(void)
{
	int ret = 0;
	
	ret = eval("killall", "upnp");

	dprintf("done\n");
	
	return ret;
}

int
start_nas(char *type)
{

	char cfgfile[64];
	char pidfile[64];
	char *auth_mode = "255";	/* -m N = WPA authorization mode (N = 0: none, 1: 802.1x, 2: WPA PSK, 255: disabled) */
	char *sec_mode  = {0};		/* -w N = security mode bitmask  (N = 1: WEP, 2: TKIP, 4: AES) */
	char *key={0}, *iface={0}, *mode={0};

	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("nas_enable", "0") || nvram_match("security_mode", "wep") || nvram_match("security_mode", "disabled")){
	  stop_nas();
	  return 0;
	}

	if (nvram_match("wl0_mode","ap")) {

		if (!type || !*type){
			if(nvram_match("wl0_mode","ap"))
				type = "lan";
			else
				type = "wan";
		}

		snprintf(cfgfile, sizeof(cfgfile), "/tmp/nas.%s.conf", type);
		snprintf(pidfile, sizeof(pidfile), "/tmp/nas.%s.pid", type);

		{
			char *argv[] = {"/usr/sbin/nas", cfgfile, pidfile, type, NULL};
			pid_t pid;

			_eval(argv, NULL, 0, &pid);
			dprintf("done\n");
		}
		return 0;
	}
	else {

		snprintf(pidfile, sizeof(pidfile), "/tmp/nas.%s.pid", type);

		/* Sveasoft rewrite - start nas with explicit parameters */
		if(0 == type || 0 == *type)
			type = "lan";

		if(!strcmp(type, "lan"))
			iface = "br0";
		else if(wl_probe("eth2"))	// identify wireless interface
			iface = "eth1";
		else
			iface = "eth2";


		if(0 == strcmp(nvram_safe_get("wl0_mode"), "ap"))
			mode = "-A";
		else
			mode = "-S";

		/* BugBug - should we bail when mode is wep ? */
		if (nvram_match("wl0_wep", "wep") || nvram_match("wl0_wep", "on") || nvram_match("wl0_wep", "restricted"))
			sec_mode = "1";
		else if (nvram_match("wl0_wep", "tkip"))
			sec_mode = "2";
		else if (nvram_match("wl0_wep", "aes"))
			sec_mode = "4";
		else if (nvram_match("wl0_wep", "tkip+aes"))
			sec_mode = "6";
		else
			sec_mode = "0";

		if (nvram_match("wl0_auth_mode", "wpa") || nvram_match("wl0_auth_mode", "radius"))
			auth_mode = "1";
		else if (nvram_match("wl0_auth_mode", "psk"))
			auth_mode = "2";
		else
			auth_mode = "255";

		if (nvram_match("wl0_auth_mode", "wpa") || nvram_match("wl0_auth_mode", "radius"))
			key = nvram_safe_get("wl0_radius_key");
		else if (nvram_match("wl0_auth_mode", "psk"))
			key = nvram_safe_get("wl_wpa_psk");
		else
			key = "";

		{
			// char *argv[] = {"nas", "-P", pidfile, "-l", nvram_safe_get("lan_ifname"), "-H", "34954", "-i", iface, mode, "-m", auth_mode, "-k", key, "-s", nvram_safe_get("wl0_ssid"), "-w", sec_mode, "-g", nvram_safe_get("wl0_wpa_gtk_rekey"), "-h", nvram_safe_get("wl0_radius_ipaddr"), "-p", nvram_safe_get("wl0_radius_port"), NULL};
			char *argv[] = {"nas", "-P", pidfile, "-H", "34954", "-i", iface, mode, "-m", auth_mode, "-k", key, "-s", nvram_safe_get("wl0_ssid"), "-w", sec_mode, "-g", nvram_safe_get("wl0_wpa_gtk_rekey"), NULL};
			pid_t pid;
			FILE *fp={0};

			_eval(argv, NULL, 0, &pid);

			fp = fopen(pidfile, "w");
			if(fp)
				fprintf(fp, "%d", pid);
			fclose(fp);

			dprintf("done\n");
		}
		return 0;
	}
}

int
stop_nas(void)
{
	/* NAS sometimes won't exit properly on a normal kill */
	int ret = eval("killall", "nas");
	sleep(2);
	eval("killall", "-9", "nas");

	dprintf("done\n");
	return ret;
}

#if 0
int
start_ntpc(void)
{
	char *servers = nvram_safe_get("ntp_server");

	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("ntpd_enable", "0"))
	  return 0;

	if (strlen(servers)) {
		char *nas_argv[] = {"ntpclient", "-h", servers, "-i", "5", "-l", "-s", "-c", "2", NULL};
		pid_t pid;

		_eval(nas_argv, NULL, 0, &pid);
	}

	dprintf("done\n");
	return 0;
}

int
stop_ntpc(void)
{
	int ret = eval("killall", "ntpclient");

	dprintf("done\n");
	return ret;
}
#endif

int
start_services(void)
{
	start_telnetd();
	start_syslog();
	start_tftpd();
	start_httpd();
	start_dhcpd();
	start_dns();
	start_upnp();
	start_nas("lan");

	// Sveasoft additions
	start_zebra();
	start_wland();
	start_wshaper();
	start_cron();	
	
#ifdef HAVE_PPTPD
	start_pptpd();
#endif

#ifdef HAVE_SSHD
	start_sshd();
#endif

#ifdef HAVE_RADVD
	start_radvd();
#endif

#ifdef HAVE_CHILLI
	start_chilli();
#endif

#ifdef HAVE_SNMP
	start_snmp();
#endif

#ifdef HAVE_WOL
	start_wol();
#endif
	// end Sveasoft additions

	dprintf("done\n");
	return 0;
}

int
stop_services(void)
{
	stop_nas();
	stop_upnp();
	stop_dhcpd();
//	stop_dns();
	stop_dns_clear_resolv();
	//stop_httpd();	// Don't kill httpd when user press Apply.
	stop_cron();
	stop_tftpd();
	stop_syslog();

	// Sveasoft additions
	stop_zebra();
	stop_wland();
	stop_telnetd();
#ifdef HAVE_SSHD
	stop_sshd();
#endif

#ifdef HAVE_RADVD
	stop_radvd();
#endif

#ifdef HAVE_CHILLI
	stop_chilli();
#endif

#ifdef HAVE_SNMP
	stop_snmp();
#endif

#ifdef HAVE_WOL
	stop_wol();
#endif
	stop_wshaper();

#ifdef HAVE_PPTPD
	stop_pptpd();
#endif

// end Sveasoft additions

	dprintf("done\n");
	return 0;
}

/////////////////////////////////////////////////////
int
start_resetbutton(void)
{
        int ret = 0;

	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("resetbutton_enable", "0"))
	  return 0;

        ret = eval("resetbutton");

        dprintf("done\n");
        return ret;
}

int
stop_resetbutton(void)
{
        int ret = 0;

        ret = eval("killall","-9","resetbutton");

        dprintf("done\n");
        return ret ;
}

int
start_iptqueue(void)
{
        int ret = 0;
	
	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("iptqueue_enable", "0"))
	  return 0;

        ret = eval("iptqueue");

        dprintf("done\n");
        return ret;
}

int
stop_iptqueue(void)
{
        int ret = 0;

        ret = eval("killall","-9","iptqueue");

        dprintf("done\n");
        return ret ;
}

int
start_tftpd(void)
{
	int ret = 0;
	pid_t pid;
	char *tftpd_argv[] = { "tftpd",
				"-s","/tmp",	// chroot to /tmp
				"-c",		// allow new files to be created
				"-l",		// standalone
			      NULL
	};

	ret = _eval(tftpd_argv, NULL, 0, &pid);

	dprintf("done\n");
	return ret;
}

int
stop_tftpd(void)
{
	int ret;

        ret = eval("killall","-9","tftpd");

	dprintf("done\n");
	return ret ;
}

int
start_cron(void)
{
	int ret = 0;
	struct stat buf;

	// Sveasoft 2003-12-15 only start if enabled
	if (nvram_match("cron_enable", "0"))
	  return 0;

	/* Create cron's database directory */
	if( stat("/var/spool", &buf) != 0 ){
		mkdir("/var/spool", 0700);
		mkdir("/var/spool/cron", 0700);
	}
	mkdir("/tmp/cron.d", 0700);

	buf_to_file("/tmp/cron.d/check_ps", "*/2 * * * * root /sbin/check_ps\n");
	cprintf("starting cron\n");
	ret = eval("/usr/sbin/cron");


	dprintf("done\n");
	return ret;
}

int
stop_cron(void)
{
	int ret = 0;

        ret = eval("killall","-9","cron");

	dprintf("done\n");
	return ret ;
}

#ifdef HAVE_ZEBRA
int zebra_init(void)
{
	if ( nvram_match("wk_mode", "gateway") ){
		printf("zebra disabled.\n");
		return 0;
	}
	else if ( nvram_match("wk_mode", "ospf") )
		return zebra_ospf_init();
	else if ( nvram_match("wk_mode", "router") )
		return zebra_ripd_init();
	else
		return 0;
}


int zebra_ospf_init(void)
{

	char *lt = nvram_safe_get("dr_lan_tx");
	char *lr = nvram_safe_get("dr_lan_rx");
	char *wt = nvram_safe_get("dr_wan_tx");
	char *wr = nvram_safe_get("dr_wan_rx");
	char *lf = nvram_safe_get("lan_ifname");
	char *wf = get_wan_face();

	FILE *fp;
	int  ret1, ret2, s=0;

//	printf("Start zebra\n");
	if ( !strcmp(lt, "0") && !strcmp(lr, "0") &&
	     !strcmp(wt, "0") && !strcmp(wr, "0") ){
		printf("zebra disabled.\n");
		return 0;
	}

	/* Write configuration file based on current information */
	if (!(fp = fopen("/tmp/zebra.conf", "w"))) {
		perror("/tmp/zebra.conf");
		return errno;
	}

	if (strlen(nvram_safe_get("zebra_conf")) < 1 || nvram_match("zebra_copt", "1"))
	{
		if (nvram_match("zebra_log", "1"))
		{
			fprintf(fp, "log file /var/log/zebra.log\n");
		}
	}

	if (strlen(nvram_safe_get("zebra_conf")) > 0)
	{
		fprintf(fp, "%s", nvram_safe_get("zebra_conf"));
	}

	fclose(fp);

	if (!(fp = fopen("/tmp/ospfd.conf", "w"))) {
		perror("/tmp/ospfd.conf");
		return errno;
	}

	if (strlen(nvram_safe_get("ospfd_conf")) < 1 || nvram_match("ospfd_copt", "1"))
	{
		fprintf(fp, "!\n");
		fprintf(fp, "password %s\n", nvram_safe_get("http_passwd"));
		fprintf(fp, "enable password %s\n", nvram_safe_get("http_passwd"));
		fprintf(fp, "!\n!\n!\n");

		fprintf(fp, "interface %s\n!\n", lf);
		fprintf(fp, "interface %s\n", wf);
		fprintf(fp, "passive interface lo\n");

		if( nvram_match("wl_br1_enable", "1") )
		{
			fprintf(fp, "!\n! 'Subnet' WDS bridge\n");
			fprintf(fp, "interface br1\n");
		}

		if(nvram_match("wl0_mode", "ap"))
		for(s=1;s<=MAX_WDS_DEVS;s++)
		{
			char wdsvarname[32] = {0};
			char wdsdevname[32] = {0};
			char wdsdevlabel[32] = {0};
			char wdsdevospf[32] = {0};
			char *dev;

			sprintf(wdsvarname, "wl_wds%d_enable", s);
			sprintf(wdsdevname, "wl_wds%d_if", s);
			sprintf(wdsdevlabel, "wl_wds%d_desc", s);
			sprintf(wdsdevospf, "wl_wds%d_ospf", s);
			dev = nvram_safe_get(wdsdevname);

			if(nvram_match(wdsvarname, "1"))
			{
				fprintf(fp, "!\n! WDS: %s\n", nvram_safe_get(wdsdevlabel));
				fprintf(fp, "interface %s\n", dev);

				if(atoi(nvram_safe_get(wdsdevospf)) > 0)
					fprintf(fp, " ip ospf cost %s\n", nvram_safe_get(wdsdevospf));
			}
		}

		fprintf(fp, "!\n");
		fprintf(fp, "router ospf\n");
		fprintf(fp, " ospf router-id %s\n", nvram_safe_get("lan_ipaddr"));
		fprintf(fp, " redistribute kernel\n");
		fprintf(fp, " redistribute connected\n");
		fprintf(fp, " redistribute static\n");
		fprintf(fp, " network 0.0.0.0/0 area 0\n"); // handle all routing
		fprintf(fp, " default-information originate\n");

		for(s=1;s<=MAX_WDS_DEVS;s++)
		{
			char wdsdevospf[32] = {0};
			char wdsdevname[32] = {0};

			sprintf(wdsdevname, "wl_wds%d_if", s);
			sprintf(wdsdevospf, "wl_wds%d_ospf", s);

			if(atoi(nvram_safe_get(wdsdevospf)) < 0)
				fprintf(fp, " passive-interface %s\n", nvram_safe_get(wdsdevname));
		}

		if (nvram_match("zebra_log", "1"))
		{
			fprintf(fp, "!\n");
			fprintf(fp, "log file /var/log/ospf.log\n");
		}

		fprintf(fp, "!\nline vty\n!\n");
	}

	if (strlen(nvram_safe_get("ospfd_conf")) > 0)
	{
		fprintf(fp, "%s", nvram_safe_get("ospfd_conf"));
	}

	fflush(fp);
	fclose(fp);

	if(nvram_match("dyn_default", "1"))
		while(!eval("/usr/sbin/ip", "route", "del", "default"))
			;

	ret1 = eval("/usr/sbin/zebra", "-d", "-f", "/tmp/zebra.conf");
	ret2 = eval("/usr/sbin/ospfd",  "-d", "-f", "/tmp/ospfd.conf");

	return ret1 + ret2;
}

int zebra_ripd_init(void)
{

	char *lt = nvram_safe_get("dr_lan_tx");
	char *lr = nvram_safe_get("dr_lan_rx");
	char *wt = nvram_safe_get("dr_wan_tx");
	char *wr = nvram_safe_get("dr_wan_rx");
	char *lf = nvram_safe_get("lan_ifname");
	char *wf = get_wan_face();

	FILE *fp;
	int  ret1, ret2;

//	printf("Start zebra\n");
	if ( !strcmp(lt, "0") && !strcmp(lr, "0") &&
	     !strcmp(wt, "0") && !strcmp(wr, "0") ){
		printf("zebra disabled.\n");
		return 0;
	}

	/* Write configuration file based on current information */
	if (!(fp = fopen("/tmp/zebra.conf", "w"))) {
		perror("/tmp/zebra.conf");
		return errno;
	}
	fclose(fp);

	if (!(fp = fopen("/tmp/ripd.conf", "w"))) {
		perror("/tmp/ripd.conf");
		return errno;
	}
	fprintf(fp, "router rip\n");
	fprintf(fp, "  network %s\n", lf);
	fprintf(fp, "  network %s\n", wf);
	fprintf(fp, "redistribute connected\n");
	//fprintf(fp, "redistribute kernel\n");
	//fprintf(fp, "redistribute static\n");

	fprintf(fp, "interface %s\n", lf);
	if( strcmp(lt, "0") != 0 )
		fprintf(fp, "  ip rip send version %s\n", lt);
	if( strcmp(lr, "0") != 0 )
		fprintf(fp, "  ip rip receive version %s\n", lr);

	fprintf(fp, "interface %s\n", wf);
	if( strcmp(wt, "0") != 0 )
		fprintf(fp, "  ip rip send version %s\n", wt);
	if( strcmp(wr, "0") != 0 )
		fprintf(fp, "  ip rip receive version %s\n", wr);

	fprintf(fp, "router rip\n");
	if( strcmp(lt, "0") == 0 )
		fprintf(fp, "  distribute-list private out %s\n",lf);
	if( strcmp(lr, "0") == 0 )
		fprintf(fp, "  distribute-list private in  %s\n",lf);
	if( strcmp(wt, "0") == 0 )
		fprintf(fp, "  distribute-list private out %s\n",wf);
	if( strcmp(wr, "0") == 0 )
		fprintf(fp, "  distribute-list private in  %s\n",wf);
	fprintf(fp, "access-list private deny any\n");

	//fprintf(fp, "debug rip events\n");
	//fprintf(fp, "log file /tmp/ripd.log\n");
	fflush(fp);
	fclose(fp);

	ret1 = eval("zebra", "-d", "-f", "/tmp/zebra.conf");
	ret2 = eval("ripd",  "-d", "-f", "/tmp/ripd.conf");
	
	return ret1 + ret2;
}
#endif

#ifdef HAVE_BIRD
int bird_init(void)
{
	FILE *fp;
	int  ret1;

	if ( nvram_match("wk_mode", "ospf") ){

		mkdir("/tmp/bird",0744);

		if (!(fp = fopen("/tmp/bird/bird.conf", "w"))) {
          		perror("/tmp/bird/bird.conf");
          		return errno;
		}

	  	char* conf_file = nvram_safe_get("bird_ospf");
	  	int i=0;

	  	do{
           		if(conf_file[i] != 0x0D)
              			fprintf(fp, "%c", conf_file[i]);
          	} while(conf_file[++i] && i < 4096);

	  	// add CR at end
          	if(conf_file[i-1] != 0x0A)
            		fprintf(fp, "%c", 0x0A);


		fflush(fp);
		fclose(fp);

		ret1 = eval("bird", "-c", "/tmp/bird/bird.conf");
	} // if wk_mode = ospf

	return 0;

}
#endif /* HAVE_BIRD */

/* Written by Sparq in 2002/07/16 */
int
start_zebra(void)
{

	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("zebra_enable", "0"))
	  return 0;
//	else if ( nvram_invmatch("wk_mode", "ospf") &&
//		  !strcmp(lt, "0") && !strcmp(lr, "0") &&
//	     	  !strcmp(wt, "0") && !strcmp(wr, "0") ){
//		printf("routing disabled.\n");
//		return 0;
//	}

#ifdef HAVE_BIRD

	if(bird_init() != 0)
	  return -1;

#elif defined(HAVE_ZEBRA)

	if(zebra_init() != 0)
	  return -1;

#endif /* HAVE_BIRD */
	return 0 ;
}

/* Written by Sparq in 2002/07/16 */
int
stop_zebra(void)
{
	int  ret1, ret2, ret3;

#ifdef HAVE_ZEBRA
//	printf("Stop zebra !\n");
	ret1 = eval("killall", "zebra");
	ret2 = eval("killall", "ripd");
	ret3 = eval("killall", "ospfd");
//	printf("Stop RET=%d, %d\n",ret1,ret2);
//	printf("Stop zebra done!\n");

	while(!(eval("killall", "zebra") && eval("killall", "ripd") && eval("killall", "ospfd")))
		sleep(1);

	dprintf("done\n");
	return ret1 | ret2 | ret3;

#elif defined(HAVE_BIRD)

	ret1 = eval("killall", "bird");

	dprintf("done\n");
	return ret1;
#else
	return -1;
#endif
}


int
start_syslog(void)
{
        int ret1 = 0, ret2 = 0;

	// Sveasoft 2003-12-15 only start if enabled
	if (!nvram_invmatch("syslogd_enable", "0"))
	  return 0;

	if(strlen(nvram_safe_get("syslogd_rem_ip")) > 0)
	  ret1 = eval("/sbin/syslogd", "-R", nvram_safe_get("syslogd_rem_ip"));
	else
	  ret1 = eval("/sbin/syslogd", "-L");

	ret2 = eval("/sbin/klogd");

	return ret1 | ret2;
}

int
stop_syslog(void)
{
	int ret;

        ret = eval("killall", "-9", "klogd");
        ret += eval("killall", "-9", "syslogd");

	dprintf("done\n");
	return ret ;
}


int
start_redial(void)
{
	int ret;
	pid_t pid;
	char *redial_argv[] = { "/tmp/ppp/redial",
				nvram_safe_get("ppp_redialperiod"),
			      NULL
	};

	symlink("/sbin/rc", "/tmp/ppp/redial");

	ret = _eval(redial_argv, NULL, 0, &pid);

	dprintf("done\n");
	return ret;
}

int 
stop_redial(void)
{
	int ret;

        ret = eval("killall","-9","redial");

	dprintf("done\n");
	return ret ;
}

int
start_radvd(void)
{
        int ret = 0;

        if (!nvram_match("radvd_enable", "1"))
          return 0;
        if (!nvram_match("ipv6_enable", "1"))
          return 0;

        nvram2file("radvd_conf", "/tmp/radvd.conf");

	system("sync");

	ret = eval("/sbin/radvd");

        dprintf("done\n");
        return ret;
}

int 
stop_radvd(void)
{
        int ret = 0;

        ret = eval("killall","radvd");

	unlink("/var/run/radvd.pid");

        dprintf("done\n");
        return ret ;
}

int
start_ipv6(void)
{
        int ret = 0;

        if (!nvram_invmatch("ipv6_enable", "0"))
          return 0;

        ret = eval("insmod","ipv6");

        dprintf("done\n");
        return ret;
}

#ifdef HAVE_CHILLI

int
start_chilli(void)
{
	int ret = 0;
	FILE *fp;

	if (!nvram_match("chilli_enable", "1"))
		return 0;

	if (!(fp = fopen("/tmp/chilli.conf", "w"))) {
		perror("/tmp/chilli.conf");
		return errno;
	}

	fprintf(fp, "radiusserver1 %s\n", nvram_get("chilli_radius"));
	fprintf(fp, "radiusserver2 %s\n", nvram_get("chilli_backup"));
	fprintf(fp, "radiussecret %s\n", nvram_get("chilli_pass"));
	if(wl_probe("eth2"))
		fprintf(fp, "dhcpif eth1\n");
	else
		fprintf(fp, "dhcpif eth2\n");
	fprintf(fp, "uamserver %s\n", nvram_get("chilli_url"));
	if(nvram_invmatch("chilli_dns1","0.0.0.0") && nvram_invmatch("chilli_dns1","")) {
		fprintf(fp, "dns1 %s\n", nvram_get("chilli_dns1"));
		if(nvram_invmatch("sv_localdns","0.0.0.0") && nvram_invmatch("sv_localdns",""))
			fprintf(fp, "dns2 %s\n", nvram_get("sv_localdns"));
	}
	else if(nvram_invmatch("sv_localdns","0.0.0.0") && nvram_invmatch("sv_localdns",""))
		fprintf(fp, "dns1 %s\n", nvram_get("sv_localdns"));

	fflush(fp);
	fclose(fp);

	ret = eval("/usr/sbin/chilli","-c","/tmp/chilli.conf");

        dprintf("done\n");
        return ret;
}

int 
stop_chilli(void)
{
        int ret = 0;

        ret = eval("killall","-9","chilli");

        dprintf("done\n");
        return ret ;
}

#endif /* HAVE_CHILLI */

int
stop_pppoe(void)
{
        int ret;

	unlink("/tmp/ppp/link");
        ret = eval("killall","pppoecd");
        ret += eval("killall", "ip-up");
        ret += eval("killall", "ip-down");

        dprintf("done\n");
        return ret ;
}

int
stop_dhcpc(void)
{
	int ret = 0;

	ret += eval("killall","udhcpc");

	dprintf("done\n");
	return ret ;
}


int
start_single_service(void)
{
	char *service;

	service = nvram_get("action_service");

	if(!service)
		kill(1, SIGHUP);

	printf("Restart service=[%s]\n",service);

	if(!strcmp(service,"dhcp")){
		stop_dhcpd();
		start_dhcpd();
	}
/* Sveasoft addition */
	else if(!strcmp(service,"router")){
		stop_zebra();
		start_zebra();
	}
	else if(!strcmp(service,"management")){
		if (nvram_match("wl0_mode","wet"))
			stop_nas();
		stop_zebra();
		stop_cron();
		stop_dhcpd();
		start_dhcpd();
		stop_telnetd();
		start_telnetd();
		stop_syslog();
		start_syslog();
		start_cron();
		start_ipv6();
#ifdef HAVE_SSHD
		stop_sshd();
		start_sshd();
#endif
#ifdef HAVE_RADVD
		stop_radvd();
		start_radvd();
#endif
#ifdef HAVE_CHILLI
		stop_chilli();
		start_chilli();
#endif
#ifdef HAVE_PPTPD
		stop_pptpd();
		start_pptpd();
#endif
		start_zebra();
		stop_firewall();
		start_firewall();
		stop_wshaper();
		start_wshaper();

#ifdef HAVE_SNMP
		stop_snmp();
		start_snmp();
#endif

#ifdef HAVE_WOL
		stop_wol();
		start_wol();
#endif
		if (nvram_match("wl0_mode","wet"))
			start_nas("lan");
	}

/* end Sveasoft additon */
	else if(!strcmp(service,"start_pppoe") || !strcmp(service,"start_pptp") || !strcmp(service,"start_l2tp") || !strcmp(service,"start_heartbeat")){
		unlink("/tmp/ppp/log");
		stop_lan();
		stop_wan();
		//stop_pppoe();
		start_lan();
		start_wan(BOOT);
		//start_pppoe(BOOT);
	}
	else if(!strcmp(service,"stop_pppoe") || !strcmp(service,"stop_pptp") || !strcmp(service,"stop_l2tp") || !strcmp(service,"stop_heartbeat")){
		stop_wan();
	}
	else if(!strcmp(service,"filters")){
		stop_cron();
		//stop_iptqueue();
		//start_iptqueue();
		stop_firewall();
		start_firewall();
		stop_wshaper();
		start_wshaper();
		start_cron();
	}
	else if(!strcmp(service,"forward")){
		stop_firewall();
		start_firewall();
		stop_wshaper();
		start_wshaper();
	}
	else if(!strcmp(service,"forward_upnp")){
		stop_upnp();
		stop_firewall();
		start_upnp();
		start_firewall();
		stop_wshaper();
		start_wshaper();
	}
	else if(!strcmp(service,"static_route_del")){
		if(nvram_safe_get("action_service_arg1")){
			del_routes(nvram_safe_get("action_service_arg1"));
		}
	}
	else if(!strcmp(service,"ddns")){
		stop_ddns();
		start_ddns();
		nvram_set("ddns_change","update");
	}
	else if(!strcmp(service,"start_ping")){
		char *ip = nvram_safe_get("ping_ip");
		// use Ping.asp as a debugging console
		char cmd[256]={0};
		snprintf(cmd, sizeof(cmd), "%s > %s 2>&1 &", ip, PING_TMP);
		setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
		system(cmd);
/*
		if(!check_wan_link(0))
			buf_to_file(PING_TMP, "Network is unreachable\n");

		else if(strchr(ip, ' ') || strchr(ip, '`') || strstr(ip, PING_TMP))		// Fix Ping.asp bug, user can execute command ping in Ping.asp
			buf_to_file(PING_TMP, "Invalid IP Address or Domain Name\n");

		else if(nvram_invmatch("ping_times","") && nvram_invmatch("ping_ip","")){
			char cmd[80];
			snprintf(cmd, sizeof(cmd), "ping -c %s -f %s %s &", nvram_safe_get("ping_times"), PING_TMP, ip);
	   	     	printf("cmd=[%s]\n",cmd);
			eval("killall", "ping");
			unlink(PING_TMP);
	        	system(cmd);
		}
*/
	}
	else if(!strcmp(service,"start_traceroute")){
		char *ip = nvram_safe_get("traceroute_ip");
		if(!check_wan_link(0))
			buf_to_file(TRACEROUTE_TMP, "Network is unreachable\n");
		
		else if(strchr(ip, ' ') || strchr(ip, '`') || strstr(ip, TRACEROUTE_TMP))	// Fix Traceroute.asp bug, users can execute command in Traceroute.asp 
			buf_to_file(TRACEROUTE_TMP, "Invalid IP Address or Domain Name\n");
		
		else if(nvram_invmatch("traceroute_ip","")){
		        /* Some site block UDP packets, so we want to use ICMP packets */
			char cmd[80];
			snprintf(cmd, sizeof(cmd), "/usr/bin/traceroute -f %s %s &", TRACEROUTE_TMP, ip);
	        	printf("cmd=[%s]\n",cmd);
			eval("killall", "traceroute");
			unlink(TRACEROUTE_TMP);
	        	system(cmd);    
		}
	}
	else if(!strcmp(service,"tftp_upgrade")){
		stop_wan();
		stop_httpd();
		stop_zebra();
		stop_upnp();
		stop_cron();
	}
	else if(!strcmp(service,"http_upgrade")){
		stop_wan();
		stop_zebra();
		stop_upnp();
		stop_cron();
	}
	else if(!strcmp(service,"wireless")){
		eval("wlconf", nvram_safe_get("wl0_ifname"), "down");
		stop_services();
		stop_lan();
                if (nvram_match("wl0_auth_mode", "wpa") || nvram_match("wl0_auth_mode", "psk") || nvram_match("wl0_auth_mode", "radius"))
			sleep(4);
		eval("wlconf", nvram_safe_get("wl0_ifname"), "up");
		start_lan();
		start_services();
	}
	else if(!strcmp(service,"dhcp_release")){
		char sigusr[] = "-XX";
		sprintf(sigusr, "-%d", SIGUSR2);
		sleep(1);
		eval("killall", sigusr, "udhcpc");
	}
	else{
		nvram_unset("action_service");
		nvram_unset("action_service_arg1");
		kill(1, SIGHUP);
	}

	nvram_set("action_service","");
	nvram_set("action_service_arg1","");

	return 0;
}

int
start_pptp(int status)
{
	int ret;
	FILE *fp;
	pid_t pid;
	char *pptp_argv[] = { "pppd",
			      NULL
	};
	char username[80],passwd[80];

	// Sveasoft 2003-12-15 only start if enabled
	/* if (!nvram_invmatch("pppd_enable", "0"))
	  return 0; */

	stop_dhcpc();
	stop_pppoe();
	unload_vpn_modules();

	if(nvram_match("aol_block_traffic","0")){
		snprintf(username, sizeof(username), "%s", nvram_safe_get("ppp_username"));
		snprintf(passwd, sizeof(passwd), "%s", nvram_safe_get("ppp_passwd"));
	}
	else{
		if(!strcmp(nvram_safe_get("aol_username"),"")){
			snprintf(username, sizeof(username), "%s", nvram_safe_get("ppp_username"));
			snprintf(passwd, sizeof(passwd), "%s", nvram_safe_get("ppp_passwd"));
		}
		else{
			snprintf(username, sizeof(username), "%s", nvram_safe_get("aol_username"));
			snprintf(passwd, sizeof(passwd), "%s", nvram_safe_get("aol_passwd"));
		}
	}

	if(status != REDIAL){
		mkdir("/tmp/ppp", 0777);
		symlink("/sbin/rc", "/tmp/ppp/ip-up");
		symlink("/sbin/rc", "/tmp/ppp/ip-down");
		symlink("/dev/null", "/tmp/ppp/connect-errors");

		/* Generate options file */
	       	if (!(fp = fopen("/tmp/ppp/options", "w"))) {
       	        	perror("/tmp/ppp/options");
       	        	return -1;
	       	}
	       	fprintf(fp, "defaultroute\n");  //Add a default route to the system routing tables, using the peer as the gateway
      	 	fprintf(fp, "usepeerdns\n");    //Ask the peer for up to 2 DNS server addresses
       		fprintf(fp, "pty 'pptp %s --nolaunchpppd", nvram_safe_get("pptp_server_ip"));

		// PPTP client also supports synchronous mode.
		// This should improve the speeds.
		if(nvram_match("pptp_synchronous", "1"))
		    fprintf(fp, " --sync'\nsync\n");
		else
		    fprintf(fp, "'\n");

       		fprintf(fp, "user '%s'\n",username);
       		//fprintf(fp, "persist\n");        // Do not exit after a connection is terminated.

       		fprintf(fp, "mtu %s\n",nvram_safe_get("wan_mtu"));

		if(nvram_match("ppp_demand", "1")){ //demand mode
       			fprintf(fp, "idle %d\n",nvram_match("ppp_demand", "1") ? atoi(nvram_safe_get("ppp_idletime"))*60 : 0);
       			fprintf(fp, "demand\n");         // Dial on demand
       			fprintf(fp, "persist\n");        // Do not exit after a connection is terminated.
	       		fprintf(fp, "%s:%s\n",PPP_PSEUDO_IP,PPP_PSEUDO_GW);   // <local IP>:<remote IP>
       			fprintf(fp, "ipcp-accept-remote\n");
       			fprintf(fp, "ipcp-accept-local\n");
       			fprintf(fp, "connect true\n");
       			fprintf(fp, "noipdefault\n");          // Disables  the  default  behaviour when no local IP address is specified
       			fprintf(fp, "ktune\n");         // Set /proc/sys/net/ipv4/ip_dynaddr to 1 in demand mode if the local address changes
		}
		else{	// keepalive mode
			start_redial();
		}
		if(nvram_match("pptp_encrypt","0"))
		fprintf(fp, "nomppe\n"); // Disable mppe negotiation
    	  	fprintf(fp, "default-asyncmap\n"); // Disable  asyncmap  negotiation
		fprintf(fp, "nopcomp\n");	// Disable protocol field compression
		fprintf(fp, "noaccomp\n");	// Disable Address/Control compression
       		fprintf(fp, "noccp\n");         // Disable CCP (Compression Control Protocol)
       		fprintf(fp, "novj\n");          // Disable Van Jacobson style TCP/IP header compression
       		fprintf(fp, "nobsdcomp\n");     // Disables BSD-Compress  compression
       		fprintf(fp, "nodeflate\n");     // Disables Deflate compression
       		fprintf(fp, "lcp-echo-interval 0\n");     // Don't send an LCP echo-request frame to the peer
       		fprintf(fp, "lock\n");
       		fprintf(fp, "noauth");

		if(nvram_invmatch("pptp_extraoptions", ""))
		    fprintf(fp, "%s\n", nvram_safe_get("pptp_extraoptions"));

       		fclose(fp);

       		/* Generate pap-secrets file */
       		if (!(fp = fopen("/tmp/ppp/pap-secrets", "w"))) {
       	        	perror("/tmp/ppp/pap-secrets");
        	       	return -1;
       		}
       		fprintf(fp, "\"%s\" * \"%s\" *\n",
			username,
			passwd);
       		fclose(fp);
		chmod("/tmp/ppp/pap-secrets", 0600);

       		/* Generate chap-secrets file */
       		if (!(fp = fopen("/tmp/ppp/chap-secrets", "w"))) {
        	       	perror("/tmp/ppp/chap-secrets");
               		return -1;
       		}
       		fprintf(fp, "\"%s\" * \"%s\" *\n",
			username,
			passwd);
       		fclose(fp);
		chmod("/tmp/ppp/chap-secrets", 0600);

		/* Enable Forwarding */
		if ((fp = fopen("/proc/sys/net/ipv4/ip_forward", "r+"))) {
			fputc('1', fp);
			fclose(fp);
		} else
			perror("/proc/sys/net/ipv4/ip_forward");
	}


	/* Bring up  WAN interface */
	if(nvram_match("pptp_usedhcp", "1")){
                char *wan_hostname = nvram_get("wan_hostname");
		char *dhcp_argv[] = { "udhcpc",
				      "-i", nvram_safe_get("wan_ifname"),
				      "-p", "/var/run/udhcpc.pid",
				      "-s", "/tmp/udhcpc",
				      wan_hostname && *wan_hostname ? "-H" : NULL,
				      wan_hostname && *wan_hostname ? wan_hostname : NULL,
				      NULL
                };

		ifconfig(nvram_safe_get("wan_ifname"), IFUP, NULL, NULL);
    		
		symlink("/sbin/rc", "/tmp/udhcpc");
    		nvram_set("wan_get_dns","");
    		_eval(dhcp_argv, NULL, 0, &pid);

		// Give enough time for DHCP to get IP address.
		sleep(2);

	} else
	    ifconfig(nvram_safe_get("wan_ifname"), IFUP, nvram_safe_get("wan_ipaddr"), nvram_safe_get("wan_netmask"));

	// Start pptp client on wan interface
	ret = _eval(pptp_argv, NULL, 0, NULL);

	if (nvram_match("ppp_demand", "1")){
		/* Trigger Connect On Demand if user press Connect button in Status page */
		if(nvram_match("action_service","start_pptp") || nvram_match("action_service","start_l2tp")){
			force_to_dial();
//			force_to_dial(nvram_safe_get("action_service"));
			nvram_set("action_service","");
		}
		/* Trigger Connect On Demand if user ping pptp server */
		else
			eval("listen", nvram_safe_get("lan_ifname"));
	}

	/* Sveasoft - make sure QoS comes up after pptp pppo device */
	start_wshaper();

	dprintf("done\n");
	return ret;
}

int
stop_pptp(void)
{
	int ret;

	unlink("/tmp/ppp/link");
        ret = eval("killall","-9","pppd");
        ret += eval("killall","-9","pptp");
        ret += eval("killall","-9","listen");

	dprintf("done\n");
	return ret ;
}


int
start_l2tp(int status)
{
	int ret;
	FILE *fp;
	char *l2tp_argv[] = { "l2tpd",
			      NULL
	};
	char l2tpctrl[64];
	char username[80],passwd[80];

	//stop_dhcpc();
	stop_pppoe();
	stop_pptp();

	if(nvram_match("aol_block_traffic","0")){
		snprintf(username, sizeof(username), "%s", nvram_safe_get("ppp_username"));
		snprintf(passwd, sizeof(passwd), "%s", nvram_safe_get("ppp_passwd"));
	}
	else{
		if(!strcmp(nvram_safe_get("aol_username"),"")){
			snprintf(username, sizeof(username), "%s", nvram_safe_get("ppp_username"));
			snprintf(passwd, sizeof(passwd), "%s", nvram_safe_get("ppp_passwd"));
		}
		else{
			snprintf(username, sizeof(username), "%s", nvram_safe_get("aol_username"));
			snprintf(passwd, sizeof(passwd), "%s", nvram_safe_get("aol_passwd"));
		}		
	}

	if(status != REDIAL){
		mkdir("/tmp/ppp", 0777);
		symlink("/sbin/rc", "/tmp/ppp/ip-up");
		symlink("/sbin/rc", "/tmp/ppp/ip-down");
		symlink("/dev/null", "/tmp/ppp/connect-errors");

                /* Generate L2TP configuration file */
                if (!(fp = fopen("/tmp/l2tp.conf", "w"))) {
                        perror("/tmp/l2tp.conf");
                        return -1;
                }
                fprintf(fp, "global\n");			// Global section
                fprintf(fp, "load-handler \"sync-pppd.so\"\n");	// Load handlers
                fprintf(fp, "load-handler \"cmd.so\"\n");
                fprintf(fp, "listen-port 1701\n");		// Bind address
                fprintf(fp, "section sync-pppd\n");		// Configure the sync-pppd handler
                fprintf(fp, "section peer\n");			// Peer section
                fprintf(fp, "peer %s\n", nvram_safe_get("l2tp_server_ip"));
                fprintf(fp, "port 1701\n");
                fprintf(fp, "lac-handler sync-pppd\n");
                fprintf(fp, "section cmd\n");			// Configure the cmd handler
       		fclose(fp);

		/* Generate options file */
	       	if (!(fp = fopen("/tmp/ppp/options", "w"))) {
       	        	perror("/tmp/ppp/options");
       	        	return -1;
	       	}
	       	fprintf(fp, "defaultroute\n");  //Add a default route to the system routing tables, using the peer as the gateway
      	 	fprintf(fp, "usepeerdns\n");    //Ask the peer for up to 2 DNS server addresses
       		//fprintf(fp, "pty 'pptp %s --nolaunchpppd'\n",nvram_safe_get("pptp_server_ip")); 
       		fprintf(fp, "user '%s'\n",username);
       		//fprintf(fp, "persist\n");        // Do not exit after a connection is terminated.

		if(nvram_match("mtu_enable", "1")){
       			fprintf(fp, "mtu %s\n",nvram_safe_get("wan_mtu"));
		}
	
		if(nvram_match("ppp_demand", "1")){ //demand mode
       			fprintf(fp, "idle %d\n",nvram_match("ppp_demand", "1") ? atoi(nvram_safe_get("ppp_idletime"))*60 : 0);
       			//fprintf(fp, "demand\n");         // Dial on demand
       			//fprintf(fp, "persist\n");        // Do not exit after a connection is terminated.
	       		//fprintf(fp, "%s:%s\n",PPP_PSEUDO_IP,PPP_PSEUDO_GW);   // <local IP>:<remote IP>
       			fprintf(fp, "ipcp-accept-remote\n");        
       			fprintf(fp, "ipcp-accept-local\n");
       			fprintf(fp, "connect true\n"); 
       			fprintf(fp, "noipdefault\n");          // Disables  the  default  behaviour when no local IP address is specified
       			fprintf(fp, "ktune\n");         // Set /proc/sys/net/ipv4/ip_dynaddr to 1 in demand mode if the local address changes
		}
		else{	// keepalive mode
			start_redial();
		}

    	  	fprintf(fp, "default-asyncmap\n"); // Disable  asyncmap  negotiation
		fprintf(fp, "nopcomp\n");	// Disable protocol field compression
		fprintf(fp, "noaccomp\n");	// Disable Address/Control compression 
       		fprintf(fp, "noccp\n");         // Disable CCP (Compression Control Protocol)
       		fprintf(fp, "novj\n");          // Disable Van Jacobson style TCP/IP header compression
       		fprintf(fp, "nobsdcomp\n");     // Disables BSD-Compress  compression
       		fprintf(fp, "nodeflate\n");     // Disables Deflate compression
       		fprintf(fp, "lcp-echo-interval 0\n");     // Don't send an LCP echo-request frame to the peer
       		fprintf(fp, "lock\n");
       		fprintf(fp, "noauth\n");
	
       		fclose(fp);

       		/* Generate pap-secrets file */
       		if (!(fp = fopen("/tmp/ppp/pap-secrets", "w"))) {
       	        	perror("/tmp/ppp/pap-secrets");
        	       	return -1;
       		}
       		fprintf(fp, "\"%s\" * \"%s\" *\n",
			username,
			passwd);
       		fclose(fp);
		chmod("/tmp/ppp/pap-secrets", 0600);

       		/* Generate chap-secrets file */
       		if (!(fp = fopen("/tmp/ppp/chap-secrets", "w"))) {
        	       	perror("/tmp/ppp/chap-secrets");
               		return -1;
       		}
       		fprintf(fp, "\"%s\" * \"%s\" *\n",
			username,
			passwd);
       		fclose(fp);
		chmod("/tmp/ppp/chap-secrets", 0600);

		/* Enable Forwarding */
		if ((fp = fopen("/proc/sys/net/ipv4/ip_forward", "r+"))) {
			fputc('1', fp);
			fclose(fp);
		} else
			perror("/proc/sys/net/ipv4/ip_forward");
	}
	
	/* Bring up  WAN interface */
	//ifconfig(nvram_safe_get("wan_ifname"), IFUP,
	//	 nvram_safe_get("wan_ipaddr"), nvram_safe_get("wan_netmask"));

	ret = _eval(l2tp_argv, NULL, 0, NULL);
	sleep(1);
	snprintf(l2tpctrl, sizeof(l2tpctrl), "/usr/sbin/l2tp-control \"start-session %s\"", nvram_safe_get("l2tp_server_ip"));
	//system(l2tpctrl);
	
	if (nvram_match("ppp_demand", "1")){
		/* Trigger Connect On Demand if user press Connect button in Status page */
		if(nvram_match("action_service","start_l2tp")){
			force_to_dial();
			nvram_set("action_service","");
		}
		/* Trigger Connect On Demand if user ping pptp server */
		else
			eval("listen", nvram_safe_get("lan_ifname"));
	}
	else
		system(l2tpctrl);

	dprintf("done\n");
	return ret;
}

int
stop_l2tp(void)
{
	int ret=0;

	unlink("/tmp/ppp/link");
        ret = eval("killall","-9","pppd");
        ret += eval("killall","-9","l2tpd");
        ret += eval("killall","-9","listen");

	dprintf("done\n");
	return ret ;
}


int
start_igmp_proxy(void)
{
	int ret=0;
	char *igmp_proxy_argv[] = { "igmprt",
				    "-f",
				    "-i", get_wan_face(),
				    NULL
	};

	if (nvram_match("multicast_pass", "1"))
		ret = _eval(igmp_proxy_argv, NULL, 0, NULL);

	dprintf("done\n");
	return ret;
}

int
stop_igmp_proxy(void)
{
	int ret = eval("killall","-9","igmprt");

	dprintf("done\n");
	return ret ;
}





/*
 * Call when keepalive mode
 */
int
redial_main(int argc, char **argv)
{
	int need_redial = 0;
	int status;
	pid_t pid;
	int count = 1;
	int num;

	while(1)
	{

		sleep(atoi(argv[1]));
		num = 0;
		count ++;

		//fprintf(stderr, "check PPPoE %d\n", num);
		if(!check_wan_link(num)){
			//fprintf(stderr, "PPPoE %d need to redial\n", num);
			need_redial = 1;
		}
		else{
			//fprintf(stderr, "PPPoE %d not need to redial\n", num);
			continue;
		}


#if 0
		dprintf("Check pppx if exist: ");
		if ((fp = fopen("/proc/net/dev", "r")) == NULL) {
  	              return -1;
	        }

		while( fgets(line, sizeof(line), fp) != NULL ) {
			if(strstr(line,"ppp")) {
				match=1;
				break;
			}
		}
		fclose(fp);
		dprintf("%s",match == 1 ? "have exist\n" : "ready to dial\n");
#endif

		if(need_redial){
			pid = fork();
			switch(pid)
			{
				case -1:
					perror("fork failed");
					exit(1);
				case 0:
					if(nvram_match("wan_proto","pppoe")){
						stop_pppoe();
						eval("killall", "-9", "pppoecd");
						sleep(1);
						start_wan(REDIAL);
					}
					else if(nvram_match("wan_proto","pptp")){
						stop_pptp();
						sleep(1);
						start_wan(REDIAL);
                                        }
                                        else if(nvram_match("wan_proto","l2tp")){
                                                stop_l2tp();
                                                sleep(1);
                                                start_l2tp(REDIAL);
                                        }
//	Moded by Boris Bakchiev
// 	We dont need this at all.
//	But if this code is executed by any of pppX programs we might have to do this.

					else if(nvram_match("wan_proto","heartbeat")){
						if(is_running("bpalogin") == 0 ){
						stop_heartbeat();
						sleep(1);
						start_heartbeat(REDIAL);
                                        }

                                        }

					exit(0);
					break;
				default:
					waitpid(pid, &status, 0);
					//dprintf("parent\n");
					break;
			} // end switch
		} // end if
	} // end while
} // end main

/* begin Sveasoft additon */
int
start_telnetd(void)
{
	int ret = 0;
	pid_t pid;

	char *telnetd_argv[] = { "/usr/sbin/telnetd", NULL};

	stop_telnetd();

	if (!nvram_invmatch("telnetd_enable", "0"))
		return 0;

	ret = _eval(telnetd_argv, NULL, 0, &pid);

	dprintf("done\n");
	return ret;
}

int
stop_telnetd(void)
{
	int ret;

        ret = eval("killall","-9","telnetd");

	dprintf("done\n");
	return ret ;
}

// Following code was borowed from busybox.
// it has been greately simplified.
int is_running( char *process_name){
    DIR *dir;
    struct dirent *next;
    int retval=0;

    dir = opendir("/proc");
    if(!dir){
	perror("Cannot open /proc");
	return 0;
    }

    while ((next = readdir(dir)) != NULL) {
	FILE *status;
	char filename[100];
	char buffer[100];
	char name[100];

        if (strcmp(next->d_name, "..") == 0)
            continue;
        if (!isdigit(*next->d_name))
            continue;

        sprintf(filename, "/proc/%s/status", next->d_name);

        if (! (status = fopen(filename, "r")) )
            continue;

        if (fgets(buffer, 99, status) == NULL) {
            fclose(status);
            continue;
        }
        fclose(status);

        sscanf(buffer, "%*s %s", name);

	 if (strcmp(name, process_name) == 0)
	    retval++;
    }

    closedir(dir);
    return retval;
}
/* end Sveasoft additon */
