
/*
 *********************************************************
 *   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
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>
#include <dirent.h>
#include <unistd.h>
#include <ctype.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <sys/ioctl.h>

#include <utils.h>
#include <bcmnvram.h>
#include <shutils.h>
#include <cy_conf.h>
#include <code_pattern.h>
#include <bcmdevs.h>
#include <net/route.h>
#include <shutils.h>

int
diag_led_4702(int type, int act)
{
	FILE *fp;	
	char string[10];
	int c = 0;
	
	int leds[3][2]={ { 1 , 6},
		         { 2 , 5},
		         { 4 , 3} };

	if( (fp=fopen("/proc/sys/diag", "r")) ){
		fgets(string, sizeof(string), fp);
		fclose(fp);
	}
	else{
		perror("/proc/sys/diag");
		return 0;
	}

	if(act == STOP_LED){
		c = (atoi(string) & leds[type][act]) + 48;
	}
	else if(act == START_LED){
		c = (atoi(string) | leds[type][act]) + 48;
	}
	fprintf(stderr, "diag led = [%d] -> [%c]\n",atoi(string), c);	

	if( (fp=fopen("/proc/sys/diag", "w")) ){
		fputc(c, fp);
		fclose(fp);
	}
	else
		perror("/proc/sys/diag");


	return 0;
}

int 
C_led_4702(int i)
{
        FILE *fp;
        char string[10];
        int flg;

        memset(string,0,10);
        /* get diag before set */
        if( (fp=fopen("/proc/sys/diag", "r")) ){
              fgets(string, sizeof(string), fp);
              fclose(fp);
        }
        else
              perror("/proc/sys/diag");

        if(i) flg=atoi(string) | 0x10 ;
        else flg=atoi(string) & 0xef;

        memset(string,0,10);
        sprintf(string,"%d",flg);
        if( (fp=fopen("/proc/sys/diag", "w")) ){
                fputs(string, fp);
                fclose(fp);
        }
        else
              perror("/proc/sys/diag");

        return 0;
}

unsigned int 
read_gpio(char *device)
{
	FILE *fp;
	unsigned int val;

        if( (fp=fopen(device, "r")) ){
            fread(&val, 4, 1, fp);
            fclose(fp);
	    //fprintf(stderr, "----- gpio %s = [%X]\n",device,val); 
	    return val;
        }
        else{
            perror(device);
            return 0;
        }
}

unsigned int 
write_gpio(char *device, unsigned int val)
{
        FILE *fp;
 
        if( (fp=fopen(device, "w")) ){
	    fwrite(&val, 4, 1, fp); 
            fclose(fp);
	    //fprintf(stderr, "----- set gpio %s = [%X]\n",device,val); 
            return 1;
        }
        else{
            perror(device);
            return 0;
        }
}
	
int
diag_led_4712(int type, int act)
{
	unsigned int control,in,outen,out;
	
#ifdef BCM94712AGR
	/* The router will crash, if we load the code into broadcom demo board. */
	return 1;
#endif
	control=read_gpio("/dev/gpio/control");
	in=read_gpio("/dev/gpio/in");
	out=read_gpio("/dev/gpio/out");
	outen=read_gpio("/dev/gpio/outen");

	
	switch (type) {
		case DIAG:	// GPIO 1
			write_gpio("/dev/gpio/control",control & 0xfd);
			write_gpio("/dev/gpio/outen",outen | 0x02);
			if (act == STOP_LED) { // stop blinking
				write_gpio("/dev/gpio/out",out | 0x02);
			} else if (act == START_LED) { // start blinking
				write_gpio("/dev/gpio/out",out & 0xfd);
			}
			//write_gpio("/dev/gpio/control",control);
			break;
		case DMZ:	// GPIO 7
                        write_gpio("/dev/gpio/control",control & 0x7f);
                        write_gpio("/dev/gpio/outen",outen | 0x80);
                        if (act == STOP_LED) {
                                write_gpio("/dev/gpio/out",out | 0x80);
                        } else if (act == START_LED) {
                                write_gpio("/dev/gpio/out",out & 0x7f);
                        }
                        //write_gpio("/dev/gpio/control",control);
                        break;

		case WL:	// GPIO 0
                        write_gpio("/dev/gpio/control",control & 0xfe);
                        write_gpio("/dev/gpio/outen",outen | 0x01);
                        if (act == STOP_LED) {
                                write_gpio("/dev/gpio/out",out | 0x01);
                        } else if (act == START_LED) {
                                write_gpio("/dev/gpio/out",out & 0xfe);
                        }
                        //write_gpio("/dev/gpio/control",control);
                        break;

	}	
	return 1;
}				
	
int C_led_4712(int i)
{
	if (i==1) 
		return diag_led(DIAG,START_LED);
	else
		return diag_led(DIAG,STOP_LED);
}		

int 
C_led(int i)
{
	if(check_hw_type() == BCM4702_CHIP)
		return C_led_4702(i);
	else
		return C_led_4712(i);
}

int
diag_led(int type, int act)
{
	if(check_hw_type() == BCM4702_CHIP)
		return diag_led_4702(type, act);
	else
		return diag_led_4712(type, act);
}

char *
get_mac_from_ip(char *ip)
{
	FILE *fp;
        char line[100];

	char ipa[50];           // ip address
	char hwa[50];           // HW address / MAC
	char mask[50];          // ntemask   
	char dev[50];           // interface
	int type;               // HW type
	int flags;              // flags
	static char mac[20]; 
							

        if ((fp = fopen("/proc/net/arp", "r")) == NULL) return NULL;

        // Bypass header -- read until newline 
	if (fgets(line, sizeof(line), fp) != (char *) NULL) {
	      // Read the ARP cache entries.
	      // IP address       HW type     Flags       HW address            Mask     Device
	      // 192.168.1.1      0x1         0x2         00:90:4C:21:00:2A     *        eth0
		for (; fgets(line, sizeof(line), fp);) {
			if(sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n", ipa, &type, &flags, hwa, mask, dev)!=6)
				continue;
			//cprintf("ip1=[%s] ip2=[%s] mac=[%s] (flags & ATF_COM)=%d\n", ip, ipa, hwa, (flags & ATF_COM));
			if(strcmp(ip, ipa))
				continue;
			//if (!(flags & ATF_COM)) {       //ATF_COM = 0x02   completed entry (ha valid)
				strcpy(mac, hwa);
				fclose(fp);
				return mac;
			//}
		}
	}

	fclose(fp);
	return "";
}

struct dns_lists *
get_dns_list(void)
{
        char list[254];
        char *next, word[254];
        struct dns_lists *dns_list = NULL;
	int i, match = 0, altdns_index = 1;
		
        dns_list = (struct dns_lists *)malloc(sizeof(struct dns_lists));
        memset(dns_list, 0, sizeof(struct dns_lists));

        dns_list->num_servers = 0;

	// nvram_safe_get("wan_dns") ==> Set by user
	// nvram_safe_get("wan_get_dns") ==> Get from DHCP, PPPoE or PPTP
	// The nvram_safe_get("wan_dns") priority is higher than nvram_safe_get("wan_get_dns")
        snprintf(list, sizeof(list), "%s %s %s", nvram_safe_get("sv_localdns"), nvram_safe_get("wan_dns"), nvram_safe_get("wan_get_dns"));
        foreach(word, list, next) {
                if(strcmp(word, "0.0.0.0") && strcmp(word, "")){
			match = 0;
			for(i=0 ; i<dns_list->num_servers ; i++){	// Skip same DNS
				if(!strcmp(dns_list->dns_server[i], word))	match = 1;
			}
			if(!match){
				snprintf(dns_list->dns_server[dns_list->num_servers], sizeof(dns_list->dns_server[dns_list->num_servers]), "%s", word);
				dns_list->num_servers++;
			}
                }
                if(dns_list->num_servers == 3)      break;	// We only need 3 DNS entries
        }
	
	/* if < 3 DNS servers found, try to insert alternates */
	while(dns_list->num_servers < 3 && altdns_index <= 3){
		char altdnsvar[32] = {0};
				
		snprintf(altdnsvar, 31, "altdns%d", altdns_index);
		
		if(strlen(nvram_safe_get(altdnsvar)) > 0){
			snprintf(dns_list->dns_server[dns_list->num_servers], sizeof(dns_list->dns_server[dns_list->num_servers]), "%s", nvram_safe_get(altdnsvar));
			dns_list->num_servers++;
		}
		altdns_index++;
	}
        return dns_list;
}

int
dns_to_resolv(void)
{
	FILE *fp_w;
	struct dns_lists *dns_list = NULL;
	int i = 0;

	/* Save DNS to resolv.conf */
	if (!(fp_w = fopen(RESOLV_FILE, "w"))) {
                perror(RESOLV_FILE);
                return errno;
        }

	if(nvram_match("dnsmasq_enable", "1")){
		fprintf(fp_w, "nameserver %s\n", nvram_get("lan_ipaddr"));
		fclose(fp_w);
		if (!(fp_w = fopen(RESOLV_FORW, "w"))) {
		    perror(RESOLV_FORW);
		    return errno;
		}
	}
	
	dns_list = get_dns_list();
        
	for(i=0 ; i<dns_list->num_servers ; i++)
               	fprintf(fp_w, "nameserver %s\n", dns_list->dns_server[i]);
	
	/* Put a pseudo DNS IP to trigger Connect On Demand */
	if(dns_list->num_servers == 0 && 
		(nvram_match("wan_proto","pppoe") || nvram_match("wan_proto","pptp") || nvram_match("wan_proto","l2tp")) && 
		nvram_match("ppp_demand","1"))
               	fprintf(fp_w, "nameserver 1.1.1.1\n");

	fclose(fp_w);
	if(dns_list)    free(dns_list);

	eval("touch", "/tmp/hosts");
				
	return 1;
}

/* Example:
 * lan_ipaddr = 192.168.1.1
 * get_dns_ip("lan_ipaddr", 1); produces "168"
 */
int
get_single_ip(char *ipaddr, int which)
{
	int ip[4]={0,0,0,0};
	int ret;

	ret = sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]);

	return ip[which];	
}

char *
get_complete_lan_ip(char *ip)
{
	static char ipaddr[20];

	int i[4]; 

	if(sscanf(nvram_safe_get("lan_ipaddr"),"%d.%d.%d.%d",&i[0],&i[1],&i[2],&i[3]) != 4)
                 return "0.0.0.0";

	snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%s", i[0],i[1],i[2],ip);

	return ipaddr;
}

char *
get_wan_face(void)
{
	static char localwanface[IFNAMSIZ];

	if(nvram_match("wan_proto", "pptp") || nvram_match("wan_proto", "l2tp") || nvram_match("wan_proto", "pppoe")){
	    if(nvram_match("pppd_pppifname",""))
		strncpy(localwanface, "ppp0", IFNAMSIZ);
	    else
		strncpy(localwanface, nvram_safe_get("pppd_pppifname"), IFNAMSIZ);
	}
	else if (nvram_invmatch("wl_mode", "ap")){

		if(check_hw_type() == BCM4702_CHIP)
			strcpy(localwanface, "eth2");
		else
			strcpy(localwanface, "eth1");

	}
	else
		strncpy(localwanface, nvram_safe_get("wan_ifname"), IFNAMSIZ);

	return localwanface;
}

int
get_ppp_pid(char *file)
{
	char buf[80];
	int pid = -1;
	if(file_to_buf(file, buf, sizeof(buf))){
		char tmp[80], tmp1[80];
		snprintf(tmp, sizeof(tmp), "/var/run/%s.pid", buf);
		file_to_buf(tmp, tmp1, sizeof(tmp1));
		pid = atoi(tmp1);
	}
	return pid;
}

int
osl_ifflags(const char *ifname)
{
    int sockfd;
    struct ifreq ifreq;
    int flags = 0;

    if ((sockfd = socket( AF_INET, SOCK_DGRAM, 0 )) < 0) {
	perror("socket");
	return flags;
    }

    strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) {
	    flags = 0;
    } else {
	    flags = ifreq.ifr_flags;
    }
    close(sockfd);
    return flags;
}

int
check_wan_link(int num)
{
	int wan_link = 0;

	if(nvram_match("wan_proto", "pptp") || nvram_match("wan_proto", "l2tp") || nvram_match("wan_proto", "pppoe") || nvram_match("wan_proto", "heartbeat")){
		FILE *fp;
		char filename[80];
		char *name;

		if(num == 0)
			strcpy(filename, "/tmp/ppp/link");
		if ((fp = fopen(filename, "r"))){
			int pid = -1;
			fclose(fp);
			if(nvram_match("wan_proto", "heartbeat")){
				char buf[20];
				file_to_buf("/tmp/ppp/link", buf, sizeof(buf));
				pid = atoi(buf);
			}
			else
				pid = get_ppp_pid(filename);

			name = find_name_by_proc(pid);
			if(!strncmp(name, "pppoecd", 7) ||	// for PPPoE
			   !strncmp(name, "pppd", 4) ||		// for PPTP
			   !strncmp(name, "bpalogin", 8))	// for HeartBeat
				wan_link = 1;     //connect
			else{
				printf("The %s had been died, remove %s\n", nvram_safe_get("wan_proto"), filename);
				wan_link = 0;	// For some reason, the pppoed had been died, but link file still exist.
				unlink(filename);
			}
		}
	}
	else{
		if(nvram_invmatch("wan_ipaddr", "0.0.0.0"))
			wan_link = 1;
	}

	return wan_link;
}

int
get_int_len(int num)
{
	char buf[80];

	snprintf(buf, sizeof(buf), "%d", num);
	
	return strlen(buf);
}

int
file_to_buf(char *path, char *buf, int len)
{
	FILE *fp;

	memset(buf, 0 , len);

	if ((fp = fopen(path, "r"))) {
		fgets(buf, len, fp);
		fclose(fp);
		return 1;
	}

	return 0;
}

int
buf_to_file(char *path, char *buf)
{
	FILE *fp;

	if ((fp = fopen(path, "w"))) {
		fprintf(fp, "%s", buf);
		fclose(fp);
		return 1;
	}

	return 0;
}


#define READ_BUF_SIZE 254
/* from busybox find_pid_by_name.c */
pid_t* find_pid_by_name( char* pidName)
{
    DIR *dir;
    struct dirent *next;
    pid_t* pidList=NULL;
    int i=0;

    dir = opendir("/proc");

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

        /* Must skip ".." since that is outside /proc */
        if (strcmp(next->d_name, "..") == 0)
            continue;

        /* If it isn't a number, we don't want it */
        if (!isdigit(*next->d_name))
            continue;

        sprintf(filename, "/proc/%s/status", next->d_name);
        if (! (status = fopen(filename, "r")) ) {
            continue;
        }
        if (fgets(buffer, READ_BUF_SIZE-1, status) == NULL) {
            fclose(status);
            continue;
        }
        fclose(status);

        /* Buffer should contain a string like "Name:   binary_name" */
        sscanf(buffer, "%*s %s", name);
	//printf("buffer=[%s] name=[%s]\n",buffer,name);
        if (strcmp(name, pidName) == 0) {
            pidList=realloc( pidList, sizeof(pid_t) * (i+2));
            pidList[i++]=strtol(next->d_name, NULL, 0);
        }
    }

    if (pidList)
        pidList[i]=0;
    else {
        pidList=realloc( pidList, sizeof(pid_t));
        pidList[0]=-1;
    }
    return pidList;

}

/* Find first process pid with same name from ps command */
int find_pid_by_ps(char* pidName)
{
        FILE * fp;
        int pid= -1 ;
        char line[254];

        if((fp = popen("ps -ax", "r"))){
                while( fgets(line, sizeof(line), fp) != NULL ) {
                        if(strstr(line, pidName)){
                                sscanf(line, "%d", &pid);
                                printf("%s pid is %d\n", pidName, pid);
                                break;
                        }
                }
                pclose(fp);
        }
	
        return pid;
}

/* Find process name by pid from /proc directory */
char *find_name_by_proc(int pid)
{
        FILE *fp;
        char line[254];
	char filename[80];
	static char name[80];

	snprintf(filename, sizeof(filename), "/proc/%d/status", pid);

	if((fp = fopen(filename, "r"))){
		fgets(line, sizeof(line), fp);
        	/* Buffer should contain a string like "Name:   binary_name" */
		sscanf(line, "%*s %s", name);
        	fclose(fp);
		return name;
        }

        return "";
}

/* Find all process pid with same name from ps command */
int *find_all_pid_by_ps(char* pidName)
{
        FILE * fp;
        int pid= -1 ;
        char line[254];
	int *pidList = NULL;
	int i = 0;

        if((fp = popen("ps -ax", "r"))){
                while( fgets(line, sizeof(line), fp) != NULL ) {
                        if(strstr(line, pidName)){
                                sscanf(line, "%d", &pid);
                                printf("%s pid is %d\n", pidName, pid);
            			pidList = realloc( pidList, sizeof(int) * (i+2));
				pidList[i++] = pid;
                        }
                }
                pclose(fp);
        }
	if (pidList)
		pidList[i]=0;
	else {
		pidList = realloc( pidList, sizeof(int));
		pidList[0] = -1;
	}

        return pidList;
}

void
encode(char *buf, int len)
{
	int i;
	char ch;

	for(i=0 ; i<len ; i++){
		ch = (buf[i] & 0x03) << 6;
	        buf[i] = (buf[i] >> 2);
	        buf[i] &= 0x3f;
	        buf[i] |= ch;
		buf[i] = ~buf[i];
	}
}

void
decode(char *buf, int len)
{
	int i;
	char ch;

	for(i=0 ; i<len ; i++){
		ch = (buf[i] & 0xC0) >> 6;
	        buf[i] = (buf[i] << 2) | ch;
		buf[i] = ~buf[i];
	}
}

/*	v1.41.7 => 014107
 *	v1.2	=> 0102
 */
long
convert_ver(char *ver)
{
        char buf[10];
        int v[3];
	int ret;

        ret = sscanf(ver,"v%d.%d.%d", &v[0], &v[1], &v[2]);

	if(ret == 2){
        	snprintf(buf, sizeof(buf), "%02d%02d", v[0], v[1]);
		return atol(buf);
	}
	else if (ret == 3){
        	snprintf(buf, sizeof(buf), "%02d%02d%02d", v[0], v[1], v[2]);
		return atol(buf);
	}
	else
		return -1;
}

/* To avoid user to download old image that is not support intel flash to new hardware with intel flash.
 */
int
check_flash(void)
{
	// The V2 image can support intel flash completely, so we don't want to check.
	if(check_hw_type() == BCM4712_CHIP)
		return FALSE;
	
	// The V1.X some images cann't support intel flash, so we want to avoid user to downgrade.
	if(nvram_match("skip_amd_check", "1")){
		if(strstr(nvram_safe_get("flash_type"), "Intel") && nvram_invmatch("skip_intel_check", "1"))
			return TRUE;
		else
			return FALSE;
	}
	else	// Cann't downgrade to old firmware version, no matter AMD or Intel flash
		return TRUE;
}

int
check_action(void)
{
	char buf[80] = "";
	
	if(file_to_buf(ACTION_FILE, buf, sizeof(buf))){
		if(!strcmp(buf, "ACT_TFTP_UPGRADE")){
			fprintf(stderr, "Upgrading from tftp now, quiet exit....\n");
			return ACT_TFTP_UPGRADE;
		}
		else if(!strcmp(buf, "ACT_WEBS_UPGRADE")){
			fprintf(stderr, "Upgrading from web (https) now, quiet exit....\n");
			return ACT_WEBS_UPGRADE;
		}
		else if(!strcmp(buf, "ACT_WEB_UPGRADE")){
			fprintf(stderr, "Upgrading from web (http) now, quiet exit....\n");
			return ACT_WEB_UPGRADE;
		}
		else if(!strcmp(buf, "ACT_SW_RESTORE")){
			fprintf(stderr, "Receive restore command from web, quiet exit....\n");
			return ACT_SW_RESTORE;
		}
		else if(!strcmp(buf, "ACT_HW_RESTORE")){
			fprintf(stderr, "Receive restore commond from resetbutton, quiet exit....\n");
			return ACT_HW_RESTORE;
		}
	}
	//fprintf(stderr, "Waiting for upgrading....\n");
	return ACT_IDLE;
}

int
check_now_boot(void)
{
	char *ver = nvram_safe_get("pmon_ver");	

	// for 4712
	// The boot_ver value is lower v2.0 (no included)
	if(!strncmp(ver, "PMON", 4)){
		// cprintf("The boot is PMON\n");
		return PMON_BOOT;
	}
	// for 4712
	// The boot_ver value is higher v2.0 (included)
	else if(!strncmp(ver, "CFE", 3)){
		// cprintf("The boot is CFE\n");
		return CFE_BOOT;
	}
	else{
		cprintf("The boot is UNKNOWN\n");
		return UNKNOWN_BOOT;
	}
}

int
check_hw_type(void)
{
	uint boardflags;	

	boardflags = strtoul(nvram_safe_get("boardflags"), NULL, 0);

	if(nvram_match("boardtype", "bcm94710dev")){
		// cprintf("The chipset is BCM4702\n");
		return BCM4702_CHIP;
	}
	else if (nvram_match("boardtype", "0x0708") && !(boardflags & BFL_ENETADM)){
		// cprintf("The chipset is BCM4712L + BCM5325E\n");
		return BCM5325E_CHIP;
	}
	else{	// 0x101
		//cprintf("The chipset is BCM4712 + ADMtek\n");
		return BCM4712_CHIP;
	}
}

int
check_vlan_support(void)
{
	uint boardflags;

	boardflags = strtoul(nvram_safe_get("boardflags"), NULL, 0);

//	if(nvram_match("boardtype", "bcm94710dev")||nvram_match("boardtype", "0x0101")||(boardflags & 0x0100))
	if((nvram_match("boardtype", "0x0101")||(boardflags & 0x0100)) && nvram_invmatch("boardnum", "2"))
		return 1;
	else
		return 0;
}


int is_exist(char *filename)
{
	FILE *fp;

	if((fp = fopen(filename, "r"))){
		fclose(fp);
		return 1;
	}
	return 0;
}

void
ct_logger(int level, const char *fmt,...)
{
}

int
ct_openlog(const char *ident, int option, int facility, char *log_name)
{
	int level = atoi(nvram_safe_get(log_name));

	switch(level){
		case CONSOLE_ONLY:
			break;
	}
	return level;
}


void
ct_syslog(int level, int enable, const char *fmt,...)
{
        char buf[1000];
        va_list args;

        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);

	switch(enable){
		case CONSOLE_ONLY:
			cprintf("[%d] %s\n", getpid(), buf);	// print to console
			break;
	}
}

void
set_ip_forward(char c)
{
	FILE *fp;

	if( (fp=fopen("/proc/sys/net/ipv4/ip_forward", "r+")) ){
		fputc(c, fp);
		fclose(fp);
	} else{
		perror("/proc/sys/net/ipv4/ip_forward");
	}
}

char *strncpyz(char *dest, char const *src, size_t size)
{
    if (!size--)
	return dest;
    strncpy(dest, src, size);
    dest[size] = 0; /* Make sure the string is null terminated */
    return dest;
}

static int sockets_open(int domain, int type, int protocol)
{
    int fd = socket(domain, type, protocol);

    if (fd<0)
	cprintf("sockets_open: no usable address was found.\n");
    return fd;
}

int sys_netdev_ioctl(int family, int socket, char *if_name, int cmd,
    struct ifreq *ifr)
{
    int rc, s;

    if ((s = socket) < 0)
    {
	if ((s = sockets_open(family, family==AF_PACKET ? SOCK_PACKET :
	    SOCK_DGRAM, family==AF_PACKET ? htons(ETH_P_ALL) : 0)) < 0)
	{
	    cprintf("sys_netdev_ioctl: failed\n");
	    return -1;
	}
    }
    strncpyz(ifr->ifr_name, if_name, IFNAMSIZ);
    rc = ioctl(s, cmd, ifr);
    if (socket < 0)
	close(s);
    return rc;
}

struct wl_assoc_mac *
get_wl_assoc_mac(int *c)
{
	FILE *fp;
	struct wl_assoc_mac *wlmac = NULL;
	int count;
	char line[80];
	char list[2][20];

	wlmac = (struct wl_assoc_mac *) malloc(sizeof(struct wl_assoc_mac));
        count = *c = 0;

	if((fp = popen("wl assoclist", "r"))){
		while( fgets(line, sizeof(line), fp) != NULL ) {
			strcpy(list[0],"");
			strcpy(list[1],"");

			if(sscanf(line,"%s %s", list[0], list[1]) != 2)   // assoclist 00:11:22:33:44:55
				continue;
			if(strcmp(list[0], "assoclist"))
				continue;

			if(count > 0)
				wlmac = realloc(wlmac, sizeof(struct wl_assoc_mac) * (count + 1));

			memset(&wlmac[count], 0, sizeof(struct wl_assoc_mac));
			strncpy(wlmac[count].mac, list[1], sizeof(wlmac[0].mac));
			count ++;
		}

		pclose(fp);
		//cprintf("Count of wl assoclist mac is %d\n", count);
		*c = count;
		return wlmac;
	}

	return NULL;
}

struct mtu_lists mtu_list[] = {
#if COUNTRY == JAPAN
        { "pppoe", "576",   "1454"},
#else
        { "pppoe", "576",   "1492"},
#endif

        { "pptp", "576",   "1460"},

        { "l2tp", "576",   "1460"},

        { "dhcp", "576",   "1500"},
        { "static", "576",   "1500"},
        { "heartbeat", "576",   "1500"},
        { "default", "576",   "1500"},	// The value must be at last
};

struct mtu_lists *
get_mtu(char *proto) 
{
	struct mtu_lists *v = NULL;

	for(v = mtu_list ; v < &mtu_list[STRUCT_LEN(mtu_list)] ; v++) {	
		if(!strcmp(proto, v->proto))
			return v;			

	}
	return v;	// Use default settings
}

void
set_host_domain_name(void)
{
	char buf[254];

	/* Allow you to use gethostname to get Host Name */
	snprintf(buf, sizeof(buf), "echo \"%s\" > /proc/sys/kernel/hostname", nvram_safe_get("wan_hostname"));
	system(buf);

	/* Allow you to use getdomainname to get Domain Name */
	if(nvram_invmatch("wan_domain", ""))
		snprintf(buf, sizeof(buf), "echo \"%s\" > /proc/sys/kernel/domainname", nvram_safe_get("wan_domain"));
	else
		snprintf(buf, sizeof(buf), "echo \"%s\" > /proc/sys/kernel/domainname", nvram_safe_get("wan_get_domain"));
	
	system(buf);
}