| /* |
| * 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")); |
| netsnmp_access_ipaddress_entry_free(entry); |
| } |
| |
| 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 %d\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"); |
| 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; |
| } |
| |
| 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 (bits) { |
| u_char mask = (0xff >> bits); |
| |
| dst[bytes] = (src[bytes] & mask); |
| } |
| |
| if (bytes < addr_len) |
| memset(&dst[bytes],0x0, addr_len - bytes); |
| |
| return pfx_len; |
| } |
| |
| |
| /** |
| * copy the prefix portion of an ip address |
| * |
| * @param mask network byte order make |
| * |
| * @returns number of prefix bits |
| */ |
| int |
| netsnmp_ipaddress_ipv4_prefix_len(in_addr_t mask) |
| { |
| int len = 0; |
| |
| while((0xff000000 & mask) == 0xff000000) { |
| len += 8; |
| mask = mask << 8; |
| } |
| |
| while(0x80000000 & mask) { |
| ++len; |
| mask = mask << 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); |
| } |