/*
 * HP-UX Network Interface Statistics Example
 * 
 * This example demonstrates how to obtain network interface statistics
 * (bytes in/out) for a specified interface on HP-UX using the same
 * approach as net-snmp.
 * 
 * Based on the net-snmp implementation in:
 * - agent/mibgroup/mibII/interfaces.c
 * - HP-UX uses nmapi_phystat structure and get_physical_stat() function
 * 
 * Compile with: cc -o hpux_interface_stats hpux_interface_stats_example.c -lnm
 * 
 * Usage: ./hpux_interface_stats <interface_name>
 * Example: ./hpux_interface_stats lan0
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mib.h>
#include <netinet/mib_kern.h>

/* Maximum physical address length */
#define MAX_PHYSADDR_LEN 20

/* Function prototypes */
int get_interface_stats(const char *interface_name, 
                       unsigned long *bytes_in, 
                       unsigned long *bytes_out);
int get_interface_count(void);
int scan_interfaces(void);

/* Global variables for interface scanning */
static nmapi_phystat *if_list = NULL;
static int if_count = 0;
static int current_index = 0;

/*
 * Get the number of network interfaces
 */
int get_interface_count(void)
{
    int fd;
    struct nmparms p;
    int val;
    unsigned int ulen;
    int ret;

    if (if_count > 0)
        return if_count;

    if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
        p.objid = ID_ifNumber;
        p.buffer = (void *) &val;
        ulen = sizeof(int);
        p.len = &ulen;
        if ((ret = get_mib_info(fd, &p)) == 0)
            if_count = val;
        close_mib(fd);
    }
    
    return if_count;
}

/*
 * Scan all network interfaces and populate the interface list
 */
int scan_interfaces(void)
{
    int count = get_interface_count();
    unsigned int ulen;
    int ret;

    if (count <= 0)
        return -1;

    if (if_list == NULL) {
        if_list = (nmapi_phystat *) malloc(sizeof(nmapi_phystat) * count);
        if (if_list == NULL) {
            fprintf(stderr, "Error: Failed to allocate memory for interface list\n");
            return -1;
        }
    }

    ulen = (unsigned int) count * sizeof(nmapi_phystat);
    if ((ret = get_physical_stat(if_list, &ulen)) < 0) {
        fprintf(stderr, "Error: get_physical_stat failed with return code %d\n", ret);
        return -1;
    }

    return 0;
}

/*
 * Get interface statistics for a specified interface by name
 */
int get_interface_stats(const char *interface_name, 
                       unsigned long *bytes_in, 
                       unsigned long *bytes_out)
{
    int i;
    int count;

    if (interface_name == NULL || bytes_in == NULL || bytes_out == NULL) {
        fprintf(stderr, "Error: Invalid parameters\n");
        return -1;
    }

    /* Initialize interface list if not already done */
    if (if_list == NULL) {
        if (scan_interfaces() < 0) {
            return -1;
        }
    }

    count = get_interface_count();
    if (count <= 0) {
        fprintf(stderr, "Error: No interfaces found\n");
        return -1;
    }

    /* Search for the specified interface */
    for (i = 0; i < count; i++) {
        if (strcmp(if_list[i].nm_device, interface_name) == 0) {
            /* Found the interface, extract statistics */
            *bytes_in = if_list[i].if_entry.ifInOctets;
            *bytes_out = if_list[i].if_entry.ifOutOctets;
            
            printf("Interface: %s\n", if_list[i].nm_device);
            printf("Bytes In:  %lu\n", *bytes_in);
            printf("Bytes Out: %lu\n", *bytes_out);
            printf("Packets In:  %lu\n", if_list[i].if_entry.ifInUcastPkts);
            printf("Packets Out: %lu\n", if_list[i].if_entry.ifOutUcastPkts);
            printf("Errors In:   %lu\n", if_list[i].if_entry.ifInErrors);
            printf("Errors Out:  %lu\n", if_list[i].if_entry.ifOutErrors);
            printf("MTU:         %lu\n", if_list[i].if_entry.ifMtu);
            printf("Speed:       %lu\n", if_list[i].if_entry.ifSpeed);
            printf("Admin Status: %s\n", (if_list[i].if_entry.ifAdmin == 1) ? "UP" : "DOWN");
            printf("Oper Status:  %s\n", (if_list[i].if_entry.ifOper == 1) ? "UP" : "DOWN");
            
            return 0;
        }
    }

    fprintf(stderr, "Error: Interface '%s' not found\n", interface_name);
    return -1;
}

/*
 * List all available network interfaces
 */
void list_interfaces(void)
{
    int i;
    int count;

    if (if_list == NULL) {
        if (scan_interfaces() < 0) {
            return;
        }
    }

    count = get_interface_count();
    if (count <= 0) {
        printf("No interfaces found\n");
        return;
    }

    printf("Available network interfaces:\n");
    printf("Index  Interface Name\n");
    printf("-----  --------------\n");
    
    for (i = 0; i < count; i++) {
        printf("%-5d  %s\n", i + 1, if_list[i].nm_device);
    }
}

/*
 * Main function
 */
int main(int argc, char *argv[])
{
    unsigned long bytes_in, bytes_out;
    int ret;

    if (argc < 2) {
        printf("Usage: %s <interface_name> [list]\n", argv[0]);
        printf("       %s list\n", argv[0]);
        printf("\nExamples:\n");
        printf("  %s lan0          # Get stats for lan0 interface\n", argv[0]);
        printf("  %s list          # List all available interfaces\n", argv[0]);
        return 1;
    }

    if (strcmp(argv[1], "list") == 0) {
        list_interfaces();
        return 0;
    }

    printf("Getting network interface statistics for: %s\n", argv[1]);
    printf("==========================================\n");

    ret = get_interface_stats(argv[1], &bytes_in, &bytes_out);
    
    if (ret == 0) {
        printf("\nSuccessfully retrieved interface statistics.\n");
    } else {
        printf("\nFailed to retrieve interface statistics.\n");
        printf("Use '%s list' to see available interfaces.\n", argv[0]);
        return 1;
    }

    /* Clean up */
    if (if_list != NULL) {
        free(if_list);
        if_list = NULL;
    }

    return 0;
}