/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
 */

#include <netinet/in.h>
#include <arpa/inet.h>

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>

#include "triton.h"
#include "ppp.h"
#include "ipdb.h"

#include "terminate.h"

static void __terminate(struct ap_session *ses)
{
	ap_session_terminate(ses, TERM_ADMIN_RESET, 0);
}

static void terminate_by_sid(const char *val)
{
	struct ap_session *ses;

	pthread_rwlock_rdlock(&ses_lock);
	list_for_each_entry(ses, &ses_list, entry) {
		if (strncmp(ses->sessionid, val, AP_SESSIONID_LEN))
			continue;
		triton_context_call(ses->ctrl->ctx, (triton_event_func)__terminate, ses);
		break;
	}
	pthread_rwlock_unlock(&ses_lock);
}

static void terminate_by_ifname(const char *val, size_t len)
{
	struct ap_session *ses;
	size_t n;

	pthread_rwlock_rdlock(&ses_lock);
	list_for_each_entry(ses, &ses_list, entry) {
		n = strlen(ses->ifname);
		if (n != len)
			continue;
		if (strncmp(ses->ifname, val, len))
			continue;
		triton_context_call(ses->ctrl->ctx, (triton_event_func)__terminate, ses);
		break;
	}
	pthread_rwlock_unlock(&ses_lock);
}

static void terminate_by_ip(const char *val, size_t len)
{
	char str[len + 1];
	in_addr_t addr;
	struct ap_session *ses;

	strncpy(str, val, len);
	str[len] = 0;

	addr = inet_addr(str);

	pthread_rwlock_rdlock(&ses_lock);
	list_for_each_entry(ses, &ses_list, entry) {
		if (!ses->ipv4 || ses->ipv4->peer_addr != addr)
			continue;
		triton_context_call(ses->ctrl->ctx, (triton_event_func)__terminate, ses);
		break;
	}
	pthread_rwlock_unlock(&ses_lock);
}

static void terminate_by_username(const char *val, size_t len)
{
	struct ap_session *ses;
	size_t n;

	pthread_rwlock_rdlock(&ses_lock);
	list_for_each_entry(ses, &ses_list, entry) {
		if (!ses->username)
			continue;
		n = strlen(ses->username);
		if (n != len)
			continue;
		if (strncmp(ses->username, val, len))
			continue;
		triton_context_call(ses->ctrl->ctx, (triton_event_func)__terminate, ses);
	}
	pthread_rwlock_unlock(&ses_lock);
}


/** Initializes the terminate module */
void
init_terminate(void)
{
    static oid termBySID_oid[] = { 1,3,6,1,4,1,8072,100,3,1,1 };
    static oid termByIfName_oid[] = { 1,3,6,1,4,1,8072,100,3,1,2 };
    static oid termByIP_oid[] = { 1,3,6,1,4,1,8072,100,3,1,3 };
    static oid termByUsername_oid[] = { 1,3,6,1,4,1,8072,100,3,1,4 };

  DEBUGMSGTL(("terminate", "Initializing\n"));

    netsnmp_register_scalar(
        netsnmp_create_handler_registration("termBySID", handle_termBySID,
                               termBySID_oid, OID_LENGTH(termBySID_oid),
                               HANDLER_CAN_RWRITE
        ));
    netsnmp_register_scalar(
        netsnmp_create_handler_registration("termByIfName", handle_termByIfName,
                               termByIfName_oid, OID_LENGTH(termByIfName_oid),
                               HANDLER_CAN_RWRITE
        ));
    netsnmp_register_scalar(
        netsnmp_create_handler_registration("termByIP", handle_termByIP,
                               termByIP_oid, OID_LENGTH(termByIP_oid),
                               HANDLER_CAN_RWRITE
        ));
    netsnmp_register_scalar(
        netsnmp_create_handler_registration("termByUsername", handle_termByUsername,
                               termByUsername_oid, OID_LENGTH(termByUsername_oid),
                               HANDLER_CAN_RWRITE
        ));
}

int
handle_termBySID(netsnmp_mib_handler *handler,
                          netsnmp_handler_registration *reginfo,
                          netsnmp_agent_request_info   *reqinfo,
                          netsnmp_request_info         *requests)
{
    int ret;
    /* We are never called for a GETNEXT if it's registered as a
       "instance", as it's "magically" handled for us.  */

    /* a instance handler also only hands us one request at a time, so
       we don't need to loop over a list of requests; we'll only get one. */

    switch(reqinfo->mode) {

        case MODE_GET:
            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
            break;

        /*
         * SET REQUEST
         *
         * multiple states in the transaction.  See:
         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
         */
        case MODE_SET_RESERVE1:
                /* or you could use netsnmp_check_vb_type_and_size instead */
            ret = netsnmp_check_vb_type_and_size(requests->requestvb, ASN_OCTET_STR, AP_SESSIONID_LEN);
            if ( ret != SNMP_ERR_NOERROR ) {
                netsnmp_set_request_error(reqinfo, requests, ret );
            }
            break;

        case MODE_SET_RESERVE2:
            break;

        case MODE_SET_FREE:
            /* XXX: free resources allocated in RESERVE1 and/or
               RESERVE2.  Something failed somewhere, and the states
               below won't be called. */
            break;

        case MODE_SET_ACTION:
						terminate_by_sid((char *)requests->requestvb->val.string);
            /* XXX: perform the value change here */
            break;

        case MODE_SET_COMMIT:
            break;

        case MODE_SET_UNDO:
            break;

        default:
            /* we should never get here, so this is a really bad error */
            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termBySID\n", reqinfo->mode );
            return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}
int
handle_termByIfName(netsnmp_mib_handler *handler,
                          netsnmp_handler_registration *reginfo,
                          netsnmp_agent_request_info   *reqinfo,
                          netsnmp_request_info         *requests)
{
    int ret;
    /* We are never called for a GETNEXT if it's registered as a
       "instance", as it's "magically" handled for us.  */

    /* a instance handler also only hands us one request at a time, so
       we don't need to loop over a list of requests; we'll only get one. */

    switch(reqinfo->mode) {

        case MODE_GET:
            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
            break;

        /*
         * SET REQUEST
         *
         * multiple states in the transaction.  See:
         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
         */
        case MODE_SET_RESERVE1:
                /* or you could use netsnmp_check_vb_type_and_size instead */
            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
            if ( ret != SNMP_ERR_NOERROR ) {
                netsnmp_set_request_error(reqinfo, requests, ret );
            }
            break;

        case MODE_SET_RESERVE2:
            /* XXX malloc "undo" storage buffer */
            break;

        case MODE_SET_FREE:
            /* XXX: free resources allocated in RESERVE1 and/or
               RESERVE2.  Something failed somewhere, and the states
               below won't be called. */
            break;

        case MODE_SET_ACTION:
						terminate_by_ifname((char *)requests->requestvb->val.string, requests->requestvb->val_len);
            /* XXX: perform the value change here */
            break;

        case MODE_SET_COMMIT:
            break;

        case MODE_SET_UNDO:
            break;

        default:
            /* we should never get here, so this is a really bad error */
            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termByIfName\n", reqinfo->mode );
            return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}
int
handle_termByIP(netsnmp_mib_handler *handler,
                          netsnmp_handler_registration *reginfo,
                          netsnmp_agent_request_info   *reqinfo,
                          netsnmp_request_info         *requests)
{
    int ret;
    /* We are never called for a GETNEXT if it's registered as a
       "instance", as it's "magically" handled for us.  */

    /* a instance handler also only hands us one request at a time, so
       we don't need to loop over a list of requests; we'll only get one. */

    switch(reqinfo->mode) {

        case MODE_GET:
            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
            break;

        /*
         * SET REQUEST
         *
         * multiple states in the transaction.  See:
         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
         */
        case MODE_SET_RESERVE1:
                /* or you could use netsnmp_check_vb_type_and_size instead */
            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
            if ( ret != SNMP_ERR_NOERROR ) {
                netsnmp_set_request_error(reqinfo, requests, ret );
            }
            break;

        case MODE_SET_RESERVE2:
            /* XXX malloc "undo" storage buffer */
            break;

        case MODE_SET_FREE:
            /* XXX: free resources allocated in RESERVE1 and/or
               RESERVE2.  Something failed somewhere, and the states
               below won't be called. */
            break;

        case MODE_SET_ACTION:
						terminate_by_ip((char *)requests->requestvb->val.string, requests->requestvb->val_len);
            /* XXX: perform the value change here */
            break;

        case MODE_SET_COMMIT:
            /* XXX: delete temporary storage */
            break;

        case MODE_SET_UNDO:
            /* XXX: UNDO and return to previous value for the object */
            break;

        default:
            /* we should never get here, so this is a really bad error */
            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termByIP\n", reqinfo->mode );
            return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}
int
handle_termByUsername(netsnmp_mib_handler *handler,
                          netsnmp_handler_registration *reginfo,
                          netsnmp_agent_request_info   *reqinfo,
                          netsnmp_request_info         *requests)
{
    int ret;
    /* We are never called for a GETNEXT if it's registered as a
       "instance", as it's "magically" handled for us.  */

    /* a instance handler also only hands us one request at a time, so
       we don't need to loop over a list of requests; we'll only get one. */

    switch(reqinfo->mode) {

        case MODE_GET:
            netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE );
            break;

        /*
         * SET REQUEST
         *
         * multiple states in the transaction.  See:
         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
         */
        case MODE_SET_RESERVE1:
                /* or you could use netsnmp_check_vb_type_and_size instead */
            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
            if ( ret != SNMP_ERR_NOERROR ) {
                netsnmp_set_request_error(reqinfo, requests, ret );
            }
            break;

        case MODE_SET_RESERVE2:
            /* XXX malloc "undo" storage buffer */
            break;

        case MODE_SET_FREE:
            /* XXX: free resources allocated in RESERVE1 and/or
               RESERVE2.  Something failed somewhere, and the states
               below won't be called. */
            break;

        case MODE_SET_ACTION:
						terminate_by_username((char *)requests->requestvb->val.string, requests->requestvb->val_len);
            /* XXX: perform the value change here */
            break;

        case MODE_SET_COMMIT:
            /* XXX: delete temporary storage */
            break;

        case MODE_SET_UNDO:
            /* XXX: UNDO and return to previous value for the object */
            break;

        default:
            /* we should never get here, so this is a really bad error */
            snmp_log(LOG_ERR, "unknown mode (%d) in handle_termByUsername\n", reqinfo->mode );
            return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}
