Blame agent/agent_registry.c

Packit fcad23
/*
Packit fcad23
 * agent_registry.c
Packit fcad23
 */
Packit fcad23
/* Portions of this file are subject to the following copyright(s).  See
Packit fcad23
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit fcad23
 * that may apply:
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 *
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 */
Packit fcad23
/** @defgroup agent_registry Registry of MIB subtrees, modules, sessions, etc
Packit fcad23
 *     Maintain a registry of MIB subtrees, together with related information
Packit fcad23
 *     regarding MIB modules, sessions, etc
Packit fcad23
 *   @ingroup agent
Packit fcad23
 *
Packit fcad23
 * @{
Packit fcad23
 */
Packit fcad23
Packit fcad23
#define IN_SNMP_VARS_C
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
Packit fcad23
#include <signal.h>
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#include <string.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_STDLIB_H
Packit fcad23
#include <stdlib.h>
Packit fcad23
#endif
Packit fcad23
#include <sys/types.h>
Packit fcad23
#include <stdio.h>
Packit fcad23
#include <fcntl.h>
Packit fcad23
#if TIME_WITH_SYS_TIME
Packit fcad23
# include <sys/time.h>
Packit fcad23
# include <time.h>
Packit fcad23
#else
Packit fcad23
# if HAVE_SYS_TIME_H
Packit fcad23
#  include <sys/time.h>
Packit fcad23
# else
Packit fcad23
#  include <time.h>
Packit fcad23
# endif
Packit fcad23
#endif
Packit fcad23
#if HAVE_NETINET_IN_H
Packit fcad23
#include <netinet/in.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-includes.h>
Packit fcad23
#include <net-snmp/library/snmp_assert.h>
Packit fcad23
#include <net-snmp/agent/net-snmp-agent-includes.h>
Packit fcad23
#include <net-snmp/agent/agent_callbacks.h>
Packit fcad23
Packit fcad23
#include "snmpd.h"
Packit fcad23
#include "agent_global_vars.h"
Packit fcad23
#include "mibgroup/struct.h"
Packit fcad23
#include <net-snmp/agent/old_api.h>
Packit fcad23
#include <net-snmp/agent/null.h>
Packit fcad23
#include <net-snmp/agent/table.h>
Packit fcad23
#include <net-snmp/agent/table_iterator.h>
Packit fcad23
#include <net-snmp/agent/agent_index.h>
Packit fcad23
#include <net-snmp/agent/agent_registry.h>
Packit fcad23
Packit fcad23
#ifdef USING_AGENTX_SUBAGENT_MODULE
Packit fcad23
#include "agentx/subagent.h"
Packit fcad23
#include "agentx/client.h"
Packit fcad23
#endif
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(agent_registry_all, libnetsnmpagent)
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(unregister_mib_table_row, agent_registry_all)
Packit fcad23
Packit fcad23
/** @defgroup agent_lookup_cache Lookup cache, storing the registered OIDs.
Packit fcad23
 *     Maintain the cache used for locating sub-trees and OIDs.
Packit fcad23
 *   @ingroup agent_registry
Packit fcad23
 *
Packit fcad23
 * @{
Packit fcad23
 */
Packit fcad23
Packit fcad23
/**  Lookup cache - default size.*/
Packit fcad23
#define SUBTREE_DEFAULT_CACHE_SIZE 8
Packit fcad23
/**  Lookup cache - max acceptable size.*/
Packit fcad23
#define SUBTREE_MAX_CACHE_SIZE     32
Packit fcad23
int lookup_cache_size = 0; /*enabled later after registrations are loaded */
Packit fcad23
Packit fcad23
typedef struct lookup_cache_s {
Packit fcad23
   netsnmp_subtree *next;
Packit fcad23
   netsnmp_subtree *previous;
Packit fcad23
} lookup_cache;
Packit fcad23
Packit fcad23
typedef struct lookup_cache_context_s {
Packit fcad23
   char *context;
Packit fcad23
   struct lookup_cache_context_s *next;
Packit fcad23
   int thecachecount;
Packit fcad23
   int currentpos;
Packit fcad23
   lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
Packit fcad23
} lookup_cache_context;
Packit fcad23
Packit fcad23
static lookup_cache_context *thecontextcache = NULL;
Packit fcad23
Packit fcad23
/** Set the lookup cache size for optimized agent registration performance.
Packit fcad23
 * Note that it is only used by master agent - sub-agent doesn't need the cache.
Packit fcad23
 * The rough guide is that the cache size should be equal to the maximum
Packit fcad23
 * number of simultaneous managers you expect to talk to the agent (M) times 80%
Packit fcad23
 * (or so, he says randomly) the average number (N) of varbinds you
Packit fcad23
 * expect to receive in a given request for a manager.  ie, M times N.
Packit fcad23
 * Bigger does NOT necessarily mean better.  Certainly 16 should be an
Packit fcad23
 * upper limit.  32 is the hard coded limit.
Packit fcad23
 *
Packit fcad23
 * @param newsize set to the maximum size of a cache for a given
Packit fcad23
 * context.  Set to 0 to completely disable caching, or to -1 to set
Packit fcad23
 * to the default cache size (8), or to a number of your chosing.  The
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
netsnmp_set_lookup_cache_size(int newsize) {
Packit fcad23
    if (newsize < 0)
Packit fcad23
        lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
Packit fcad23
    else if (newsize < SUBTREE_MAX_CACHE_SIZE)
Packit fcad23
        lookup_cache_size = newsize;
Packit fcad23
    else
Packit fcad23
        lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Retrieves the current value of the lookup cache size
Packit fcad23
 *  Should be called from master agent only - sub-agent doesn't need the cache.
Packit fcad23
 *
Packit fcad23
 *  @return the current lookup cache size
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_get_lookup_cache_size(void) {
Packit fcad23
    return lookup_cache_size;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Returns lookup cache entry for the context of given name.
Packit fcad23
 *
Packit fcad23
 *  @param context Name of the context. Name is case sensitive.
Packit fcad23
 *
Packit fcad23
 *  @return the lookup cache context
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE lookup_cache_context *
Packit fcad23
get_context_lookup_cache(const char *context) {
Packit fcad23
    lookup_cache_context *ptr;
Packit fcad23
    if (!context)
Packit fcad23
        context = "";
Packit fcad23
Packit fcad23
    for(ptr = thecontextcache; ptr; ptr = ptr->next) {
Packit fcad23
        if (strcmp(ptr->context, context) == 0)
Packit fcad23
            break;
Packit fcad23
    }
Packit fcad23
    if (!ptr) {
Packit fcad23
        if (netsnmp_subtree_find_first(context)) {
Packit fcad23
            ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
Packit fcad23
            ptr->next = thecontextcache;
Packit fcad23
            ptr->context = strdup(context);
Packit fcad23
            thecontextcache = ptr;
Packit fcad23
        } else {
Packit fcad23
            return NULL;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    return ptr;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Adds an entry to the Lookup Cache under specified context name.
Packit fcad23
 *
Packit fcad23
 *  @param context  Name of the context. Name is case sensitive.
Packit fcad23
 *
Packit fcad23
 *  @param next     Next subtree item.
Packit fcad23
 *
Packit fcad23
 *  @param previous Previous subtree item.
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
lookup_cache_add(const char *context,
Packit fcad23
                 netsnmp_subtree *next, netsnmp_subtree *previous) {
Packit fcad23
    lookup_cache_context *cptr;
Packit fcad23
Packit fcad23
    if ((cptr = get_context_lookup_cache(context)) == NULL)
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    if (cptr->thecachecount < lookup_cache_size)
Packit fcad23
        cptr->thecachecount++;
Packit fcad23
Packit fcad23
    cptr->cache[cptr->currentpos].next = next;
Packit fcad23
    cptr->cache[cptr->currentpos].previous = previous;
Packit fcad23
Packit fcad23
    if (++cptr->currentpos >= lookup_cache_size)
Packit fcad23
        cptr->currentpos = 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Replaces next and previous pointer in given Lookup Cache.
Packit fcad23
 *
Packit fcad23
 *  @param ptr      Lookup Cache pointer.
Packit fcad23
 *
Packit fcad23
 *  @param next     Next subtree item.
Packit fcad23
 *
Packit fcad23
 *  @param previous Previous subtree item.
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
lookup_cache_replace(lookup_cache *ptr,
Packit fcad23
                     netsnmp_subtree *next, netsnmp_subtree *previous) {
Packit fcad23
Packit fcad23
    ptr->next = next;
Packit fcad23
    ptr->previous = previous;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Finds an entry in the Lookup Cache.
Packit fcad23
 *
Packit fcad23
 *  @param context  Case sensitive name of the context.
Packit fcad23
 *
Packit fcad23
 *  @param name     The OID we're searching for.
Packit fcad23
 *
Packit fcad23
 *  @param name_len Number of sub-ids (single integers) in the OID.
Packit fcad23
 *
Packit fcad23
 *  @param retcmp   Value set to snmp_oid_compare() call result.
Packit fcad23
 *                  The value, if set, is always nonnegative.
Packit fcad23
 *
Packit fcad23
 *  @return gives Lookup Cache entry, or NULL if not found.
Packit fcad23
 *
Packit fcad23
 *  @see snmp_oid_compare()
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE lookup_cache *
Packit fcad23
lookup_cache_find(const char *context, const oid *name, size_t name_len,
Packit fcad23
                  int *retcmp) {
Packit fcad23
    lookup_cache_context *cptr;
Packit fcad23
    lookup_cache *ret = NULL;
Packit fcad23
    int cmp;
Packit fcad23
    int i;
Packit fcad23
Packit fcad23
    if ((cptr = get_context_lookup_cache(context)) == NULL)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
Packit fcad23
        if (cptr->cache[i].previous->start_a)
Packit fcad23
            cmp = snmp_oid_compare(name, name_len,
Packit fcad23
                                   cptr->cache[i].previous->start_a,
Packit fcad23
                                   cptr->cache[i].previous->start_len);
Packit fcad23
        else
Packit fcad23
            cmp = 1;
Packit fcad23
        if (cmp >= 0) {
Packit fcad23
            *retcmp = cmp;
Packit fcad23
            ret = &(cptr->cache[i]);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Clears cache count and position in Lookup Cache.
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
invalidate_lookup_cache(const char *context) {
Packit fcad23
    lookup_cache_context *cptr;
Packit fcad23
    if ((cptr = get_context_lookup_cache(context)) != NULL) {
Packit fcad23
        cptr->thecachecount = 0;
Packit fcad23
        cptr->currentpos = 0;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
clear_lookup_cache(void) {
Packit fcad23
Packit fcad23
    lookup_cache_context *ptr = NULL, *next = NULL;
Packit fcad23
Packit fcad23
    ptr = thecontextcache;
Packit fcad23
    while (ptr) {
Packit fcad23
	next = ptr->next;
Packit fcad23
	SNMP_FREE(ptr->context);
Packit fcad23
	SNMP_FREE(ptr);
Packit fcad23
	ptr = next;
Packit fcad23
    }
Packit fcad23
    thecontextcache = NULL; /* !!! */
Packit fcad23
}
Packit fcad23
Packit fcad23
/**  @} */
Packit fcad23
/* End of Lookup cache code */
Packit fcad23
Packit fcad23
/** @defgroup agent_context_cache Context cache, storing the OIDs under their contexts.
Packit fcad23
 *     Maintain the cache used for locating sub-trees registered under different contexts.
Packit fcad23
 *   @ingroup agent_registry
Packit fcad23
 *
Packit fcad23
 * @{
Packit fcad23
 */
Packit fcad23
subtree_context_cache *context_subtrees = NULL;
Packit fcad23
Packit fcad23
/** Returns the top element of context subtrees cache.
Packit fcad23
 *  Use it if you wish to sweep through the cache elements.
Packit fcad23
 *  Note that the return may be NULL (cache may be empty).
Packit fcad23
 *
Packit fcad23
 *  @return pointer to topmost context subtree cache element.
Packit fcad23
 */
Packit fcad23
subtree_context_cache *
Packit fcad23
get_top_context_cache(void)
Packit fcad23
{
Packit fcad23
    return context_subtrees;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Finds the first subtree registered under given context.
Packit fcad23
 *
Packit fcad23
 *  @param context_name Text name of the context we're searching for.
Packit fcad23
 *
Packit fcad23
 *  @return pointer to the first subtree element, or NULL if not found.
Packit fcad23
 */
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_find_first(const char *context_name)
Packit fcad23
{
Packit fcad23
    subtree_context_cache *ptr;
Packit fcad23
Packit fcad23
    if (!context_name) {
Packit fcad23
        context_name = "";
Packit fcad23
    }
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
Packit fcad23
		context_name));
Packit fcad23
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
Packit fcad23
        if (ptr->context_name != NULL && 
Packit fcad23
	    strcmp(ptr->context_name, context_name) == 0) {
Packit fcad23
            DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
Packit fcad23
            return ptr->first_subtree;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
Packit fcad23
		context_name));
Packit fcad23
    return NULL;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Adds the subtree to Context Cache under given context name.
Packit fcad23
 *
Packit fcad23
 *  @param context_name Text name of the context we're adding.
Packit fcad23
 *
Packit fcad23
 *  @param new_tree The subtree to be added.
Packit fcad23
 *
Packit fcad23
 *  @return copy of the new_tree pointer, or NULL if cannot add.
Packit fcad23
 */
Packit fcad23
netsnmp_subtree *
Packit fcad23
add_subtree(netsnmp_subtree *new_tree, const char *context_name)
Packit fcad23
{
Packit fcad23
    subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
Packit fcad23
    
Packit fcad23
    if (!context_name) {
Packit fcad23
        context_name = "";
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!ptr) {
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",	
Packit fcad23
		context_name));
Packit fcad23
Packit fcad23
    ptr->next = context_subtrees;
Packit fcad23
    ptr->first_subtree = new_tree;
Packit fcad23
    ptr->context_name = strdup(context_name);
Packit fcad23
    context_subtrees = ptr;
Packit fcad23
Packit fcad23
    return ptr->first_subtree;
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
netsnmp_remove_subtree(netsnmp_subtree *tree)
Packit fcad23
{
Packit fcad23
    subtree_context_cache *ptr;
Packit fcad23
Packit fcad23
    if (!tree->prev) {
Packit fcad23
        for (ptr = context_subtrees; ptr; ptr = ptr->next)
Packit fcad23
            if (ptr->first_subtree == tree)
Packit fcad23
                break;
Packit fcad23
        netsnmp_assert(ptr);
Packit fcad23
        if (ptr)
Packit fcad23
            ptr->first_subtree = tree->next;
Packit fcad23
    } else
Packit fcad23
        tree->prev->next = tree->next;
Packit fcad23
Packit fcad23
    if (tree->next)
Packit fcad23
        tree->next->prev = tree->prev;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Replaces first subtree registered under given context name.
Packit fcad23
 *  Overwrites a subtree pointer in Context Cache for the context name.
Packit fcad23
 *  The previous subtree pointer is lost. If there's no subtree
Packit fcad23
 *  under the supplied name, then a new cache item is created.
Packit fcad23
 *
Packit fcad23
 *  @param new_tree     The new subtree to be set.
Packit fcad23
 *
Packit fcad23
 *  @param context_name Text name of the context we're replacing.
Packit fcad23
 *                      It is case sensitive.
Packit fcad23
 *
Packit fcad23
 * @return copy of the new_tree pointer, or NULL on error.
Packit fcad23
 */
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 
Packit fcad23
			      const char *context_name)
Packit fcad23
{
Packit fcad23
    subtree_context_cache *ptr;
Packit fcad23
    if (!context_name) {
Packit fcad23
        context_name = "";
Packit fcad23
    }
Packit fcad23
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
Packit fcad23
        if (ptr->context_name != NULL &&
Packit fcad23
	    strcmp(ptr->context_name, context_name) == 0) {
Packit fcad23
            ptr->first_subtree = new_tree;
Packit fcad23
            return ptr->first_subtree;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    return add_subtree(new_tree, context_name);
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
void clear_subtree (netsnmp_subtree *sub);
Packit fcad23
Packit fcad23
/** Completely clears both the Context cache and the Lookup cache.
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
clear_context(void) {
Packit fcad23
Packit fcad23
    subtree_context_cache *ptr = NULL, *next = NULL;
Packit fcad23
    netsnmp_subtree *t, *u;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("agent_registry", "clear context\n"));
Packit fcad23
Packit fcad23
    ptr = get_top_context_cache(); 
Packit fcad23
    while (ptr) {
Packit fcad23
	next = ptr->next;
Packit fcad23
Packit fcad23
	for (t = ptr->first_subtree; t; t = u) {
Packit fcad23
            u = t->next;
Packit fcad23
	    clear_subtree(t);
Packit fcad23
	}
Packit fcad23
Packit fcad23
        free(NETSNMP_REMOVE_CONST(char*, ptr->context_name));
Packit fcad23
        SNMP_FREE(ptr);
Packit fcad23
Packit fcad23
	ptr = next;
Packit fcad23
    }
Packit fcad23
    context_subtrees = NULL; /* !!! */
Packit fcad23
    clear_lookup_cache();
Packit fcad23
}
Packit fcad23
Packit fcad23
/**  @} */
Packit fcad23
/* End of Context cache code */
Packit fcad23
Packit fcad23
/** @defgroup agent_mib_subtree Maintaining MIB subtrees.
Packit fcad23
 *     Maintaining MIB nodes and subtrees.
Packit fcad23
 *   @ingroup agent_registry
Packit fcad23
 *
Packit fcad23
 * @{
Packit fcad23
 */
Packit fcad23
Packit fcad23
static void register_mib_detach_node(netsnmp_subtree *s);
Packit fcad23
Packit fcad23
/** Frees single subtree item.
Packit fcad23
 *  Deallocated memory for given netsnmp_subtree item, including
Packit fcad23
 *  Handle Registration structure stored inside this item.
Packit fcad23
 *  After calling this function, the pointer is invalid
Packit fcad23
 *  and should be set to NULL.
Packit fcad23
 *
Packit fcad23
 *  @param a The subtree item to dispose.
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
netsnmp_subtree_free(netsnmp_subtree *a)
Packit fcad23
{
Packit fcad23
  if (a != NULL) {
Packit fcad23
    if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 
Packit fcad23
					     a->start_a, a->start_len) == 0) {
Packit fcad23
      SNMP_FREE(a->variables);
Packit fcad23
    }
Packit fcad23
    SNMP_FREE(a->name_a);
Packit fcad23
    a->namelen = 0;
Packit fcad23
    SNMP_FREE(a->start_a);
Packit fcad23
    a->start_len = 0;
Packit fcad23
    SNMP_FREE(a->end_a);
Packit fcad23
    a->end_len = 0;
Packit fcad23
    SNMP_FREE(a->label_a);
Packit fcad23
    netsnmp_handler_registration_free(a->reginfo);
Packit fcad23
    a->reginfo = NULL;
Packit fcad23
    SNMP_FREE(a);
Packit fcad23
  }
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Creates deep copy of a subtree item.
Packit fcad23
 *  Duplicates all properties stored in the structure, including
Packit fcad23
 *  Handle Registration structure stored inside the item.
Packit fcad23
 *
Packit fcad23
 *  @param a The subtree item to copy.
Packit fcad23
 *
Packit fcad23
 *  @return deep copy of the subtree item, or NULL on error.
Packit fcad23
 */
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_deepcopy(netsnmp_subtree *a)
Packit fcad23
{
Packit fcad23
  netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
Packit fcad23
Packit fcad23
  if (b != NULL) {
Packit fcad23
    memcpy(b, a, sizeof(netsnmp_subtree));
Packit fcad23
    b->name_a  = snmp_duplicate_objid(a->name_a,  a->namelen);
Packit fcad23
    b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
Packit fcad23
    b->end_a   = snmp_duplicate_objid(a->end_a,   a->end_len);
Packit fcad23
    b->label_a = strdup(a->label_a);
Packit fcad23
    
Packit fcad23
    if (b->name_a == NULL || b->start_a == NULL || 
Packit fcad23
	b->end_a  == NULL || b->label_a == NULL) {
Packit fcad23
      netsnmp_subtree_free(b);
Packit fcad23
      return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (a->variables != NULL) {
Packit fcad23
      b->variables = (struct variable *)malloc(a->variables_len * 
Packit fcad23
					       a->variables_width);
Packit fcad23
      if (b->variables != NULL) {
Packit fcad23
	memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
Packit fcad23
      } else {
Packit fcad23
	netsnmp_subtree_free(b);
Packit fcad23
	return NULL;
Packit fcad23
      }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (a->reginfo != NULL) {
Packit fcad23
      b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
Packit fcad23
      if (b->reginfo == NULL) {
Packit fcad23
	netsnmp_subtree_free(b);
Packit fcad23
	return NULL;
Packit fcad23
      }
Packit fcad23
    }
Packit fcad23
  }
Packit fcad23
  return b;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Replaces next subtree pointer in given subtree.
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext)
Packit fcad23
{
Packit fcad23
    ptr->next = thenext;
Packit fcad23
    if (thenext)
Packit fcad23
        netsnmp_oid_compare_ll(ptr->start_a,
Packit fcad23
                               ptr->start_len,
Packit fcad23
                               thenext->start_a,
Packit fcad23
                               thenext->start_len,
Packit fcad23
                               &thenext->oid_off);
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Replaces previous subtree pointer in given subtree.
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev)
Packit fcad23
{
Packit fcad23
    ptr->prev = theprev;
Packit fcad23
    if (theprev)
Packit fcad23
        netsnmp_oid_compare_ll(theprev->start_a,
Packit fcad23
                               theprev->start_len,
Packit fcad23
                               ptr->start_a,
Packit fcad23
                               ptr->start_len,
Packit fcad23
                               &ptr->oid_off);
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(netsnmp_subtree_compare,netsnmp_unused)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE
Packit fcad23
/** Compares OIDs of given subtrees.
Packit fcad23
 *
Packit fcad23
 *  @param ap,bp Pointers to the subtrees to be compared.
Packit fcad23
 *
Packit fcad23
 *  @return OIDs lexicographical comparison result.
Packit fcad23
 *
Packit fcad23
 *  @see snmp_oid_compare()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
Packit fcad23
{
Packit fcad23
    return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE */
Packit fcad23
Packit fcad23
/** Joins the given subtree with the current tree.
Packit fcad23
 *  Trees are joined and the one supplied as parameter is freed.
Packit fcad23
 *
Packit fcad23
 *  @param root The subtree to be merged with current subtree.
Packit fcad23
 *              Do not use the pointer after joining - it may be invalid.
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
netsnmp_subtree_join(netsnmp_subtree *root)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *s, *tmp, *c, *d;
Packit fcad23
Packit fcad23
    while (root != NULL) {
Packit fcad23
        s = root->next;
Packit fcad23
        while (s != NULL && root->reginfo == s->reginfo) {
Packit fcad23
            tmp = s->next;
Packit fcad23
            DEBUGMSGTL(("subtree", "root start "));
Packit fcad23
            DEBUGMSGOID(("subtree", root->start_a, root->start_len));
Packit fcad23
            DEBUGMSG(("subtree", " (original end "));
Packit fcad23
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
Packit fcad23
            DEBUGMSG(("subtree", ")\n"));
Packit fcad23
            DEBUGMSGTL(("subtree", "  JOINING to "));
Packit fcad23
            DEBUGMSGOID(("subtree", s->start_a, s->start_len));
Packit fcad23
Packit fcad23
	    SNMP_FREE(root->end_a);
Packit fcad23
	    root->end_a   = s->end_a;
Packit fcad23
            root->end_len = s->end_len;
Packit fcad23
	    s->end_a      = NULL;
Packit fcad23
Packit fcad23
            for (c = root; c != NULL; c = c->children) {
Packit fcad23
                netsnmp_subtree_change_next(c, s->next);
Packit fcad23
            }
Packit fcad23
            for (c = s; c != NULL; c = c->children) {
Packit fcad23
                netsnmp_subtree_change_prev(c, root);
Packit fcad23
            }
Packit fcad23
            DEBUGMSG(("subtree", " so new end "));
Packit fcad23
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
Packit fcad23
            DEBUGMSG(("subtree", "\n"));
Packit fcad23
            /*
Packit fcad23
             * Probably need to free children too?  
Packit fcad23
             */
Packit fcad23
            for (c = s->children; c != NULL; c = d) {
Packit fcad23
                d = c->children;
Packit fcad23
                netsnmp_subtree_free(c);
Packit fcad23
            }
Packit fcad23
            netsnmp_subtree_free(s);
Packit fcad23
            s = tmp;
Packit fcad23
        }
Packit fcad23
        root = root->next;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
/** Split the subtree into two at the specified point.
Packit fcad23
 *  Subtrees of the given OID and separated and formed into the
Packit fcad23
 *  returned subtree.
Packit fcad23
 *
Packit fcad23
 *  @param current The element at which splitting is started.
Packit fcad23
 *
Packit fcad23
 *  @param name The OID we'd like to split.
Packit fcad23
 *
Packit fcad23
 *  @param name_len Length of the OID.
Packit fcad23
 *
Packit fcad23
 *  @return head of the new (second) subtree.
Packit fcad23
 */
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
Packit fcad23
{
Packit fcad23
    struct variable *vp = NULL;
Packit fcad23
    netsnmp_subtree *new_sub, *ptr;
Packit fcad23
    int i = 0, rc = 0, rc2 = 0;
Packit fcad23
    size_t common_len = 0;
Packit fcad23
    char *cp;
Packit fcad23
    oid *tmp_a, *tmp_b;
Packit fcad23
Packit fcad23
    if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
Packit fcad23
	/* Split comes after the end of this subtree */
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    new_sub = netsnmp_subtree_deepcopy(current);
Packit fcad23
    if (new_sub == NULL) {
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*  Set up the point of division.  */
Packit fcad23
    tmp_a = snmp_duplicate_objid(name, name_len);
Packit fcad23
    if (tmp_a == NULL) {
Packit fcad23
	netsnmp_subtree_free(new_sub);
Packit fcad23
	return NULL;
Packit fcad23
    }
Packit fcad23
    tmp_b = snmp_duplicate_objid(name, name_len);
Packit fcad23
    if (tmp_b == NULL) {
Packit fcad23
	netsnmp_subtree_free(new_sub);
Packit fcad23
	SNMP_FREE(tmp_a);
Packit fcad23
	return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    SNMP_FREE(current->end_a);
Packit fcad23
    current->end_a = tmp_a;
Packit fcad23
    current->end_len = name_len;
Packit fcad23
    if (new_sub->start_a != NULL) {
Packit fcad23
	SNMP_FREE(new_sub->start_a);
Packit fcad23
    }
Packit fcad23
    new_sub->start_a = tmp_b;
Packit fcad23
    new_sub->start_len = name_len;
Packit fcad23
Packit fcad23
    /*  Split the variables between the two new subtrees.  */
Packit fcad23
    i = current->variables_len;
Packit fcad23
    current->variables_len = 0;
Packit fcad23
Packit fcad23
    for (vp = current->variables; i > 0; i--) {
Packit fcad23
	/*  Note that the variable "name" field omits the prefix common to the
Packit fcad23
	    whole registration, hence the strange comparison here.  */
Packit fcad23
Packit fcad23
	rc = snmp_oid_compare(vp->name, vp->namelen,
Packit fcad23
			      name     + current->namelen, 
Packit fcad23
			      name_len - current->namelen);
Packit fcad23
Packit fcad23
        if (name_len - current->namelen > vp->namelen) {
Packit fcad23
            common_len = vp->namelen;
Packit fcad23
        } else {
Packit fcad23
            common_len = name_len - current->namelen;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        rc2 = snmp_oid_compare(vp->name, common_len,
Packit fcad23
                               name + current->namelen, common_len);
Packit fcad23
Packit fcad23
        if (rc >= 0) {
Packit fcad23
            break;  /* All following variables belong to the second subtree */
Packit fcad23
	}
Packit fcad23
Packit fcad23
        current->variables_len++;
Packit fcad23
        if (rc2 < 0) {
Packit fcad23
            new_sub->variables_len--;
Packit fcad23
            cp = (char *) new_sub->variables;
Packit fcad23
            new_sub->variables = (struct variable *)(cp + 
Packit fcad23
						     new_sub->variables_width);
Packit fcad23
        }
Packit fcad23
        vp = (struct variable *) ((char *) vp + current->variables_width);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* Delegated trees should retain their variables regardless */
Packit fcad23
    if (current->variables_len > 0 &&
Packit fcad23
        IS_DELEGATED((u_char) current->variables[0].type)) {
Packit fcad23
        new_sub->variables_len = 1;
Packit fcad23
        new_sub->variables = current->variables;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* Propogate this split down through any children */
Packit fcad23
    if (current->children) {
Packit fcad23
        new_sub->children = netsnmp_subtree_split(current->children, 
Packit fcad23
						  name, name_len);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* Retain the correct linking of the list */
Packit fcad23
    for (ptr = current; ptr != NULL; ptr = ptr->children) {
Packit fcad23
        netsnmp_subtree_change_next(ptr, new_sub);
Packit fcad23
    }
Packit fcad23
    for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
Packit fcad23
        netsnmp_subtree_change_prev(ptr, current);
Packit fcad23
    }
Packit fcad23
    for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
Packit fcad23
        netsnmp_subtree_change_prev(ptr, new_sub);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return new_sub;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Loads the subtree under given context name.
Packit fcad23
 *
Packit fcad23
 *  @param new_sub The subtree to be loaded into current subtree.
Packit fcad23
 *
Packit fcad23
 *  @param context_name Text name of the context we're searching for.
Packit fcad23
 *
Packit fcad23
 *  @return gives MIB_REGISTERED_OK on success, error code otherwise.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *tree1, *tree2;
Packit fcad23
    netsnmp_subtree *prev, *next;
Packit fcad23
Packit fcad23
    if (new_sub == NULL) {
Packit fcad23
        return MIB_REGISTERED_OK;       /* Degenerate case */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!netsnmp_subtree_find_first(context_name)) {
Packit fcad23
        static int inloop = 0;
Packit fcad23
        if (!inloop) {
Packit fcad23
            oid ccitt[1]           = { 0 };
Packit fcad23
            oid iso[1]             = { 1 };
Packit fcad23
            oid joint_ccitt_iso[1] = { 2 };
Packit fcad23
            inloop = 1;
Packit fcad23
            netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1,
Packit fcad23
                                          context_name);
Packit fcad23
            netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1,
Packit fcad23
                                          context_name);
Packit fcad23
            netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1),
Packit fcad23
                                          1, context_name);
Packit fcad23
            inloop = 0;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*  Find the subtree that contains the start of the new subtree (if
Packit fcad23
	any)...*/
Packit fcad23
Packit fcad23
    tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
Packit fcad23
				 NULL, context_name);
Packit fcad23
Packit fcad23
    /*  ... and the subtree that follows the new one (NULL implies this is the
Packit fcad23
	final region covered).  */
Packit fcad23
Packit fcad23
    if (tree1 == NULL) {
Packit fcad23
	tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
Packit fcad23
					  NULL, context_name);
Packit fcad23
    } else {
Packit fcad23
	tree2 = tree1->next;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*  Handle new subtrees that start in virgin territory.  */
Packit fcad23
Packit fcad23
    if (tree1 == NULL) {
Packit fcad23
        /*netsnmp_subtree *new2 = NULL;*/
Packit fcad23
	/*  Is there any overlap with later subtrees?  */
Packit fcad23
	if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
Packit fcad23
				      tree2->start_a, tree2->start_len) > 0) {
Packit fcad23
	    /*new2 =*/
Packit fcad23
            netsnmp_subtree_split(new_sub, tree2->start_a, tree2->start_len);
Packit fcad23
	}
Packit fcad23
Packit fcad23
	/*  Link the new subtree (less any overlapping region) with the list of
Packit fcad23
	    existing registrations.  */
Packit fcad23
Packit fcad23
	if (tree2) {
Packit fcad23
            netsnmp_subtree_change_prev(new_sub, tree2->prev);
Packit fcad23
            netsnmp_subtree_change_prev(tree2, new_sub);
Packit fcad23
	} else {
Packit fcad23
            netsnmp_subtree_change_prev(new_sub,
Packit fcad23
                                        netsnmp_subtree_find_prev(new_sub->start_a,
Packit fcad23
                                                                  new_sub->start_len, NULL, context_name));
Packit fcad23
Packit fcad23
	    if (new_sub->prev) {
Packit fcad23
                netsnmp_subtree_change_next(new_sub->prev, new_sub);
Packit fcad23
	    } else {
Packit fcad23
		netsnmp_subtree_replace_first(new_sub, context_name);
Packit fcad23
	    }
Packit fcad23
Packit fcad23
            netsnmp_subtree_change_next(new_sub, tree2);
Packit fcad23
Packit fcad23
#if 0
Packit fcad23
            /* The code below cannot be reached which is why it has been
Packit fcad23
               surrounded with #if 0 / #endif. */
Packit fcad23
	    /* If there was any overlap, recurse to merge in the overlapping
Packit fcad23
	       region (including anything that may follow the overlap).  */
Packit fcad23
	    if (new2) {
Packit fcad23
		return netsnmp_subtree_load(new2, context_name);
Packit fcad23
	    }
Packit fcad23
#endif
Packit fcad23
	}
Packit fcad23
    } else {
Packit fcad23
	/*  If the new subtree starts *within* an existing registration
Packit fcad23
	    (rather than at the same point as it), then split the existing
Packit fcad23
	    subtree at this point.  */
Packit fcad23
Packit fcad23
	if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 
Packit fcad23
			     tree1->start_a,   tree1->start_len) != 0) {
Packit fcad23
	    tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 
Packit fcad23
					  new_sub->start_len);
Packit fcad23
	}
Packit fcad23
Packit fcad23
        if (tree1 == NULL) {
Packit fcad23
            return MIB_REGISTRATION_FAILED;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	/*  Now consider the end of this existing subtree:
Packit fcad23
	    
Packit fcad23
	    If it matches the new subtree precisely,
Packit fcad23
	            simply merge the new one into the list of children
Packit fcad23
Packit fcad23
	    If it includes the whole of the new subtree,
Packit fcad23
		    split it at the appropriate point, and merge again
Packit fcad23
     
Packit fcad23
	    If the new subtree extends beyond this existing region,
Packit fcad23
	            split it, and recurse to merge the two parts.  */
Packit fcad23
Packit fcad23
	switch (snmp_oid_compare(new_sub->end_a, new_sub->end_len,
Packit fcad23
                                 tree1->end_a, tree1->end_len)) {
Packit fcad23
Packit fcad23
	case -1:
Packit fcad23
	    /*  Existing subtree contains new one.  */
Packit fcad23
	    netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
Packit fcad23
	    /* Fall Through */
Packit fcad23
Packit fcad23
	case  0:
Packit fcad23
	    /*  The two trees match precisely.  */
Packit fcad23
Packit fcad23
	    /*  Note: This is the only point where the original registration
Packit fcad23
	        OID ("name") is used.  */
Packit fcad23
Packit fcad23
	    prev = NULL;
Packit fcad23
	    next = tree1;
Packit fcad23
	
Packit fcad23
	    while (next && next->namelen > new_sub->namelen) {
Packit fcad23
		prev = next;
Packit fcad23
		next = next->children;
Packit fcad23
	    }
Packit fcad23
Packit fcad23
	    while (next && next->namelen == new_sub->namelen &&
Packit fcad23
		   next->priority < new_sub->priority ) {
Packit fcad23
		prev = next;
Packit fcad23
		next = next->children;
Packit fcad23
	    }
Packit fcad23
	
Packit fcad23
	    if (next && (next->namelen  == new_sub->namelen) &&
Packit fcad23
		(next->priority == new_sub->priority)) {
Packit fcad23
                if (new_sub->namelen != 1) {    /* ignore root OID dups */
Packit fcad23
                    size_t          out_len = 0;
Packit fcad23
                    size_t          buf_len = 0;
Packit fcad23
                    char           *buf = NULL;
Packit fcad23
                    int             buf_overflow = 0;
Packit fcad23
Packit fcad23
                    netsnmp_sprint_realloc_objid((u_char **) &buf, &buf_len, &out_len,
Packit fcad23
                                                 1, &buf_overflow,
Packit fcad23
                                                 new_sub->start_a,
Packit fcad23
                                                 new_sub->start_len);
Packit fcad23
                    snmp_log(LOG_ERR,
Packit fcad23
                             "duplicate registration: MIB modules %s and %s (oid %s%s).\n",
Packit fcad23
                             next->label_a, new_sub->label_a,
Packit fcad23
                             buf ? buf : "",
Packit fcad23
                             buf_overflow ? " [TRUNCATED]" : "");
Packit fcad23
                    free(buf);
Packit fcad23
                }
Packit fcad23
		return MIB_DUPLICATE_REGISTRATION;
Packit fcad23
	    }
Packit fcad23
Packit fcad23
	    if (prev) {
Packit fcad23
		prev->children    = new_sub;
Packit fcad23
		new_sub->children = next;
Packit fcad23
                netsnmp_subtree_change_prev(new_sub, prev->prev);
Packit fcad23
                netsnmp_subtree_change_next(new_sub, prev->next);
Packit fcad23
	    } else {
Packit fcad23
		new_sub->children = next;
Packit fcad23
                netsnmp_subtree_change_prev(new_sub, next->prev);
Packit fcad23
                netsnmp_subtree_change_next(new_sub, next->next);
Packit fcad23
	
Packit fcad23
		for (next = new_sub->next; next != NULL;next = next->children){
Packit fcad23
                    netsnmp_subtree_change_prev(next, new_sub);
Packit fcad23
		}
Packit fcad23
Packit fcad23
		for (prev = new_sub->prev; prev != NULL;prev = prev->children){
Packit fcad23
                    netsnmp_subtree_change_next(prev, new_sub);
Packit fcad23
		}
Packit fcad23
	    }
Packit fcad23
	    break;
Packit fcad23
Packit fcad23
	case  1:
Packit fcad23
	    /*  New subtree contains the existing one.  */
Packit fcad23
            {
Packit fcad23
                netsnmp_subtree *new2 =
Packit fcad23
                    netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
Packit fcad23
                int res = netsnmp_subtree_load(new_sub, context_name);
Packit fcad23
                if (res != MIB_REGISTERED_OK) {
Packit fcad23
                    netsnmp_remove_subtree(new2);
Packit fcad23
                    netsnmp_subtree_free(new2);
Packit fcad23
                    return res;
Packit fcad23
                }
Packit fcad23
                return netsnmp_subtree_load(new2, context_name);
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Free the given subtree and all its children.
Packit fcad23
 *
Packit fcad23
 *  @param sub Subtree branch to be cleared and freed.
Packit fcad23
 *             After the call, this pointer is invalid
Packit fcad23
 *             and should be set to NULL.
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
clear_subtree (netsnmp_subtree *sub) {
Packit fcad23
Packit fcad23
    netsnmp_subtree *c;
Packit fcad23
    
Packit fcad23
    if (sub == NULL)
Packit fcad23
	return;
Packit fcad23
Packit fcad23
    for(c = sub; c;) {
Packit fcad23
        sub = c;
Packit fcad23
        c = c->children;
Packit fcad23
        netsnmp_subtree_free(sub);
Packit fcad23
    }
Packit fcad23
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_find_prev(const oid *name, size_t len, netsnmp_subtree *subtree,
Packit fcad23
			  const char *context_name)
Packit fcad23
{
Packit fcad23
    lookup_cache *lookup_cache = NULL;
Packit fcad23
    netsnmp_subtree *myptr = NULL, *previous = NULL;
Packit fcad23
    int cmp = 1;
Packit fcad23
    size_t ll_off = 0;
Packit fcad23
Packit fcad23
    if (subtree) {
Packit fcad23
        myptr = subtree;
Packit fcad23
    } else {
Packit fcad23
	/* look through everything */
Packit fcad23
        if (lookup_cache_size) {
Packit fcad23
            lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
Packit fcad23
            if (lookup_cache) {
Packit fcad23
                myptr = lookup_cache->next;
Packit fcad23
                previous = lookup_cache->previous;
Packit fcad23
            }
Packit fcad23
            if (!myptr)
Packit fcad23
                myptr = netsnmp_subtree_find_first(context_name);
Packit fcad23
        } else {
Packit fcad23
            myptr = netsnmp_subtree_find_first(context_name);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * this optimization causes a segfault on sf cf alpha-linux1.
Packit fcad23
     * ifdef out until someone figures out why and fixes it. xxx-rks 20051117
Packit fcad23
     */
Packit fcad23
#ifndef __alpha
Packit fcad23
#define WTEST_OPTIMIZATION 1
Packit fcad23
#endif
Packit fcad23
#ifdef WTEST_OPTIMIZATION
Packit fcad23
    DEBUGMSGTL(("wtest","oid in: "));
Packit fcad23
    DEBUGMSGOID(("wtest", name, len));
Packit fcad23
    DEBUGMSG(("wtest","\n"));
Packit fcad23
#endif
Packit fcad23
    for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
Packit fcad23
#ifdef WTEST_OPTIMIZATION
Packit fcad23
        /* Compare the incoming oid with the linked list.  If we have
Packit fcad23
           results of previous compares, its faster to make sure the
Packit fcad23
           length we differed in the last check is greater than the
Packit fcad23
           length between this pointer and the last then we don't need
Packit fcad23
           to actually perform a comparison */
Packit fcad23
        DEBUGMSGTL(("wtest","oid cmp: "));
Packit fcad23
        DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len));
Packit fcad23
        DEBUGMSG(("wtest","  --- off = %lu, in off = %lu test = %d\n",
Packit fcad23
                  (unsigned long)myptr->oid_off, (unsigned long)ll_off,
Packit fcad23
                  !(ll_off && myptr->oid_off &&
Packit fcad23
                    myptr->oid_off > ll_off)));
Packit fcad23
        if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) &&
Packit fcad23
            netsnmp_oid_compare_ll(name, len,
Packit fcad23
                                   myptr->start_a, myptr->start_len,
Packit fcad23
                                   &ll_off) < 0) {
Packit fcad23
#else
Packit fcad23
        if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
Packit fcad23
#endif
Packit fcad23
            if (lookup_cache_size && previous && cmp) {
Packit fcad23
                if (lookup_cache) {
Packit fcad23
                    lookup_cache_replace(lookup_cache, myptr, previous);
Packit fcad23
                } else {
Packit fcad23
                    lookup_cache_add(context_name, myptr, previous);
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
            return previous;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    return previous;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_find_next(const oid *name, size_t len,
Packit fcad23
			  netsnmp_subtree *subtree, const char *context_name)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *myptr = NULL;
Packit fcad23
Packit fcad23
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
Packit fcad23
Packit fcad23
    if (myptr != NULL) {
Packit fcad23
        myptr = myptr->next;
Packit fcad23
        while (myptr != NULL && (myptr->variables == NULL || 
Packit fcad23
				 myptr->variables_len == 0)) {
Packit fcad23
            myptr = myptr->next;
Packit fcad23
        }
Packit fcad23
        return myptr;
Packit fcad23
    } else if (subtree != NULL && snmp_oid_compare(name, len, 
Packit fcad23
				   subtree->start_a, subtree->start_len) < 0) {
Packit fcad23
        return subtree;
Packit fcad23
    } else {
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_subtree *
Packit fcad23
netsnmp_subtree_find(const oid *name, size_t len, netsnmp_subtree *subtree, 
Packit fcad23
		     const char *context_name)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *myptr;
Packit fcad23
Packit fcad23
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
Packit fcad23
    if (myptr && myptr->end_a &&
Packit fcad23
        snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
Packit fcad23
        return myptr;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return NULL;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**  @} */
Packit fcad23
/* End of Subtrees maintaining code */
Packit fcad23
Packit fcad23
/** @defgroup agent_mib_registering Registering and unregistering MIB subtrees.
Packit fcad23
 *     Adding and removing MIB nodes to the database under their contexts.
Packit fcad23
 *   @ingroup agent_registry
Packit fcad23
 *
Packit fcad23
 * @{
Packit fcad23
 */
Packit fcad23
Packit fcad23
Packit fcad23
/** Registers a MIB handler.
Packit fcad23
 *
Packit fcad23
 *  @param moduleName
Packit fcad23
 *  @param var
Packit fcad23
 *  @param varsize
Packit fcad23
 *  @param numvars
Packit fcad23
 *  @param  mibloc
Packit fcad23
 *  @param mibloclen
Packit fcad23
 *  @param priority
Packit fcad23
 *  @param range_subid
Packit fcad23
 *  @param range_ubound
Packit fcad23
 *  @param  ss
Packit fcad23
 *  @param context
Packit fcad23
 *  @param timeout
Packit fcad23
 *  @param flags
Packit fcad23
 *  @param reginfo Registration handler structure.
Packit fcad23
 *                 In a case of failure, it will be freed.
Packit fcad23
 *  @param perform_callback
Packit fcad23
 *
Packit fcad23
 *  @return gives MIB_REGISTERED_OK or MIB_* error code.
Packit fcad23
 *
Packit fcad23
 *  @see netsnmp_register_handler()
Packit fcad23
 *  @see register_agentx_list()
Packit fcad23
 *  @see netsnmp_handler_registration_free()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_register_mib(const char *moduleName,
Packit fcad23
                     struct variable *var,
Packit fcad23
                     size_t varsize,
Packit fcad23
                     size_t numvars,
Packit fcad23
                     oid * mibloc,
Packit fcad23
                     size_t mibloclen,
Packit fcad23
                     int priority,
Packit fcad23
                     int range_subid,
Packit fcad23
                     oid range_ubound,
Packit fcad23
                     netsnmp_session * ss,
Packit fcad23
                     const char *context,
Packit fcad23
                     int timeout,
Packit fcad23
                     int flags,
Packit fcad23
                     netsnmp_handler_registration *reginfo,
Packit fcad23
                     int perform_callback)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *subtree, *sub2;
Packit fcad23
    int             res;
Packit fcad23
    struct register_parameters reg_parms;
Packit fcad23
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
Packit fcad23
Packit fcad23
    if (moduleName == NULL ||
Packit fcad23
        mibloc     == NULL) {
Packit fcad23
        /* Shouldn't happen ??? */
Packit fcad23
        netsnmp_handler_registration_free(reginfo);
Packit fcad23
        return MIB_REGISTRATION_FAILED;
Packit fcad23
    }
Packit fcad23
    subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
Packit fcad23
    if (subtree == NULL) {
Packit fcad23
        netsnmp_handler_registration_free(reginfo);
Packit fcad23
        return MIB_REGISTRATION_FAILED;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
Packit fcad23
    DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
Packit fcad23
                      range_ubound));
Packit fcad23
    DEBUGMSG(("register_mib", " with context \"%s\"\n",
Packit fcad23
              SNMP_STRORNULL(context)));
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * verify that the passed context is equal to the context
Packit fcad23
     * in the reginfo.
Packit fcad23
     * (which begs the question, why do we have both? It appears that the
Packit fcad23
     *  reginfo item didn't appear til 5.2)
Packit fcad23
     */
Packit fcad23
    if( ((NULL == context) && (NULL != reginfo->contextName)) ||
Packit fcad23
        ((NULL != context) && (NULL == reginfo->contextName)) ||
Packit fcad23
        ( ((NULL != context) && (NULL != reginfo->contextName)) &&
Packit fcad23
          (0 != strcmp(context, reginfo->contextName))) ) {
Packit fcad23
        snmp_log(LOG_WARNING,"context passed during registration does not "
Packit fcad23
                 "equal the reginfo contextName! ('%s' != '%s')\n",
Packit fcad23
                 context, reginfo->contextName);
Packit fcad23
        netsnmp_assert(!"register context == reginfo->contextName"); /* always false */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*  Create the new subtree node being registered.  */
Packit fcad23
Packit fcad23
    subtree->reginfo = reginfo;
Packit fcad23
    subtree->name_a  = snmp_duplicate_objid(mibloc, mibloclen);
Packit fcad23
    subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
Packit fcad23
    subtree->end_a   = snmp_duplicate_objid(mibloc, mibloclen);
Packit fcad23
    subtree->label_a = strdup(moduleName);
Packit fcad23
    if (subtree->name_a == NULL || subtree->start_a == NULL || 
Packit fcad23
	subtree->end_a  == NULL || subtree->label_a == NULL) {
Packit fcad23
	netsnmp_subtree_free(subtree); /* also frees reginfo */
Packit fcad23
	return MIB_REGISTRATION_FAILED;
Packit fcad23
    }
Packit fcad23
    subtree->namelen   = (u_char)mibloclen;
Packit fcad23
    subtree->start_len = (u_char)mibloclen;
Packit fcad23
    subtree->end_len   = (u_char)mibloclen;
Packit fcad23
    subtree->end_a[mibloclen - 1]++;
Packit fcad23
Packit fcad23
    if (var != NULL) {
Packit fcad23
	subtree->variables = (struct variable *)malloc(varsize*numvars);
Packit fcad23
	if (subtree->variables == NULL) {
Packit fcad23
	    netsnmp_subtree_free(subtree); /* also frees reginfo */
Packit fcad23
	    return MIB_REGISTRATION_FAILED;
Packit fcad23
	}
Packit fcad23
	memcpy(subtree->variables, var, numvars*varsize);
Packit fcad23
	subtree->variables_len = numvars;
Packit fcad23
	subtree->variables_width = varsize;
Packit fcad23
    }
Packit fcad23
    subtree->priority = priority;
Packit fcad23
    subtree->timeout = timeout;
Packit fcad23
    subtree->range_subid = range_subid;
Packit fcad23
    subtree->range_ubound = range_ubound;
Packit fcad23
    subtree->session = ss;
Packit fcad23
    subtree->flags = (u_char)flags;    /*  used to identify instance oids  */
Packit fcad23
    subtree->flags |= SUBTREE_ATTACHED;
Packit fcad23
    subtree->global_cacheid = reginfo->global_cacheid;
Packit fcad23
Packit fcad23
    netsnmp_set_lookup_cache_size(0);
Packit fcad23
    res = netsnmp_subtree_load(subtree, context);
Packit fcad23
Packit fcad23
    /*  If registering a range, use the first subtree as a template for the
Packit fcad23
	rest of the range.  */
Packit fcad23
Packit fcad23
    if (res == MIB_REGISTERED_OK && range_subid != 0) {
Packit fcad23
        int i;
Packit fcad23
	for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
Packit fcad23
	    sub2 = netsnmp_subtree_deepcopy(subtree);
Packit fcad23
Packit fcad23
	    if (sub2 == NULL) {
Packit fcad23
                unregister_mib_context(mibloc, mibloclen, priority,
Packit fcad23
                                       range_subid, range_ubound, context);
Packit fcad23
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit fcad23
                invalidate_lookup_cache(context);
Packit fcad23
                return MIB_REGISTRATION_FAILED;
Packit fcad23
            }
Packit fcad23
Packit fcad23
            sub2->name_a[range_subid - 1]  = i;
Packit fcad23
            sub2->start_a[range_subid - 1] = i;
Packit fcad23
            sub2->end_a[range_subid - 1]   = i;     /* XXX - ???? */
Packit fcad23
            if (range_subid == (int)mibloclen) {
Packit fcad23
                ++sub2->end_a[range_subid - 1];
Packit fcad23
            }
Packit fcad23
            sub2->flags |= SUBTREE_ATTACHED;
Packit fcad23
            sub2->global_cacheid = reginfo->global_cacheid;
Packit fcad23
            /* FRQ This is essential for requests to succeed! */
Packit fcad23
            sub2->reginfo->rootoid[range_subid - 1]  = i;
Packit fcad23
Packit fcad23
            res = netsnmp_subtree_load(sub2, context);
Packit fcad23
            if (res != MIB_REGISTERED_OK) {
Packit fcad23
                unregister_mib_context(mibloc, mibloclen, priority,
Packit fcad23
                                       range_subid, range_ubound, context);
Packit fcad23
                netsnmp_remove_subtree(sub2);
Packit fcad23
		netsnmp_subtree_free(sub2);
Packit fcad23
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit fcad23
                invalidate_lookup_cache(context);
Packit fcad23
                return res;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    } else if (res == MIB_DUPLICATE_REGISTRATION ||
Packit fcad23
               res == MIB_REGISTRATION_FAILED) {
Packit fcad23
        netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit fcad23
        invalidate_lookup_cache(context);
Packit fcad23
        netsnmp_subtree_free(subtree);
Packit fcad23
        return res;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * mark the MIB as detached, if there's no master agent present as of now 
Packit fcad23
     */
Packit fcad23
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
Packit fcad23
			       NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
Packit fcad23
        if (main_session == NULL) {
Packit fcad23
            register_mib_detach_node(subtree);
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (res == MIB_REGISTERED_OK && perform_callback) {
Packit fcad23
        memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit fcad23
        reg_parms.name = mibloc;
Packit fcad23
        reg_parms.namelen = mibloclen;
Packit fcad23
        reg_parms.priority = priority;
Packit fcad23
        reg_parms.range_subid = range_subid;
Packit fcad23
        reg_parms.range_ubound = range_ubound;
Packit fcad23
        reg_parms.timeout = timeout;
Packit fcad23
        reg_parms.flags = (u_char) flags;
Packit fcad23
        reg_parms.contextName = context;
Packit fcad23
        reg_parms.session = ss;
Packit fcad23
        reg_parms.reginfo = reginfo;
Packit fcad23
        reg_parms.contextName = context;
Packit fcad23
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit fcad23
    invalidate_lookup_cache(context);
Packit fcad23
    return res;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Reattach a particular node.  
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
register_mib_reattach_node(netsnmp_subtree *s)
Packit fcad23
{
Packit fcad23
    if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
Packit fcad23
        struct register_parameters reg_parms;
Packit fcad23
        /*
Packit fcad23
         * only do registrations that are not the top level nodes 
Packit fcad23
         */
Packit fcad23
        memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * XXX: do this better 
Packit fcad23
         */
Packit fcad23
        reg_parms.name = s->name_a;
Packit fcad23
        reg_parms.namelen = s->namelen;
Packit fcad23
        reg_parms.priority = s->priority;
Packit fcad23
        reg_parms.range_subid = s->range_subid;
Packit fcad23
        reg_parms.range_ubound = s->range_ubound;
Packit fcad23
        reg_parms.timeout = s->timeout;
Packit fcad23
        reg_parms.flags = s->flags;
Packit fcad23
        reg_parms.session = s->session;
Packit fcad23
        reg_parms.reginfo = s->reginfo;
Packit fcad23
        /* XXX: missing in subtree: reg_parms.contextName = s->context; */
Packit fcad23
        if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName))
Packit fcad23
            reg_parms.contextName = s->reginfo->contextName;
Packit fcad23
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
Packit fcad23
        s->flags |= SUBTREE_ATTACHED;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Call callbacks to reattach all our nodes.  
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
register_mib_reattach(void)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *s, *t;
Packit fcad23
    subtree_context_cache *ptr;
Packit fcad23
Packit fcad23
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
Packit fcad23
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
Packit fcad23
            register_mib_reattach_node(s);
Packit fcad23
            for (t = s->children; t != NULL; t = t->children) {
Packit fcad23
                register_mib_reattach_node(t);
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Mark a node as detached.
Packit fcad23
 *
Packit fcad23
 *  @param s The note to be marked
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
register_mib_detach_node(netsnmp_subtree *s)
Packit fcad23
{
Packit fcad23
    if (s != NULL) {
Packit fcad23
        s->flags = s->flags & ~SUBTREE_ATTACHED;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Mark all our registered OIDs as detached.
Packit fcad23
 *  This is only really useful for subagent protocols, when
Packit fcad23
 *  a connection is lost or the subagent is being shut down.  
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
register_mib_detach(void)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *s, *t;
Packit fcad23
    subtree_context_cache *ptr;
Packit fcad23
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
Packit fcad23
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
Packit fcad23
            register_mib_detach_node(s);
Packit fcad23
            for (t = s->children; t != NULL; t = t->children) {
Packit fcad23
                register_mib_detach_node(t);
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Register a new module into the MIB database, with all possible custom options
Packit fcad23
 *
Packit fcad23
 *  @param  moduleName Text name of the module.
Packit fcad23
 *                     The given name will be used to identify the module
Packit fcad23
 *                     inside the agent.
Packit fcad23
 *
Packit fcad23
 *  @param  var        Array of variables to be registered in the module.
Packit fcad23
 *
Packit fcad23
 *  @param  varsize    Size of a single variable in var array.
Packit fcad23
 *                     The size is normally equal to sizeof(struct variable),
Packit fcad23
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit fcad23
 *                     could use different variant of the variable structure.
Packit fcad23
 *
Packit fcad23
 *  @param  numvars    Number of variables in the var array.
Packit fcad23
 *                     This is how many variables the function will try to register.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloc     Base OID of the module.
Packit fcad23
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloclen  Length of the base OID.
Packit fcad23
 *                     Number of integers making up the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  priority   Registration priority.
Packit fcad23
 *                     Used to achieve a desired configuration when different
Packit fcad23
 *                     sessions register identical or overlapping regions.
Packit fcad23
 *                     Primarily used with AgentX subagent registrations.
Packit fcad23
 *
Packit fcad23
 *  @param range_subid If non-zero, the module is registered against a range
Packit fcad23
 *                     of OIDs, with this parameter identifying the relevant
Packit fcad23
 *                     subidentifier - see RFC 2741 for details.
Packit fcad23
 *                     Typically used to register a single row of a table.
Packit fcad23
 *                     If zero, then register the module against the full OID subtree.
Packit fcad23
 *
Packit fcad23
 *  @param range_ubound The end of the range being registered (see RFC 2741)
Packit fcad23
 *                     If range_subid is zero, then this parameter is ignored.
Packit fcad23
 *
Packit fcad23
 *  @param ss 
Packit fcad23
 *  @param context
Packit fcad23
 *  @param timeout 
Packit fcad23
 *  @param flags 
Packit fcad23
 *
Packit fcad23
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit fcad23
 *
Packit fcad23
 *  @see register_mib()
Packit fcad23
 *  @see register_mib_priority()
Packit fcad23
 *  @see register_mib_range()
Packit fcad23
 *  @see unregister_mib()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
register_mib_context(const char *moduleName,
Packit fcad23
                     const struct variable *var,
Packit fcad23
                     size_t varsize,
Packit fcad23
                     size_t numvars,
Packit fcad23
                     const oid * mibloc,
Packit fcad23
                     size_t mibloclen,
Packit fcad23
                     int priority,
Packit fcad23
                     int range_subid,
Packit fcad23
                     oid range_ubound,
Packit fcad23
                     netsnmp_session * ss,
Packit fcad23
                     const char *context, int timeout, int flags)
Packit fcad23
{
Packit fcad23
    return netsnmp_register_old_api(moduleName, var, varsize, numvars,
Packit fcad23
                                    mibloc, mibloclen, priority,
Packit fcad23
                                    range_subid, range_ubound, ss, context,
Packit fcad23
                                    timeout, flags);
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Register a new module into the MIB database, as being responsible
Packit fcad23
 *   for a range of OIDs (typically a single row of a table).
Packit fcad23
 *
Packit fcad23
 *  @param  moduleName Text name of the module.
Packit fcad23
 *                     The given name will be used to identify the module
Packit fcad23
 *                     inside the agent.
Packit fcad23
 *
Packit fcad23
 *  @param  var        Array of variables to be registered in the module.
Packit fcad23
 *
Packit fcad23
 *  @param  varsize    Size of a single variable in var array.
Packit fcad23
 *                     The size is normally equal to sizeof(struct variable),
Packit fcad23
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit fcad23
 *                     could use different variant of the variable structure.
Packit fcad23
 *
Packit fcad23
 *  @param  numvars    Number of variables in the var array.
Packit fcad23
 *                     This is how many variables the function will try to register.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloc     Base OID of the module.
Packit fcad23
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloclen  Length of the base OID.
Packit fcad23
 *                     Number of integers making up the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  priority   Registration priority.
Packit fcad23
 *                     Used to achieve a desired configuration when different
Packit fcad23
 *                     sessions register identical or overlapping regions.
Packit fcad23
 *                     Primarily used with AgentX subagent registrations.
Packit fcad23
 *
Packit fcad23
 *  @param range_subid If non-zero, the module is registered against a range
Packit fcad23
 *                     of OIDs, with this parameter identifying the relevant
Packit fcad23
 *                     subidentifier - see RFC 2741 for details.
Packit fcad23
 *                     Typically used to register a single row of a table.
Packit fcad23
 *                     If zero, then register the module against the full OID subtree.
Packit fcad23
 *
Packit fcad23
 *  @param range_ubound The end of the range being registered (see RFC 2741)
Packit fcad23
 *                     If range_subid is zero, then this parameter is ignored.
Packit fcad23
 *
Packit fcad23
 *  @param ss 
Packit fcad23
 *
Packit fcad23
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit fcad23
 *
Packit fcad23
 *  @see register_mib()
Packit fcad23
 *  @see register_mib_priority()
Packit fcad23
 *  @see register_mib_context()
Packit fcad23
 *  @see unregister_mib()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
register_mib_range(const char *moduleName,
Packit fcad23
                   const struct variable *var,
Packit fcad23
                   size_t varsize,
Packit fcad23
                   size_t numvars,
Packit fcad23
                   const oid * mibloc,
Packit fcad23
                   size_t mibloclen,
Packit fcad23
                   int priority,
Packit fcad23
                   int range_subid, oid range_ubound, netsnmp_session * ss)
Packit fcad23
{
Packit fcad23
    return register_mib_context(moduleName, var, varsize, numvars,
Packit fcad23
                                mibloc, mibloclen, priority,
Packit fcad23
                                range_subid, range_ubound, ss, "", -1, 0);
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Register a new module into the MIB database, with a non-default priority
Packit fcad23
 *
Packit fcad23
 *  @param  moduleName Text name of the module.
Packit fcad23
 *                     The given name will be used to identify the module
Packit fcad23
 *                     inside the agent.
Packit fcad23
 *
Packit fcad23
 *  @param  var        Array of variables to be registered in the module.
Packit fcad23
 *
Packit fcad23
 *  @param  varsize    Size of a single variable in var array.
Packit fcad23
 *                     The size is normally equal to sizeof(struct variable),
Packit fcad23
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit fcad23
 *                     could use different variant of the variable structure.
Packit fcad23
 *
Packit fcad23
 *  @param  numvars    Number of variables in the var array.
Packit fcad23
 *                     This is how many variables the function will try to register.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloc     Base OID of the module.
Packit fcad23
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloclen  Length of the base OID.
Packit fcad23
 *                     Number of integers making up the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  priority   Registration priority.
Packit fcad23
 *                     Used to achieve a desired configuration when different
Packit fcad23
 *                     sessions register identical or overlapping regions.
Packit fcad23
 *                     Primarily used with AgentX subagent registrations.
Packit fcad23
 *
Packit fcad23
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit fcad23
 *
Packit fcad23
 *  @see register_mib()
Packit fcad23
 *  @see register_mib_range()
Packit fcad23
 *  @see register_mib_context()
Packit fcad23
 *  @see unregister_mib()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
register_mib_priority(const char *moduleName,
Packit fcad23
                      const struct variable *var,
Packit fcad23
                      size_t varsize,
Packit fcad23
                      size_t numvars,
Packit fcad23
                      const oid * mibloc, size_t mibloclen, int priority)
Packit fcad23
{
Packit fcad23
    return register_mib_range(moduleName, var, varsize, numvars,
Packit fcad23
                              mibloc, mibloclen, priority, 0, 0, NULL);
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Register a new module into the MIB database, using default priority and context
Packit fcad23
 *
Packit fcad23
 *  @param  moduleName Text name of the module.
Packit fcad23
 *                     The given name will be used to identify the module
Packit fcad23
 *                     inside the agent.
Packit fcad23
 *
Packit fcad23
 *  @param  var        Array of variables to be registered in the module.
Packit fcad23
 *
Packit fcad23
 *  @param  varsize    Size of a single variable in var array.
Packit fcad23
 *                     The size is normally equal to sizeof(struct variable),
Packit fcad23
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit fcad23
 *                     could use different variant of the variable structure.
Packit fcad23
 *
Packit fcad23
 *  @param  numvars    Number of variables in the var array.
Packit fcad23
 *                     This is how many variables the function will try to register.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloc     Base OID of the module.
Packit fcad23
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit fcad23
 *
Packit fcad23
 *  @param  mibloclen  Length of the base OID.
Packit fcad23
 *                     Number of integers making up the base OID.
Packit fcad23
 *
Packit fcad23
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit fcad23
 *
Packit fcad23
 *  @see register_mib_priority()
Packit fcad23
 *  @see register_mib_range()
Packit fcad23
 *  @see register_mib_context()
Packit fcad23
 *  @see unregister_mib()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
register_mib(const char *moduleName,
Packit fcad23
             const struct variable *var,
Packit fcad23
             size_t varsize,
Packit fcad23
             size_t numvars, const oid * mibloc, size_t mibloclen)
Packit fcad23
{
Packit fcad23
    return register_mib_priority(moduleName, var, varsize, numvars,
Packit fcad23
                                 mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
Packit fcad23
}
Packit fcad23
Packit fcad23
/** @private
Packit fcad23
 *  Unloads a subtree from MIB tree.
Packit fcad23
 *
Packit fcad23
 *  @param  sub     The sub-tree which is being removed.
Packit fcad23
 *
Packit fcad23
 *  @param  prev    Previous entry, before the unloaded one.
Packit fcad23
 *
Packit fcad23
 *  @param  context Name of the context which is being removed.
Packit fcad23
 *
Packit fcad23
 *  @see unregister_mib_context()
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *ptr;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("register_mib", "unload("));
Packit fcad23
    if (sub != NULL) {
Packit fcad23
        DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSG(("register_mib", "[NIL]"));
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
    DEBUGMSG(("register_mib", ", "));
Packit fcad23
    if (prev != NULL) {
Packit fcad23
        DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSG(("register_mib", "[NIL]"));
Packit fcad23
    }
Packit fcad23
    DEBUGMSG(("register_mib", ")\n"));
Packit fcad23
Packit fcad23
    if (prev != NULL) {         /* non-leading entries are easy */
Packit fcad23
        prev->children = sub->children;
Packit fcad23
        invalidate_lookup_cache(context);
Packit fcad23
        return;
Packit fcad23
    }
Packit fcad23
    /*
Packit fcad23
     * otherwise, we need to amend our neighbours as well 
Packit fcad23
     */
Packit fcad23
Packit fcad23
    if (sub->children == NULL) {        /* just remove this node completely */
Packit fcad23
        for (ptr = sub->prev; ptr; ptr = ptr->children) {
Packit fcad23
            netsnmp_subtree_change_next(ptr, sub->next);
Packit fcad23
        }
Packit fcad23
        for (ptr = sub->next; ptr; ptr = ptr->children) {
Packit fcad23
            netsnmp_subtree_change_prev(ptr, sub->prev);
Packit fcad23
        }
Packit fcad23
Packit fcad23
	if (sub->prev == NULL) {
Packit fcad23
	    netsnmp_subtree_replace_first(sub->next, context);
Packit fcad23
	}
Packit fcad23
Packit fcad23
    } else {
Packit fcad23
        for (ptr = sub->prev; ptr; ptr = ptr->children)
Packit fcad23
            netsnmp_subtree_change_next(ptr, sub->children);
Packit fcad23
        for (ptr = sub->next; ptr; ptr = ptr->children)
Packit fcad23
            netsnmp_subtree_change_prev(ptr, sub->children);
Packit fcad23
Packit fcad23
	if (sub->prev == NULL) {
Packit fcad23
	    netsnmp_subtree_replace_first(sub->children, context);
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
    invalidate_lookup_cache(context);
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Unregisters a module registered against a given OID (or range) in a specified context. 
Packit fcad23
 * Typically used when a module has multiple contexts defined.
Packit fcad23
 * The parameters priority, range_subid, range_ubound and context
Packit fcad23
 * should match those used to register the module originally.
Packit fcad23
 *
Packit fcad23
 * @param name  the specific OID to unregister if it conatins the associated
Packit fcad23
 *              context.
Packit fcad23
 *
Packit fcad23
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit fcad23
 *
Packit fcad23
 * @param priority  a value between 1 and 255, used to achieve a desired
Packit fcad23
 *                  configuration when different sessions register identical or
Packit fcad23
 *                  overlapping regions.  Subagents with no particular
Packit fcad23
 *                  knowledge of priority should register with the default
Packit fcad23
 *                  value of 127.
Packit fcad23
 *
Packit fcad23
 * @param range_subid  permits specifying a range in place of one of a subtree
Packit fcad23
 *                     sub-identifiers.  When this value is zero, no range is
Packit fcad23
 *                     being specified.
Packit fcad23
 *
Packit fcad23
 * @param range_ubound  the upper bound of a sub-identifier's range.
Packit fcad23
 *                      This field is present only if range_subid is not 0.
Packit fcad23
 *
Packit fcad23
 * @param context  a context name that has been created
Packit fcad23
 *
Packit fcad23
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit fcad23
 * 
Packit fcad23
 * @see unregister_mib()
Packit fcad23
 * @see unregister_mib_priority()
Packit fcad23
 * @see unregister_mib_range()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
unregister_mib_context(oid * name, size_t len, int priority,
Packit fcad23
                       int range_subid, oid range_ubound,
Packit fcad23
                       const char *context)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *list, *myptr = NULL;
Packit fcad23
    netsnmp_subtree *prev, *child, *next; /* loop through children */
Packit fcad23
    struct register_parameters reg_parms;
Packit fcad23
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
Packit fcad23
    int unregistering = 1;
Packit fcad23
    int orig_subid_val = -1;
Packit fcad23
Packit fcad23
    netsnmp_set_lookup_cache_size(0);
Packit fcad23
Packit fcad23
    if ((range_subid > 0) &&  ((size_t)range_subid <= len))
Packit fcad23
        orig_subid_val = name[range_subid-1];
Packit fcad23
Packit fcad23
    while(unregistering){
Packit fcad23
        DEBUGMSGTL(("register_mib", "unregistering "));
Packit fcad23
        DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
Packit fcad23
        DEBUGMSG(("register_mib", "\n"));
Packit fcad23
Packit fcad23
        list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
Packit fcad23
                    context);
Packit fcad23
        if (list == NULL) {
Packit fcad23
            return MIB_NO_SUCH_REGISTRATION;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        for (child = list, prev = NULL; child != NULL;
Packit fcad23
            prev = child, child = child->children) {
Packit fcad23
            if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
Packit fcad23
                child->priority == priority) {
Packit fcad23
                break;              /* found it */
Packit fcad23
             }
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (child == NULL) {
Packit fcad23
            return MIB_NO_SUCH_REGISTRATION;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        netsnmp_subtree_unload(child, prev, context);
Packit fcad23
        myptr = child;              /* remember this for later */
Packit fcad23
Packit fcad23
        /*
Packit fcad23
        *  Now handle any occurances in the following subtrees,
Packit fcad23
        *      as a result of splitting this range.  Due to the
Packit fcad23
        *      nature of the way such splits work, the first
Packit fcad23
        *      subtree 'slice' that doesn't refer to the given
Packit fcad23
        *      name marks the end of the original region.
Packit fcad23
        *
Packit fcad23
        *  This should also serve to register ranges.
Packit fcad23
        */
Packit fcad23
Packit fcad23
        for (list = myptr->next; list != NULL; list = next) {
Packit fcad23
            next = list->next; /* list gets freed sometimes; cache next */
Packit fcad23
            for (child = list, prev = NULL; child != NULL;
Packit fcad23
                prev = child, child = child->children) {
Packit fcad23
                if ((netsnmp_oid_equals(child->name_a, child->namelen,
Packit fcad23
                    name, len) == 0) &&
Packit fcad23
            (child->priority == priority)) {
Packit fcad23
                    netsnmp_subtree_unload(child, prev, context);
Packit fcad23
                    netsnmp_subtree_free(child);
Packit fcad23
                    break;
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
            if (child == NULL)      /* Didn't find the given name */
Packit fcad23
                break;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /* Maybe we are in a range... */
Packit fcad23
        if (orig_subid_val != -1){
Packit fcad23
            if (++name[range_subid-1] >= orig_subid_val+range_ubound)
Packit fcad23
                {
Packit fcad23
                unregistering=0;
Packit fcad23
                name[range_subid-1] = orig_subid_val;
Packit fcad23
                }
Packit fcad23
        }
Packit fcad23
        else {
Packit fcad23
            unregistering=0;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit fcad23
    reg_parms.name = name;
Packit fcad23
    reg_parms.namelen = len;
Packit fcad23
    reg_parms.priority = priority;
Packit fcad23
    reg_parms.range_subid = range_subid;
Packit fcad23
    reg_parms.range_ubound = range_ubound;
Packit fcad23
    reg_parms.flags = 0x00;     /*  this is okay I think  */
Packit fcad23
    reg_parms.contextName = context;
Packit fcad23
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
Packit fcad23
Packit fcad23
    netsnmp_subtree_free(myptr);
Packit fcad23
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit fcad23
    invalidate_lookup_cache(context);
Packit fcad23
    return MIB_UNREGISTERED_OK;
Packit fcad23
}
Packit fcad23
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW
Packit fcad23
int
Packit fcad23
netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
Packit fcad23
                                 int var_subid, oid range_ubound,
Packit fcad23
                                 const char *context)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *list, *myptr, *futureptr;
Packit fcad23
    netsnmp_subtree *prev, *child;       /* loop through children */
Packit fcad23
    struct register_parameters reg_parms;
Packit fcad23
    oid             range_lbound = name[var_subid - 1];
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("register_mib", "unregistering "));
Packit fcad23
    DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
Packit fcad23
    DEBUGMSG(("register_mib", "\n"));
Packit fcad23
Packit fcad23
    for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
Packit fcad23
        list = netsnmp_subtree_find(name, len, 
Packit fcad23
				netsnmp_subtree_find_first(context), context);
Packit fcad23
Packit fcad23
        if (list == NULL) {
Packit fcad23
            continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        for (child = list, prev = NULL; child != NULL;
Packit fcad23
             prev = child, child = child->children) {
Packit fcad23
Packit fcad23
            if (netsnmp_oid_equals(child->name_a, child->namelen, 
Packit fcad23
				 name, len) == 0 && 
Packit fcad23
		(child->priority == priority)) {
Packit fcad23
                break;          /* found it */
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (child == NULL) {
Packit fcad23
            continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        netsnmp_subtree_unload(child, prev, context);
Packit fcad23
        myptr = child;          /* remember this for later */
Packit fcad23
Packit fcad23
        for (list = myptr->next; list != NULL; list = futureptr) {
Packit fcad23
            /* remember the next spot in the list in case we free this node */
Packit fcad23
            futureptr = list->next;
Packit fcad23
Packit fcad23
            /* check each child */
Packit fcad23
            for (child = list, prev = NULL; child != NULL;
Packit fcad23
                 prev = child, child = child->children) {
Packit fcad23
Packit fcad23
                if (netsnmp_oid_equals(child->name_a, child->namelen, 
Packit fcad23
				      name, len) == 0 &&
Packit fcad23
                    (child->priority == priority)) {
Packit fcad23
                    netsnmp_subtree_unload(child, prev, context);
Packit fcad23
                    netsnmp_subtree_free(child);
Packit fcad23
                    break;
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
Packit fcad23
            /* XXX: wjh: not sure why we're bailing here */
Packit fcad23
            if (child == NULL) {        /* Didn't find the given name */
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
        netsnmp_subtree_free(myptr);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    name[var_subid - 1] = range_lbound;
Packit fcad23
    memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit fcad23
    reg_parms.name = name;
Packit fcad23
    reg_parms.namelen = len;
Packit fcad23
    reg_parms.priority = priority;
Packit fcad23
    reg_parms.range_subid = var_subid;
Packit fcad23
    reg_parms.range_ubound = range_ubound;
Packit fcad23
    reg_parms.flags = 0x00;     /*  this is okay I think  */
Packit fcad23
    reg_parms.contextName = context;
Packit fcad23
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW */
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Unregisters a module registered against a given OID (or range) in the default context. 
Packit fcad23
 * Typically used when a module has multiple contexts defined.
Packit fcad23
 * The parameters priority, range_subid, and range_ubound should
Packit fcad23
 * match those used to register the module originally.
Packit fcad23
 *
Packit fcad23
 * @param name  the specific OID to unregister if it conatins the associated
Packit fcad23
 *              context.
Packit fcad23
 *
Packit fcad23
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit fcad23
 *
Packit fcad23
 * @param priority  a value between 1 and 255, used to achieve a desired
Packit fcad23
 *                  configuration when different sessions register identical or
Packit fcad23
 *                  overlapping regions.  Subagents with no particular
Packit fcad23
 *                  knowledge of priority should register with the default
Packit fcad23
 *                  value of 127.
Packit fcad23
 *
Packit fcad23
 * @param range_subid  permits specifying a range in place of one of a subtree
Packit fcad23
 *                     sub-identifiers.  When this value is zero, no range is
Packit fcad23
 *                     being specified.
Packit fcad23
 *
Packit fcad23
 * @param range_ubound  the upper bound of a sub-identifier's range.
Packit fcad23
 *                      This field is present only if range_subid is not 0.
Packit fcad23
 *
Packit fcad23
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit fcad23
 * 
Packit fcad23
 * @see unregister_mib()
Packit fcad23
 * @see unregister_mib_priority()
Packit fcad23
 * @see unregister_mib_context()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
unregister_mib_range(oid * name, size_t len, int priority,
Packit fcad23
                     int range_subid, oid range_ubound)
Packit fcad23
{
Packit fcad23
    return unregister_mib_context(name, len, priority, range_subid,
Packit fcad23
                                  range_ubound, "");
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Unregisters a module registered against a given OID at the specified priority.
Packit fcad23
 * The priority parameter should match that used to register the module originally.
Packit fcad23
 *
Packit fcad23
 * @param name  the specific OID to unregister if it conatins the associated
Packit fcad23
 *              context.
Packit fcad23
 *
Packit fcad23
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit fcad23
 *
Packit fcad23
 * @param priority  a value between 1 and 255, used to achieve a desired
Packit fcad23
 *                  configuration when different sessions register identical or
Packit fcad23
 *                  overlapping regions.  Subagents with no particular
Packit fcad23
 *                  knowledge of priority should register with the default
Packit fcad23
 *                  value of 127.
Packit fcad23
 *
Packit fcad23
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit fcad23
 * 
Packit fcad23
 * @see unregister_mib()
Packit fcad23
 * @see unregister_mib_range()
Packit fcad23
 * @see unregister_mib_context()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
unregister_mib_priority(oid * name, size_t len, int priority)
Packit fcad23
{
Packit fcad23
    return unregister_mib_range(name, len, priority, 0, 0);
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Unregisters a module registered against a given OID at the default priority.
Packit fcad23
 *
Packit fcad23
 * @param name  the specific OID to unregister if it conatins the associated
Packit fcad23
 *              context.
Packit fcad23
 *
Packit fcad23
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit fcad23
 *
Packit fcad23
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit fcad23
 * 
Packit fcad23
 * @see unregister_mib_priority()
Packit fcad23
 * @see unregister_mib_context()
Packit fcad23
 * @see unregister_mib_range()
Packit fcad23
 * @see unregister_agentx_list()
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
unregister_mib(oid * name, size_t len)
Packit fcad23
{
Packit fcad23
    return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Unregisters subtree of OIDs bounded to given session.
Packit fcad23
 *
Packit fcad23
 *  @param ss Session which OIDs will be removed from tree.
Packit fcad23
 *
Packit fcad23
 *  @see unregister_mib()
Packit fcad23
 *  @see unregister_agentx_list()
Packit fcad23
 */
Packit fcad23
void
Packit fcad23
unregister_mibs_by_session(netsnmp_session * ss)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *list, *list2;
Packit fcad23
    netsnmp_subtree *child, *prev, *next_child;
Packit fcad23
    struct register_parameters rp;
Packit fcad23
    subtree_context_cache *contextptr;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
Packit fcad23
		ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
Packit fcad23
Packit fcad23
    for (contextptr = get_top_context_cache(); contextptr != NULL;
Packit fcad23
         contextptr = contextptr->next) {
Packit fcad23
        for (list = contextptr->first_subtree; list != NULL; list = list2) {
Packit fcad23
            list2 = list->next;
Packit fcad23
Packit fcad23
            for (child = list, prev = NULL; child != NULL; child = next_child){
Packit fcad23
                next_child = child->children;
Packit fcad23
Packit fcad23
                if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
Packit fcad23
		     child->session == ss) ||
Packit fcad23
                    (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
Packit fcad23
                     child->session->subsession == ss)) {
Packit fcad23
Packit fcad23
                    memset(&rp,0x0,sizeof(rp));
Packit fcad23
                    rp.name = child->name_a;
Packit fcad23
		    child->name_a = NULL;
Packit fcad23
                    rp.namelen = child->namelen;
Packit fcad23
                    rp.priority = child->priority;
Packit fcad23
                    rp.range_subid = child->range_subid;
Packit fcad23
                    rp.range_ubound = child->range_ubound;
Packit fcad23
                    rp.timeout = child->timeout;
Packit fcad23
                    rp.flags = child->flags;
Packit fcad23
                    if ((NULL != child->reginfo) &&
Packit fcad23
                        (NULL != child->reginfo->contextName))
Packit fcad23
                        rp.contextName = child->reginfo->contextName;
Packit fcad23
Packit fcad23
                    if (child->reginfo != NULL) {
Packit fcad23
                        /*
Packit fcad23
                         * Don't let's free the session pointer just yet!  
Packit fcad23
                         */
Packit fcad23
                        child->reginfo->handler->myvoid = NULL;
Packit fcad23
                        netsnmp_handler_registration_free(child->reginfo);
Packit fcad23
			child->reginfo = NULL;
Packit fcad23
                    }
Packit fcad23
Packit fcad23
                    netsnmp_subtree_unload(child, prev, contextptr->context_name);
Packit fcad23
                    netsnmp_subtree_free(child);
Packit fcad23
Packit fcad23
                    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                                        SNMPD_CALLBACK_UNREGISTER_OID, &rp);
Packit fcad23
		    SNMP_FREE(rp.name);
Packit fcad23
                } else {
Packit fcad23
                    prev = child;
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
        netsnmp_subtree_join(contextptr->first_subtree);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Determines if given PDU is allowed to see (or update) a given OID.
Packit fcad23
 *
Packit fcad23
 * @param name    The OID to check access for.
Packit fcad23
 *                On return, this parameter holds the OID actually matched
Packit fcad23
 *
Packit fcad23
 * @param namelen Number of sub-identifiers in the OID.
Packit fcad23
 *                On return, this parameter holds the length of the matched OID
Packit fcad23
 *
Packit fcad23
 * @param pdu     PDU requesting access to the OID.
Packit fcad23
 *
Packit fcad23
 * @param type    ANS.1 type of the value at given OID.
Packit fcad23
 *                (Used for catching SNMPv1 requests for SMIv2-only objects)
Packit fcad23
 *
Packit fcad23
 * @return gives VACM_SUCCESS if the OID is in the PDU, otherwise error code.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
Packit fcad23
{
Packit fcad23
    struct view_parameters view_parms;
Packit fcad23
Packit fcad23
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
Packit fcad23
	/* Enable bypassing of view-based access control */
Packit fcad23
        return VACM_SUCCESS;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * check for v1 and counter64s, since snmpv1 doesn't support it 
Packit fcad23
     */
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV1
Packit fcad23
    if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
Packit fcad23
        return VACM_NOTINVIEW;
Packit fcad23
    }
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    view_parms.pdu = pdu;
Packit fcad23
    view_parms.name = name;
Packit fcad23
    if (namelen != NULL) {
Packit fcad23
        view_parms.namelen = *namelen;
Packit fcad23
    } else {
Packit fcad23
        view_parms.namelen = 0;
Packit fcad23
    }
Packit fcad23
    view_parms.errorcode = 0;
Packit fcad23
    view_parms.check_subtree = 0;
Packit fcad23
Packit fcad23
    switch (pdu->version) {
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV1
Packit fcad23
    case SNMP_VERSION_1:
Packit fcad23
#endif
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit fcad23
    case SNMP_VERSION_2c:
Packit fcad23
#endif
Packit fcad23
   case SNMP_VERSION_3:
Packit fcad23
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
Packit fcad23
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                            SNMPD_CALLBACK_ACM_CHECK, &view_parms);
Packit fcad23
        return view_parms.errorcode;
Packit fcad23
    }
Packit fcad23
  unsupported_version:
Packit fcad23
    return VACM_NOSECNAME;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Determines if the given PDU request could potentially succeed.
Packit fcad23
 *  (Preliminary, OID-independent validation)
Packit fcad23
 *
Packit fcad23
 * @param pdu     PDU requesting access
Packit fcad23
 *
Packit fcad23
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
Packit fcad23
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
Packit fcad23
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
Packit fcad23
 *               other codes may returned on error
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
check_access(netsnmp_pdu *pdu)
Packit fcad23
{                               /* IN - pdu being checked */
Packit fcad23
    struct view_parameters view_parms;
Packit fcad23
    view_parms.pdu = pdu;
Packit fcad23
    view_parms.name = NULL;
Packit fcad23
    view_parms.namelen = 0;
Packit fcad23
    view_parms.errorcode = 0;
Packit fcad23
    view_parms.check_subtree = 0;
Packit fcad23
Packit fcad23
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
Packit fcad23
	/* Enable bypassing of view-based access control */
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    switch (pdu->version) {
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV1
Packit fcad23
    case SNMP_VERSION_1:
Packit fcad23
#endif
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit fcad23
    case SNMP_VERSION_2c:
Packit fcad23
#endif
Packit fcad23
    case SNMP_VERSION_3:
Packit fcad23
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
Packit fcad23
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                            SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
Packit fcad23
        return view_parms.errorcode;
Packit fcad23
    }
Packit fcad23
  unsupported_version:
Packit fcad23
    return 1;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Determines if the given PDU request could potentially access
Packit fcad23
 *   the specified MIB subtree
Packit fcad23
 *
Packit fcad23
 * @param pdu     PDU requesting access
Packit fcad23
 *
Packit fcad23
 * @param name    The OID to check access for.
Packit fcad23
 *
Packit fcad23
 * @param namelen Number of sub-identifiers in the OID.
Packit fcad23
 *
Packit fcad23
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
Packit fcad23
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
Packit fcad23
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
Packit fcad23
 *               other codes may returned on error
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
Packit fcad23
{                               /* IN - pdu being checked */
Packit fcad23
    struct view_parameters view_parms;
Packit fcad23
    view_parms.pdu = pdu;
Packit fcad23
    view_parms.name = name;
Packit fcad23
    view_parms.namelen = namelen;
Packit fcad23
    view_parms.errorcode = 0;
Packit fcad23
    view_parms.check_subtree = 1;
Packit fcad23
Packit fcad23
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
Packit fcad23
	/* Enable bypassing of view-based access control */
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    switch (pdu->version) {
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV1
Packit fcad23
    case SNMP_VERSION_1:
Packit fcad23
#endif
Packit fcad23
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit fcad23
    case SNMP_VERSION_2c:
Packit fcad23
#endif
Packit fcad23
    case SNMP_VERSION_3:
Packit fcad23
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
Packit fcad23
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit fcad23
                            SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
Packit fcad23
        return view_parms.errorcode;
Packit fcad23
    }
Packit fcad23
  unsupported_version:
Packit fcad23
    return 1;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(get_session_for_oid,netsnmp_unused)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID
Packit fcad23
netsnmp_session *
Packit fcad23
get_session_for_oid(const oid *name, size_t len, const char *context_name)
Packit fcad23
{
Packit fcad23
    netsnmp_subtree *myptr;
Packit fcad23
Packit fcad23
    myptr = netsnmp_subtree_find_prev(name, len, 
Packit fcad23
				      netsnmp_subtree_find_first(context_name),
Packit fcad23
				      context_name);
Packit fcad23
Packit fcad23
    while (myptr && myptr->variables == NULL) {
Packit fcad23
        myptr = myptr->next;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (myptr == NULL) {
Packit fcad23
        return NULL;
Packit fcad23
    } else {
Packit fcad23
        return myptr->session;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID */
Packit fcad23
Packit fcad23
void
Packit fcad23
setup_tree(void)
Packit fcad23
{
Packit fcad23
    oid ccitt[1]           = { 0 };
Packit fcad23
    oid iso[1]             = { 1 };
Packit fcad23
    oid joint_ccitt_iso[1] = { 2 };
Packit fcad23
Packit fcad23
#ifdef USING_AGENTX_SUBAGENT_MODULE
Packit fcad23
    int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
Packit fcad23
				       NETSNMP_DS_AGENT_ROLE);
Packit fcad23
Packit fcad23
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
Packit fcad23
			   MASTER_AGENT);
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    /* 
Packit fcad23
     * we need to have the oid's in the heap, that we can *free* it for every case, 
Packit fcad23
     * thats the purpose of the duplicate_objid's
Packit fcad23
     */
Packit fcad23
    netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
Packit fcad23
    netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
Packit fcad23
    netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
Packit fcad23
Packit fcad23
#ifdef USING_AGENTX_SUBAGENT_MODULE
Packit fcad23
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
Packit fcad23
			   role);
Packit fcad23
#endif
Packit fcad23
}
Packit fcad23
Packit fcad23
int 
Packit fcad23
remove_tree_entry (oid *name, size_t len) {
Packit fcad23
Packit fcad23
    netsnmp_subtree *sub = NULL;
Packit fcad23
Packit fcad23
    if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
Packit fcad23
	return MIB_NO_SUCH_REGISTRATION;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return unregister_mib_context(name, len, sub->priority,
Packit fcad23
				  sub->range_subid, sub->range_ubound, "");
Packit fcad23
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
void
Packit fcad23
shutdown_tree(void) {
Packit fcad23
    oid ccitt[1]           = { 0 };
Packit fcad23
    oid iso[1]             = { 1 };
Packit fcad23
    oid joint_ccitt_iso[1] = { 2 };
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("agent_registry", "shut down tree\n"));
Packit fcad23
Packit fcad23
    remove_tree_entry(joint_ccitt_iso, 1);
Packit fcad23
    remove_tree_entry(iso, 1);
Packit fcad23
    remove_tree_entry(ccitt, 1);
Packit fcad23
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
dump_registry(void)
Packit fcad23
{
Packit fcad23
    struct variable *vp = NULL;
Packit fcad23
    netsnmp_subtree *myptr, *myptr2;
Packit fcad23
    u_char *s = NULL, *e = NULL, *v = NULL;
Packit fcad23
    size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
Packit fcad23
    int i = 0;
Packit fcad23
Packit fcad23
    if ((s = (u_char *) calloc(sl, 1)) != NULL &&
Packit fcad23
        (e = (u_char *) calloc(sl, 1)) != NULL &&
Packit fcad23
        (v = (u_char *) calloc(sl, 1)) != NULL) {
Packit fcad23
Packit fcad23
        subtree_context_cache *ptr;
Packit fcad23
        for (ptr = context_subtrees; ptr; ptr = ptr->next) {
Packit fcad23
            printf("Subtrees for Context: %s\n", ptr->context_name);
Packit fcad23
            for (myptr = ptr->first_subtree; myptr != NULL;
Packit fcad23
                 myptr = myptr->next) {
Packit fcad23
                sl_o = el_o = vl_o = 0;
Packit fcad23
Packit fcad23
                if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
Packit fcad23
                                          myptr->start_a,
Packit fcad23
                                          myptr->start_len)) {
Packit fcad23
                    break;
Packit fcad23
                }
Packit fcad23
                if (!sprint_realloc_objid(&e, &el, &el_o, 1,
Packit fcad23
                                          myptr->end_a,
Packit fcad23
					  myptr->end_len)) {
Packit fcad23
                    break;
Packit fcad23
                }
Packit fcad23
Packit fcad23
                if (myptr->variables) {
Packit fcad23
                    printf("%02x ( %s - %s ) [", myptr->flags, s, e);
Packit fcad23
                    for (i = 0, vp = myptr->variables;
Packit fcad23
                         i < myptr->variables_len; i++) {
Packit fcad23
                        vl_o = 0;
Packit fcad23
                        if (!sprint_realloc_objid
Packit fcad23
                            (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
Packit fcad23
                            break;
Packit fcad23
                        }
Packit fcad23
                        printf("%s, ", v);
Packit fcad23
                        vp = (struct variable *) ((char *) vp +
Packit fcad23
                                                  myptr->variables_width);
Packit fcad23
                    }
Packit fcad23
                    printf("]\n");
Packit fcad23
                } else {
Packit fcad23
                    printf("%02x   %s - %s  \n", myptr->flags, s, e);
Packit fcad23
                }
Packit fcad23
                for (myptr2 = myptr; myptr2 != NULL;
Packit fcad23
                     myptr2 = myptr2->children) {
Packit fcad23
                    if (myptr2->label_a && myptr2->label_a[0]) {
Packit fcad23
                        if (strcmp(myptr2->label_a, "old_api") == 0) {
Packit fcad23
                            struct variable *vp =
Packit fcad23
                                (struct variable*)myptr2->reginfo->handler->myvoid;
Packit fcad23
Packit fcad23
                            if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
Packit fcad23
                                                 vp->name, vp->namelen)) {
Packit fcad23
                                continue;
Packit fcad23
                            }
Packit fcad23
                            printf("\t%s[%s] %p var %s\n", myptr2->label_a,
Packit fcad23
                                   myptr2->reginfo->handlerName ?
Packit fcad23
                                   myptr2->reginfo->handlerName : "no-name",
Packit fcad23
                                   myptr2->reginfo, s);
Packit fcad23
                        } else {
Packit fcad23
                            printf("\t%s %s %p\n", myptr2->label_a,
Packit fcad23
                                   myptr2->reginfo->handlerName ?
Packit fcad23
                                   myptr2->reginfo->handlerName : "no-handler-name",
Packit fcad23
                                   myptr2->reginfo);
Packit fcad23
                        }
Packit fcad23
                    }
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    SNMP_FREE(s);
Packit fcad23
    SNMP_FREE(e);
Packit fcad23
    SNMP_FREE(v);
Packit fcad23
Packit fcad23
    dump_idx_registry();
Packit fcad23
}
Packit fcad23
Packit fcad23
/**  @} */
Packit fcad23
/* End of MIB registration code */
Packit fcad23
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(register_signal, netsnmp_unused)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL
Packit fcad23
Packit fcad23
/** @defgroup agent_signals POSIX signals support for agents.
Packit fcad23
 *     Registering and unregistering signal handlers.
Packit fcad23
 *   @ingroup agent_registry
Packit fcad23
 *
Packit fcad23
 * @{
Packit fcad23
 */
Packit fcad23
Packit fcad23
int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
Packit fcad23
void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
Packit fcad23
Packit fcad23
#ifndef WIN32
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
Packit fcad23
 *       below for every single that might be handled by register_signal().
Packit fcad23
 */
Packit fcad23
Packit fcad23
RETSIGTYPE
Packit fcad23
agent_SIGCHLD_handler(int sig)
Packit fcad23
{
Packit fcad23
    external_signal_scheduled[SIGCHLD]++;
Packit fcad23
#ifndef HAVE_SIGACTION
Packit fcad23
    /*
Packit fcad23
     * signal() sucks. It *might* have SysV semantics, which means that
Packit fcad23
     * * a signal handler is reset once it gets called. Ensure that it
Packit fcad23
     * * remains active.
Packit fcad23
     */
Packit fcad23
    signal(SIGCHLD, agent_SIGCHLD_handler);
Packit fcad23
#endif
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Registers a POSIX Signal handler.
Packit fcad23
 *  Implements the signal registering process for POSIX and non-POSIX
Packit fcad23
 *  systems. Also, unifies the way signals work.
Packit fcad23
 *  Note that the signal handler should register itself again with
Packit fcad23
 *  signal() call before end of execution to prevent possible problems.
Packit fcad23
 *
Packit fcad23
 *  @param sig POSIX Signal ID number, as defined in signal.h.
Packit fcad23
 *
Packit fcad23
 *  @param func New signal handler function.
Packit fcad23
 *
Packit fcad23
 *  @return value is SIG_REGISTERED_OK for success and
Packit fcad23
 *        SIG_REGISTRATION_FAILED if the registration can't
Packit fcad23
 *        be handled.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
register_signal(int sig, void (*func) (int))
Packit fcad23
{
Packit fcad23
Packit fcad23
    switch (sig) {
Packit fcad23
#if defined(SIGCHLD)
Packit fcad23
    case SIGCHLD:
Packit fcad23
#ifdef HAVE_SIGACTION
Packit fcad23
        {
Packit fcad23
            static struct sigaction act;
Packit fcad23
            act.sa_handler = agent_SIGCHLD_handler;
Packit fcad23
            sigemptyset(&act.sa_mask);
Packit fcad23
            act.sa_flags = 0;
Packit fcad23
            sigaction(SIGCHLD, &act, NULL);
Packit fcad23
        }
Packit fcad23
#else
Packit fcad23
        signal(SIGCHLD, agent_SIGCHLD_handler);
Packit fcad23
#endif
Packit fcad23
        break;
Packit fcad23
#endif
Packit fcad23
    default:
Packit fcad23
        snmp_log(LOG_CRIT,
Packit fcad23
                 "register_signal: signal %d cannot be handled\n", sig);
Packit fcad23
        return SIG_REGISTRATION_FAILED;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    external_signal_handler[sig] = func;
Packit fcad23
    external_signal_scheduled[sig] = 0;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
Packit fcad23
    return SIG_REGISTERED_OK;
Packit fcad23
}
Packit fcad23
Packit fcad23
/** Unregisters a POSIX Signal handler.
Packit fcad23
 *
Packit fcad23
 *  @param sig POSIX Signal ID number, as defined in signal.h.
Packit fcad23
 *
Packit fcad23
 *  @return value is SIG_UNREGISTERED_OK for success, or error code.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
unregister_signal(int sig)
Packit fcad23
{
Packit fcad23
    signal(sig, SIG_DFL);
Packit fcad23
    DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
Packit fcad23
    return SIG_UNREGISTERED_OK;
Packit fcad23
}
Packit fcad23
Packit fcad23
#endif                          /* !WIN32 */
Packit fcad23
Packit fcad23
/**  @} */
Packit fcad23
/* End of signals support code */
Packit fcad23
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL */
Packit fcad23
Packit fcad23
/**  @} */
Packit fcad23