/*
 *      sysinfo.c from Access Point SNMP Utils for Linux
 *
 * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 from
 * June 1991 as published by the Free Software Foundation.
 *
 * 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 <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "ap-utils.h"

#define SYS_DESCR _("System Description: ")
#define SYSINFO _("System Info")

#define OID_NUM 11

extern WINDOW *main_sub;
extern char* bridge_modes[6];
extern int poll_delay;

void atmel_sysinfo()
{
    char sysDescr[] = {
	0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x01, 0x01, 0x00
    };
    char sysDeviceInfo[] = {
	0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x01, 0x05, 0x00
    };
    char bridgeOperationalMode[] = {
	0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x01, 0x00
    };
    /* This one is ATMEL12350 EZYNET MIB specific. */
    char UpTime[] = {
	0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x02, 0x09, 0x01, 0x00
    };

char *bridge_modes[6] = {
	    _("Wireless Bridge Point to MultiPoint"),
	        _("Access Point"),
		    _("Access Point client"),
		        _("Wireless Bridge Point to Point"),
			    _("Repeater"),
			        _("unknown")
};

    
    char message[200];
    int i;
    varbind varbinds[4];
    struct sysDeviceInfo_128 str128;
    struct sysDeviceInfo_160 str160;
    extern short ap_type, ap_vendorext;
    extern int LINES, wait_mode;
    extern rdprops regdom_types[];

    /*
     * These have to represent used sysDeviceInfo_{128,160} members
     */
    uint32_t ap_sversion;
    char *ap_macaddr;
    uint32_t ap_regdomain;
    uint32_t ap_prodtype;
    char *ap_oemname;
    uint32_t ap_oemid;
    char *ap_prodname;
    uint32_t ap_hwrev;

    if (ap_type == ATMEL12350) {
	sysDescr[5] = 0xE0;
	sysDescr[6] = 0x3E;
	sysDeviceInfo[5] = 0xE0;
	sysDeviceInfo[6] = 0x3E;
	bridgeOperationalMode[5] = 0xE0;
	bridgeOperationalMode[6] = 0x3E;
    }

    print_top(wait_mode == WAIT_TIMEOUT ? POLL_ON : POLL_OFF, SYSINFO);

    if (wait_mode == WAIT_TIMEOUT)
	print_help(QT_HELP);

    while (1) {
	i = 0;

	varbinds[i].oid = sysDescr;
	varbinds[i].len_oid = sizeof(sysDescr);
	varbinds[i].value = sysDescr;
	varbinds[i].type = NULL_VALUE;
	varbinds[i].len_val = 0;
	i++;

	varbinds[i].oid = sysDeviceInfo;
	varbinds[i].len_oid = sizeof(sysDeviceInfo);
	varbinds[i].value = sysDeviceInfo;
	varbinds[i].len_val = 0;
	varbinds[i].type = NULL_VALUE;
	i++;

	varbinds[i].oid = bridgeOperationalMode;
	varbinds[i].len_oid = sizeof(bridgeOperationalMode);
	varbinds[i].value = bridgeOperationalMode;
	varbinds[i].len_val = 0;
	varbinds[i].type = NULL_VALUE;
	i++;

	if (ap_type == ATMEL12350 && ap_vendorext == EZYNET) {
	    varbinds[i].oid = UpTime;
	    varbinds[i].len_oid = sizeof(UpTime);
	    varbinds[i].value = UpTime;
	    varbinds[i].len_val = 0;
	    varbinds[i].type = NULL_VALUE;
	    i++;
	}

	if (wait_mode == WAIT_FOREVER)
	    print_help(WAIT_RET);

	if (snmp(varbinds, i, GET) < i) {
	    print_helperr(ERR_RET);
	    getch();
	    goto quit;
	}

	if (wait_mode == WAIT_FOREVER)
	    print_help(QT_HELP);

	mvwaddstr(main_sub, 0, 0, _("Device hardware/software/name info:"));
	for (i = 0; i < varbinds[0].len_val && *(varbinds[0].value + i); i++)
	    mvwaddch(main_sub, 1, i + 1, *(varbinds[0].value + i));

	if (varbinds[1].len_val == 92 || varbinds[1].len_val == 128) {
	    memcpy(&str128, varbinds[1].value,
		sizeof(struct sysDeviceInfo_128));
	    ap_sversion = str128.StructVersion;
	    ap_macaddr = str128.MacAddress;
	    ap_regdomain = swap4(str128.RegulatoryDomain);
	    ap_prodtype = str128.ProductType;
	    ap_oemname = str128.OEMName;
	    ap_oemid = str128.OEMID;
	    ap_prodname = str128.ProductName;
	    ap_hwrev = str128.HardwareRevision;
	} else { /* varbinds[1].len_val == 160 */
	    memcpy(&str160, varbinds[1].value,
		sizeof(struct sysDeviceInfo_160));
	    ap_regdomain = str160.RegulatoryDomain;
	    ap_sversion = str160.StructVersion;
	    ap_macaddr = str160.MacAddress;
	    ap_prodtype = str160.ProductType;
	    ap_oemname = str160.OEMName;
	    ap_oemid = str160.OEMID;
	    ap_prodname = str160.ProductName;
	    ap_hwrev = str160.HardwareRevision;
	}

	sprintf(message, _("Operational mode: %s"),
	    bridge_modes[*(varbinds[2].value) - 1]);
	mvwaddstr(main_sub, 2, 0, message);

	sprintf(message, "%s%02X%02X%02X%02X%02X%02X", MAC,
	    ap_macaddr[0] & 0xFF, ap_macaddr[1] & 0xFF,
	    ap_macaddr[2] & 0xFF, ap_macaddr[3] & 0xFF,
	    ap_macaddr[4] & 0xFF, ap_macaddr[5] & 0xFF);
	mvwaddstr(main_sub, 3, 0, message);

	mvwaddstr(main_sub, 4, 0, _("Product name: "));
	for (i = 0; i < 32 && ap_prodname[i]; i++)
	    waddch(main_sub, ap_prodname[i]);

	sprintf(message, _("Product type: %u"), swap4(ap_prodtype));
	mvwaddstr(main_sub, 5, 0, message);

	mvwaddstr(main_sub, 6, 0, _("OEM name: "));
	for (i = 0; i < 32 && ap_oemname[i]; i++)
	    waddch(main_sub, ap_oemname[i]);

	sprintf(message, "OEM ID: %u", swap4(ap_oemid));
	mvwaddstr(main_sub, 7, 0, message);

	sprintf(message, _("Hardware revision: %u"), swap4(ap_hwrev));
	mvwaddstr(main_sub, 8, 0, message);

	i = regdom_idx(ap_regdomain);
	sprintf(message, "Regulatory domain: %s [%d]",
	    regdom_types[i].desc, ap_regdomain);
	mvwaddstr(main_sub, 9, 0, message);

	sprintf(message, _("Info structure version: %u"), swap4(ap_sversion));
	mvwaddstr(main_sub, 10, 0, message);

	sprintf(message, _("Manufacturer OUI: %02X %02X %02X (%s)"),
	    ap_macaddr[0] & 0xFF, ap_macaddr[1] & 0xFF, ap_macaddr[2] & 0xFF,
	    oui2manufacturer(ap_macaddr));
	mvwaddstr(main_sub, 11, 0, message);

	if (ap_type == ATMEL12350 && ap_vendorext == EZYNET) {
	    unsigned int j = 0;

	    if (varbinds[3].len_val > 1) {
		for (i = 0; i < varbinds[3].len_val; i++)
		    j |= (varbinds[3].value[i]
			<< (8 * (varbinds[3].len_val - i - 1)));
	    } else {
		j = varbinds[3].value[0] & 0x80 ?
		    0xff00 | varbinds[3].value[0] : varbinds[3].value[0];
	    }
	    sprintf(message,
		_("Uptime: %u days, %02u:%02u:%02u hours:mins:secs"),
		j / 60 / 60 / 24, j / 60 / 60 % 24, j / 60 % 60, j % 60);
	    mvwaddstr(main_sub, 12, 0, message);
	}

	wrefresh(main_sub);

	i = wait_key(poll_delay);
	if (i == -1)
	    goto quit;

	switch((char) i) {
	    case 'q':
	    case 'Q':
		goto quit;
	    case 't':
	    case 'T':
		wait_mode = (wait_mode == WAIT_FOREVER ?
		    WAIT_TIMEOUT : WAIT_FOREVER);
		print_top(wait_mode == WAIT_TIMEOUT ? POLL_ON : POLL_OFF,
		    SYSINFO);
	}

	/* either timeout for user input (i == 0) or invalid key => continue */
    }
  quit:
    print_top(NULL, NULL);
    clear_main(0);
}

int get_RegDomain()
{
    char oid_dot11CurrentRegDomain[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x04, 0x01, 0x01, 0x02, 0x01 };
    varbind varbinds[1];

    varbinds[0].oid = oid_dot11CurrentRegDomain;
    varbinds[0].len_oid = sizeof(oid_dot11CurrentRegDomain);
    varbinds[0].value = oid_dot11CurrentRegDomain;
    varbinds[0].type = NULL_VALUE;
    varbinds[0].len_val = 0;

    if (snmp(varbinds, 1, GET) <= 0)
	return 0;
    return *(varbinds[0].value);
}

void nwn_sysinfo()
{
    char oid_mac[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x02, 0x01, 0x01, 0x01, 0x01 };
    char oid_manufacturerID[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x02, 0x01, 0x01, 0x08, 0x01 };
    char oid_productID[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x02, 0x01, 0x01, 0x09, 0x01 };
    char oid_dot11manufacturerOUI[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x03, 0x01, 0x02, 0x01, 0x01,
	0x01
    };
    char oid_dot11manufacturerName[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x03, 0x01, 0x02, 0x01, 0x02,
	0x01
    };
    char oid_dot11manufacturerProductName[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x03, 0x01, 0x02, 0x01, 0x03,
	0x01
    };
    char oid_dot11manufacturerProductVersion[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x03, 0x01, 0x02, 0x01, 0x04,
	0x01
    };
    char oid_dot11PHYType[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01 };
    char oid_dot11TempType[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x04, 0x01, 0x01, 0x03, 0x01 };
    char oid_TxPowerLevel1[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x04, 0x03, 0x01, 0x02, 0x01 };
    char oid_dot11PrivacyOptionImplemented[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x01, 0x01, 0x01, 0x07, 0x01 };
    char oid_dot11DiversitySupport[] =
	{ 0x2a, 0x86, 0x48, 0xce, 0x34, 0x04, 0x02, 0x01, 0x03, 0x01 };
    char oid_sysDescr[] =
	{ 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00 };
    char oid_sysUptime[] =
	{ 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00 };
    char oid_ip[] =
	{ 0x2b, 0x06, 0x01, 0x02, 0x01, 0x04, 0x14, 0x01, 0x01 };
    char *types[3] =
	{ _("FHSS 2.4 GHz"), _("DSSS 2.4 GHz"), _("IR Baseband") };
    char *temp[3] = { _("Commercial range 0..40 C"),
	_("Industrial range -30..70 C"),
	_("unknown")
    }, *diversity[3] = {
    _("manual"), _("notsupported"), _("dynamic")};

    char message[300];
    int i, hand, c, min, sec;
    struct in_addr ip;
    varbind varbinds[OID_NUM];
    size_t time_stamp;
    extern int wait_mode;

    print_top(wait_mode == WAIT_TIMEOUT ? POLL_ON : POLL_OFF, SYSINFO);

    if (wait_mode == WAIT_TIMEOUT)
	print_help(QT_HELP);

    while (1) {
	for (i = 0; i < OID_NUM; i++) {
	    varbinds[i].value = oid_mac;
	    varbinds[i].type = NULL_VALUE;
	    varbinds[i].len_val = 0;
	}
	varbinds[0].oid = oid_mac;
	varbinds[0].len_oid = sizeof(oid_mac);
	varbinds[1].oid = oid_manufacturerID;
	varbinds[1].len_oid = sizeof(oid_manufacturerID);
	varbinds[2].oid = oid_productID;
	varbinds[2].len_oid = sizeof(oid_productID);
	varbinds[3].oid = oid_dot11manufacturerOUI;
	varbinds[3].len_oid = sizeof(oid_dot11manufacturerOUI);
	varbinds[4].oid = oid_dot11manufacturerName;
	varbinds[4].len_oid = sizeof(oid_dot11manufacturerName);
	varbinds[5].oid = oid_dot11manufacturerProductName;
	varbinds[5].len_oid = sizeof(oid_dot11manufacturerProductName);
	varbinds[6].oid = oid_dot11manufacturerProductVersion;
	varbinds[6].len_oid = sizeof(oid_dot11manufacturerProductVersion);
	varbinds[7].oid = oid_dot11PHYType;
	varbinds[7].len_oid = sizeof(oid_dot11PHYType);
	varbinds[8].oid = oid_dot11TempType;
	varbinds[8].len_oid = sizeof(oid_dot11TempType);
	varbinds[9].oid = oid_TxPowerLevel1;
	varbinds[9].len_oid = sizeof(oid_TxPowerLevel1);

	if (wait_mode == WAIT_FOREVER)
	    print_help(WAIT_RET);

	if (snmp(varbinds, OID_NUM - 1, GET) < OID_NUM - 1) {
	    print_helperr(ERR_RET);
	    getch();
	    goto quit;
	}

	sprintf(message, "%s%02X%02X%02X%02X%02X%02X", MAC,
	    varbinds[0].value[0] & 0xFF, varbinds[0].value[1] & 0xFF,
	    varbinds[0].value[2] & 0xFF, varbinds[0].value[3] & 0xFF,
	    varbinds[0].value[4] & 0xFF, varbinds[0].value[5] & 0xFF);
	mvwaddstr(main_sub, 0, 0, message);

	mvwaddstr(main_sub, 3, 0, _("Manufacturer:"));
	i = 0;
	while (varbinds[4].len_val > i)
	    mvwaddch(main_sub, 3, i + 20, *(varbinds[4].value + i++));

	mvwaddstr(main_sub, 4, 0, _("Manufacturer ID:"));
	i = 0;
	while (varbinds[1].len_val > i)
	    mvwaddch(main_sub, 4, i + 20, *(varbinds[1].value + i++));

	sprintf(message, _("Manufacturer OUI: %02X %02X %02X (%s)"),
	    varbinds[3].value[0] & 0xFF, varbinds[3].value[1] & 0xFF,
	    varbinds[3].value[2] & 0xFF,
	    oui2manufacturer(varbinds[3].value));
	mvwaddstr(main_sub, 5, 0, message);

	sprintf(message, _("Product Name:"));
	mvwaddstr(main_sub, 6, 0, message);
	i = 0;
	while (varbinds[5].len_val > i)
	    mvwaddch(main_sub, 6, i + 20, *(varbinds[5].value + i++));

	sprintf(message, _("Product ID:"));
	mvwaddstr(main_sub, 7, 0, message);
	i = 0;
	while (varbinds[2].len_val > i)
	    mvwaddch(main_sub, 7, i + 20, *(varbinds[2].value + i++));

	sprintf(message, _("Product Version:"));
	mvwaddstr(main_sub, 8, 0, message);
	i = 0;
	while (varbinds[6].len_val > i)
	    mvwaddch(main_sub, 8, i + 20, *(varbinds[6].value + i++));

	sprintf(message, _("PHYType: %s"), types[*(varbinds[7].value) - 1]);
	mvwaddstr(main_sub, 9, 0, message);

	sprintf(message, _("Temperature: %s"), temp[*(varbinds[8].value) - 1]);
	mvwaddstr(main_sub, 10, 0, message);

	if ((i = get_RegDomain()) == 0) {
	    print_helperr(ERR_RET);
	    getch();
	    goto quit;
	}
	sprintf(message, _("Regulatory Domain: %s"),
	    (i == 0x10) ? _("FCC (USA)") :
	    (i == 0x20) ? _("DOC (Canada)") :
	    (i == 0x30) ? _("ETSI (Europe)") :
	    (i == 0x31) ? _("Spain") :
	    (i == 0x32) ? _("France") :
	    (i == 0x40) ? _("MKK (Japan)") : _("unknown"));
	mvwaddstr(main_sub, 11, 0, message);

	sprintf(message, _("Transmit Power: %u mW"), *(varbinds[9].value));
	mvwaddstr(main_sub, 12, 0, message);

	varbinds[0].oid = oid_dot11PrivacyOptionImplemented;
	varbinds[0].len_oid = sizeof(oid_dot11PrivacyOptionImplemented);
	varbinds[0].value = oid_mac;
	varbinds[0].type = NULL_VALUE;
	varbinds[0].len_val = 0;
	varbinds[1].oid = oid_dot11DiversitySupport;
	varbinds[1].len_oid = sizeof(oid_dot11DiversitySupport);
	varbinds[1].value = oid_mac;
	varbinds[1].type = NULL_VALUE;
	varbinds[1].len_val = 0;
	varbinds[2].oid = oid_sysDescr;
	varbinds[2].len_oid = sizeof(oid_sysDescr);
	varbinds[2].value = oid_mac;
	varbinds[2].type = NULL_VALUE;
	varbinds[2].len_val = 0;
	varbinds[3].oid = oid_sysUptime;
	varbinds[3].len_oid = sizeof(oid_sysUptime);
	varbinds[3].value = oid_mac;
	varbinds[3].type = NULL_VALUE;
	varbinds[3].len_val = 0;

	if (snmp(varbinds, 4, GET) < 4) {
	    print_helperr(ERR_RET);
	    getch();
	    goto quit;
	}

	sprintf(message, _("WEP implemented: %s"),
	    (*(varbinds[0].value) == 1) ? ON : OFF);
	mvwaddstr(main_sub, 13, 0, message);
	sprintf(message, _("Diversity: %s"),
	    diversity[*(varbinds[1].value) - 1]);
	mvwaddstr(main_sub, 14, 0, message);
	mvwaddstr(main_sub, LINES - 8, 0, SYS_DESCR);
	i = 0;
	while (varbinds[2].len_val > i && varbinds[2].value[i]) {
	    message[i] = varbinds[2].value[i];
	    i++;
	}
	message[i] = '\0';
	mvwaddstr(main_sub, LINES - 8, strlen(SYS_DESCR) + 1, message);

	time_stamp = 0;
	i = 1;

	for (c = 1; c <= varbinds[3].len_val; c++) {
	    time_stamp +=
		(unsigned char) varbinds[3].value[varbinds[3].len_val - c] * i;
	    i *= 256;
	}

	hand = time_stamp % 100;
	time_stamp = time_stamp / 100;
	sec = time_stamp % 60;
	time_stamp = time_stamp / 60;
	min = time_stamp % 60;
	time_stamp = time_stamp / 60;

	sprintf(message, _("Uptime: %u:%02u:%02u.%02u"), time_stamp, min, sec,
	    hand);
	mvwaddstr(main_sub, 15, 0, message);

	varbinds[0].oid = oid_ip;
	varbinds[0].len_oid = sizeof(oid_ip);
	varbinds[0].value = oid_mac;
	varbinds[0].type = NULL_VALUE;
	varbinds[0].len_val = 0;

	if (snmp(varbinds, 1, GET_NEXT) <= 0) {
	    print_helperr(ERR_RET);
	    getch();
	    goto quit;
	}

	if (wait_mode == WAIT_FOREVER)
	    print_help(QT_HELP);

	memcpy(&ip.s_addr, varbinds[0].value, 4);
	sprintf(message, _("IP  Address: %s"), inet_ntoa(ip));
	mvwaddstr(main_sub, 1, 0, message);
	wrefresh(main_sub);

	i = wait_key(poll_delay);
	if (i == -1)
	    goto quit;

	switch((char) i) {
	    case 'q':
	    case 'Q':
		goto quit;
	    case 't':
	    case 'T':
		wait_mode = (wait_mode == WAIT_FOREVER ?
		    WAIT_TIMEOUT : WAIT_FOREVER);
		print_top(wait_mode == WAIT_TIMEOUT ? POLL_ON : POLL_OFF,
		    SYSINFO);
	}

	/* either timeout for user input (i == 0) or invalid key => continue */
    }
  quit:
    print_top(NULL, NULL);
    clear_main(0);
}

