/* $Id: netbsd.c,v 1.5 2003/02/23 17:26:02 hscholz Exp $ */

/*****************************************************************************
 *
 * checkinterface()
 *
 * check if a given interface exists, return TRUE if it does and FALSE if not
 *
 ****************************************************************************/
int checkinterface()
{
    int validinterface = FALSE;
    static int mib_name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
    static char *buf;
    static int alloc;
    char *lim, *next;
    struct if_msghdr *ifm, *nextifm;
    struct sockaddr_dl *sdl;
    size_t needed;
    char s[32];

    if (sysctl(mib_name, 6, NULL, &needed, NULL, 0) < 0)
        return FALSE;
    if (alloc < (signed long) needed) {
        if (buf != NULL)
            free(buf);
        buf = malloc(needed);
        if (buf == NULL)
            return FALSE;
        alloc = needed;
    }

    if (sysctl(mib_name, 6, buf, &needed, NULL, 0) < 0)
        return FALSE;
    lim = buf + needed;
    next = buf;
    while ((next < lim) && (validinterface == 0)) {
        ifm = (struct if_msghdr *) next;
        if (ifm->ifm_type != RTM_IFINFO)
            return FALSE;
        next += ifm->ifm_msglen;

        while (next < lim) {
            nextifm = (struct if_msghdr *) next;
            if (nextifm->ifm_type != RTM_NEWADDR)
                break;
            next += nextifm->ifm_msglen;
        }

        if (ifm->ifm_flags & IFF_UP) {
            sdl = (struct sockaddr_dl *) (ifm + 1);
            strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
            s[sdl->sdl_nlen] = '\0';
            /* search for the right network interface */
            if (sdl->sdl_family != AF_LINK)
                continue;
            if (strcmp(s, ifdata.if_name) != 0)
                continue;
            else {
                validinterface = TRUE;
                break;          /* stop searching */
            }
        }
    }
    return validinterface;
}

/******************************************************************************
 *
 * get_stat()
 *
 * this code is based on gkrellm code (thanks guys!)
 *
 ****************************************************************************/

int get_stat(void)
{
    static int mib_name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
    static char *buf;
    static int alloc;
    char *lim, *next;
    struct if_msghdr *ifm, *nextifm;
    struct sockaddr_dl *sdl;
    char s[32];
    size_t needed;
    unsigned long rx_o, tx_o;

    if (sysctl(mib_name, 6, NULL, &needed, NULL, 0) < 0)
        return 1;
    if (alloc < (signed long) needed) {
        if (buf != NULL)
            free(buf);
        buf = malloc(needed);
        if (buf == NULL)
            return 1;
        alloc = needed;
    }

    if (sysctl(mib_name, 6, buf, &needed, NULL, 0) < 0)
        return 1;
    lim = buf + needed;
    next = buf;
    while (next < lim) {
        ifm = (struct if_msghdr *) next;
        if (ifm->ifm_type != RTM_IFINFO)
            return 1;
        next += ifm->ifm_msglen;

        while (next < lim) {
            nextifm = (struct if_msghdr *) next;
            if (nextifm->ifm_type != RTM_NEWADDR)
                break;
            next += nextifm->ifm_msglen;
        }

        if (ifm->ifm_flags & IFF_UP) {
            sdl = (struct sockaddr_dl *) (ifm + 1);
            strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
            s[sdl->sdl_nlen] = '\0';

            /* search for the right network interface */
            if (strcmp(s, ifdata.if_name) != 0)
                continue;

            rx_o = stats.rx_bytes;
            tx_o = stats.tx_bytes;
            /* write stats */
            stats.tx_packets = ifm->ifm_data.ifi_opackets;
            stats.rx_packets = ifm->ifm_data.ifi_ipackets;
            stats.rx_bytes = ifm->ifm_data.ifi_ibytes;
            stats.tx_bytes = ifm->ifm_data.ifi_obytes;
            stats.rx_errors = ifm->ifm_data.ifi_ierrors;
            stats.tx_errors = ifm->ifm_data.ifi_oerrors;

            if (rx_o > stats.rx_bytes)
                stats.rx_over++;
            if (tx_o > stats.tx_bytes)
                stats.tx_over++;
        }
    }
    return 0;
}
