blob: ac62c40591bbacd3fb1549cf08e8104f3e3c1687 [file] [log] [blame]
/*
* Ipaddress MIB architecture support
*
* $Id$
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/data_access/ipaddress.h>
#include <net-snmp/data_access/interface.h>
#include "ip-mib/ipAddressTable/ipAddressTable_constants.h"
/**---------------------------------------------------------------------*/
/*
* local static prototypes
*/
static int _access_ipaddress_entry_compare_addr(const void *lhs,
const void *rhs);
static void _access_ipaddress_entry_release(netsnmp_ipaddress_entry * entry,
void *unused);
/**---------------------------------------------------------------------*/
/*
* external per-architecture functions prototypes
*
* These shouldn't be called by the general public, so they aren't in
* the header file.
*/
extern int
netsnmp_arch_ipaddress_container_load(netsnmp_container* container,
u_int load_flags);
extern int
netsnmp_arch_ipaddress_entry_init(netsnmp_ipaddress_entry *entry);
extern int
netsnmp_arch_ipaddress_entry_copy(netsnmp_ipaddress_entry *lhs,
netsnmp_ipaddress_entry *rhs);
extern void
netsnmp_arch_ipaddress_entry_cleanup(netsnmp_ipaddress_entry *entry);
extern int
netsnmp_arch_ipaddress_create(netsnmp_ipaddress_entry *entry);
extern int
netsnmp_arch_ipaddress_delete(netsnmp_ipaddress_entry *entry);
/**---------------------------------------------------------------------*/
/*
* container functions
*/
/**
*/
netsnmp_container *
netsnmp_access_ipaddress_container_init(u_int flags)
{
netsnmp_container *container1;
DEBUGMSGTL(("access:ipaddress:container", "init\n"));
/*
* create the containers. one indexed by ifIndex, the other
* indexed by ifName.
*/
container1 = netsnmp_container_find("access_ipaddress:table_container");
if (NULL == container1) {
snmp_log(LOG_ERR, "ipaddress primary container not found\n");
return NULL;
}
container1->container_name = strdup("ia_index");
if (flags & NETSNMP_ACCESS_IPADDRESS_INIT_ADDL_IDX_BY_ADDR) {
netsnmp_container *container2 =
netsnmp_container_find("ipaddress_addr:access_ipaddress:table_container");
if (NULL == container2) {
snmp_log(LOG_ERR, "ipaddress secondary container not found\n");
CONTAINER_FREE(container1);
return NULL;
}
container2->compare = _access_ipaddress_entry_compare_addr;
container2->container_name = strdup("ia_addr");
netsnmp_container_add_index(container1, container2);
}
return container1;
}
/**
* @retval NULL error
* @retval !NULL pointer to container
*/
netsnmp_container*
netsnmp_access_ipaddress_container_load(netsnmp_container* container,
u_int load_flags)
{
int rc;
u_int container_flags = 0;
DEBUGMSGTL(("access:ipaddress:container", "load\n"));
if (NULL == container) {
if (load_flags & NETSNMP_ACCESS_IPADDRESS_LOAD_ADDL_IDX_BY_ADDR)
container_flags |= NETSNMP_ACCESS_IPADDRESS_INIT_ADDL_IDX_BY_ADDR;
container = netsnmp_access_ipaddress_container_init(container_flags);
}
if (NULL == container) {
snmp_log(LOG_ERR, "no container specified/found for access_ipaddress\n");
return NULL;
}
rc = netsnmp_arch_ipaddress_container_load(container, load_flags);
if (0 != rc) {
netsnmp_access_ipaddress_container_free(container,
NETSNMP_ACCESS_IPADDRESS_FREE_NOFLAGS);
container = NULL;
}
return container;
}
void
netsnmp_access_ipaddress_container_free(netsnmp_container *container, u_int free_flags)
{
DEBUGMSGTL(("access:ipaddress:container", "free\n"));
if (NULL == container) {
snmp_log(LOG_ERR, "invalid container for netsnmp_access_ipaddress_free\n");
return;
}
if(! (free_flags & NETSNMP_ACCESS_IPADDRESS_FREE_DONT_CLEAR)) {
/*
* free all items.
*/
CONTAINER_CLEAR(container,
(netsnmp_container_obj_func*)_access_ipaddress_entry_release,
NULL);
}
if(! (free_flags & NETSNMP_ACCESS_IPADDRESS_FREE_KEEP_CONTAINER))
CONTAINER_FREE(container);
}
/**---------------------------------------------------------------------*/
/*
* ipaddress_entry functions
*/
/**
*/
/**
*/
netsnmp_ipaddress_entry *
netsnmp_access_ipaddress_entry_create(void)
{
netsnmp_ipaddress_entry *entry =
SNMP_MALLOC_TYPEDEF(netsnmp_ipaddress_entry);
int rc = 0;
entry->oid_index.len = 1;
entry->oid_index.oids = &entry->ns_ia_index;
/*
* set up defaults
*/
entry->ia_type = IPADDRESSTYPE_UNICAST;
entry->ia_status = IPADDRESSSTATUSTC_PREFERRED;
entry->ia_storagetype = STORAGETYPE_VOLATILE;
rc = netsnmp_arch_ipaddress_entry_init(entry);
if (SNMP_ERR_NOERROR != rc) {
DEBUGMSGT(("access:ipaddress:create","error %d in arch init\n", rc));
netsnmp_access_ipaddress_entry_free(entry);
entry = NULL;
}
return entry;
}
/**
*/
void
netsnmp_access_ipaddress_entry_free(netsnmp_ipaddress_entry * entry)
{
if (NULL == entry)
return;
if (NULL != entry->arch_data)
netsnmp_arch_ipaddress_entry_cleanup(entry);
free(entry);
}
/**
* update underlying data store (kernel) for entry
*
* @retval 0 : success
* @retval -1 : error
*/
int
netsnmp_access_ipaddress_entry_set(netsnmp_ipaddress_entry * entry)
{
int rc = SNMP_ERR_NOERROR;
if (NULL == entry) {
netsnmp_assert(NULL != entry);
return -1;
}
/*
* make sure interface and ifIndex match up
*/
if (NULL == netsnmp_access_interface_name_find(entry->if_index)) {
DEBUGMSGT(("access:ipaddress:set", "cant find name for index %ld\n",
entry->if_index));
return -1;
}
/*
* don't support non-volatile yet
*/
if (STORAGETYPE_VOLATILE != entry->ia_storagetype) {
DEBUGMSGT(("access:ipaddress:set",
"non-volatile storagetypes unsupported\n"));
return -1;
}
/*
*
*/
rc = -1;
if (entry->flags & NETSNMP_ACCESS_IPADDRESS_CREATE) {
rc = netsnmp_arch_ipaddress_create(entry);
}
else if (entry->flags & NETSNMP_ACCESS_IPADDRESS_CHANGE) {
}
else if (entry->flags & NETSNMP_ACCESS_IPADDRESS_DELETE) {
rc = netsnmp_arch_ipaddress_delete(entry);
}
else {
snmp_log(LOG_ERR,"netsnmp_access_ipaddress_entry_set with no mode\n");
netsnmp_assert(!"ipaddress_entry_set == unknown mode"); /* always false */
rc = -1;
}
return rc;
}
/**
* update an old ipaddress_entry from a new one
*
* @note: only mib related items are compared. Internal objects
* such as oid_index, ns_ia_index and flags are not compared.
*
* @retval -1 : error
* @retval >=0 : number of fields updated
*/
int
netsnmp_access_ipaddress_entry_update(netsnmp_ipaddress_entry *lhs,
netsnmp_ipaddress_entry *rhs)
{
int rc, changed = 0;
/*
* copy arch stuff. we don't care if it changed
*/
rc = netsnmp_arch_ipaddress_entry_copy(lhs,rhs);
if (0 != rc) {
snmp_log(LOG_ERR,"arch ipaddress copy failed\n");
return -1;
}
if (lhs->if_index != rhs->if_index) {
++changed;
lhs->if_index = rhs->if_index;
}
if (lhs->ia_storagetype != rhs->ia_storagetype) {
++changed;
lhs->ia_storagetype = rhs->ia_storagetype;
}
if (lhs->ia_address_len != rhs->ia_address_len) {
changed += 2;
lhs->ia_address_len = rhs->ia_address_len;
memcpy(lhs->ia_address, rhs->ia_address, rhs->ia_address_len);
}
else if (memcmp(lhs->ia_address, rhs->ia_address, rhs->ia_address_len) != 0) {
++changed;
memcpy(lhs->ia_address, rhs->ia_address, rhs->ia_address_len);
}
if (lhs->ia_type != rhs->ia_type) {
++changed;
lhs->ia_type = rhs->ia_type;
}
if (lhs->ia_status != rhs->ia_status) {
++changed;
lhs->ia_status = rhs->ia_status;
}
if (lhs->ia_origin != rhs->ia_origin) {
++changed;
lhs->ia_origin = rhs->ia_origin;
}
if (lhs->ia_onlink_flag != rhs->ia_onlink_flag) {
++changed;
lhs->ia_onlink_flag = rhs->ia_onlink_flag;
}
if (lhs->ia_autonomous_flag != rhs->ia_autonomous_flag) {
++changed;
lhs->ia_autonomous_flag = rhs->ia_autonomous_flag;
}
if (lhs->ia_prefered_lifetime != rhs->ia_prefered_lifetime) {
++changed;
lhs->ia_prefered_lifetime = rhs->ia_prefered_lifetime;
}
if (lhs->ia_valid_lifetime != rhs->ia_valid_lifetime) {
++changed;
lhs->ia_valid_lifetime = rhs->ia_valid_lifetime;
}
return changed;
}
/**
* copy an ipaddress_entry
*
* @retval -1 : error
* @retval 0 : no error
*/
int
netsnmp_access_ipaddress_entry_copy(netsnmp_ipaddress_entry *lhs,
netsnmp_ipaddress_entry *rhs)
{
int rc;
/*
* copy arch stuff. we don't care if it changed
*/
rc = netsnmp_arch_ipaddress_entry_copy(lhs,rhs);
if (0 != rc) {
snmp_log(LOG_ERR,"arch ipaddress copy failed\n");
return -1;
}
lhs->if_index = rhs->if_index;
lhs->ia_storagetype = rhs->ia_storagetype;
lhs->ia_address_len = rhs->ia_address_len;
memcpy(lhs->ia_address, rhs->ia_address, rhs->ia_address_len);
lhs->ia_type = rhs->ia_type;
lhs->ia_status = rhs->ia_status;
lhs->ia_origin = rhs->ia_origin;
return 0;
}
/**---------------------------------------------------------------------*/
/*
* Utility routines
*/
/**
* copy the prefix portion of an ip address
*/
int
netsnmp_ipaddress_prefix_copy(u_char *dst, u_char *src, int addr_len, int pfx_len)
{
int bytes = pfx_len / 8;
int bits = pfx_len % 8;
if ((NULL == dst) || (NULL == src) || (0 == pfx_len))
return 0;
memcpy(dst, src, bytes);
if (bytes < addr_len)
memset(&dst[bytes],0x0, addr_len - bytes);
if (bits) {
u_char mask = (0xff << (8-bits));
dst[bytes] = (src[bytes] & mask);
}
return pfx_len;
}
/**
* Compute the prefix length of a network mask
*
* @param mask network byte order mask
*
* @returns number of prefix bits
*/
int
netsnmp_ipaddress_ipv4_prefix_len(in_addr_t mask)
{
int i, len = 0;
unsigned char *mp = (unsigned char *)&mask;
for (i = 0; i < 4; i++)
if (mp[i] == 0xFF) len += 8;
else break;
if (i == 4)
return len;
while(0x80 & mp[i]) {
++len;
mp[i] <<= 1;
}
return len;
}
/**
*/
void
_access_ipaddress_entry_release(netsnmp_ipaddress_entry * entry, void *context)
{
netsnmp_access_ipaddress_entry_free(entry);
}
static int _access_ipaddress_entry_compare_addr(const void *lhs,
const void *rhs)
{
const netsnmp_ipaddress_entry *lh = (const netsnmp_ipaddress_entry *)lhs;
const netsnmp_ipaddress_entry *rh = (const netsnmp_ipaddress_entry *)rhs;
netsnmp_assert(NULL != lhs);
netsnmp_assert(NULL != rhs);
/*
* compare address length
*/
if (lh->ia_address_len < rh->ia_address_len)
return -1;
else if (lh->ia_address_len > rh->ia_address_len)
return 1;
/*
* length equal, compare address
*/
return memcmp(lh->ia_address, rh->ia_address, lh->ia_address_len);
}
int
netsnmp_ipaddress_flags_copy(u_long *ipAddressPrefixAdvPreferredLifetime,
u_long *ipAddressPrefixAdvValidLifetime,
u_long *ipAddressPrefixOnLinkFlag,
u_long *ipAddressPrefixAutonomousFlag,
u_long *ia_prefered_lifetime,
u_long *ia_valid_lifetime,
u_char *ia_onlink_flag,
u_char *ia_autonomous_flag)
{
/*Copy all the flags*/
*ipAddressPrefixAdvPreferredLifetime = *ia_prefered_lifetime;
*ipAddressPrefixAdvValidLifetime = *ia_valid_lifetime;
*ipAddressPrefixOnLinkFlag = *ia_onlink_flag;
*ipAddressPrefixAutonomousFlag = *ia_autonomous_flag;
return 0;
}
int
netsnmp_ipaddress_prefix_origin_copy(u_long *ipAddressPrefixOrigin,
u_char ia_origin,
int flags,
u_long ipAddressAddrType)
{
if(ipAddressAddrType == INETADDRESSTYPE_IPV4){
if(ia_origin == 6) /*Random*/
(*ipAddressPrefixOrigin) = 3 /*IPADDRESSPREFIXORIGINTC_WELLKNOWN*/;
else
(*ipAddressPrefixOrigin) = ia_origin;
} else {
if(ia_origin == 5) { /*Link Layer*/
if(!flags) /*Global address assigned by router adv*/
(*ipAddressPrefixOrigin) = 5 /*IPADDRESSPREFIXORIGINTC_ROUTERADV*/;
else
(*ipAddressPrefixOrigin) = 3 /*IPADDRESSPREFIXORIGINTC_WELLKNOWN*/;
}
else if(ia_origin == 6) /*Random*/
(*ipAddressPrefixOrigin) = 5 /*IPADDRESSPREFIXORIGINTC_ROUTERADV*/;
else
(*ipAddressPrefixOrigin) = ia_origin;
}
return 0;
}