/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6pm_attr.c,v $ $Revision: 1.22 $ * $Source: /home/interpeak/CVSRoot/ipmip6pm/src/ipmip6pm_attr.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6pm_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipmip6pm_h.h" #include "ipmip6pm_attr.h" #include "ipmip6pm_attr_h.h" #include "ipmip6pm_node.h" #include "ipmip6pm_if.h" #include "ipmip6pm_mh.h" #include "ipmip6pm_route.h" #include "ipmip6pm_lma.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ struct Ipmip6pm_attr_op { Ipmip_cli_message_t *request; Ipmip6pm_node_lookup_t nargs; }; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ const char *ipmip6pm_attr_status_desc[IPMIP6PM_CLI_ATTR_BC_P_STATUS_MAX] = { "created", "pending", "retransmit", "timeout", "error", "deleted", "registered", "running" }; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmipfa_node_del_cb *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipmip6pm_attr_list_nodes(Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip6pm_node_t *node, struct Ipmip6pm_attr_op *ops, void *unused) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(unused); /* Match NAI */ if (ops->nargs.nai_mn != IP_NULL && ops->nargs.nai_mn_len > 0) { if (!ipmip_util_strnncmp(ops->nargs.nai_mn, ops->nargs.nai_mn_len, (char *)&node->mo_nai_mn->nai[0], node->mo_nai_mn->hdr.len - 1)) return; } if (!ipmip6pm_node_compare(node, &ops->nargs)) return; /* Add this node */ ipmip_attr_put_u32(&ops->request->message, IPMIP6PM_CLI_ATTR_BC_P_HANDLE, node->identity); } IP_STATIC void ipmip6pm_attr_build_lookup(Ipmip6pm_node_lookup_t *nargs, struct Ipmip_attr **idattr) { /* NAI */ if (idattr[IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI] != IP_NULL) { nargs->nai_mn = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI]); nargs->nai_mn_len = ipmip_util_strnlen(nargs->nai_mn, IPMIP_ATTR_PAYLOAD(idattr[IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI])); } if (idattr[IPMIP6PM_CLI_ATTR_BC_P_IFIDENT] != IP_NULL) { nargs->args.lladdr = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_IFIDENT]); nargs->args.lladdr_len = IPMIP_ATTR_PAYLOAD(idattr[IPMIP6PM_CLI_ATTR_BC_P_IFIDENT]); IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_LLADDR); } if (idattr[IPMIP6PM_CLI_ATTR_BC_P_IFNAME] != IP_NULL) { nargs->args.ifname = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_IFNAME]); IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_IFNAME); } if (idattr[IPMIP6PM_CLI_ATTR_BC_P_ACCESS_TYPE] != IP_NULL) { nargs->args.access_type = ipmip_attr_get_u32(idattr[IPMIP6PM_CLI_ATTR_BC_P_ACCESS_TYPE]); IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_ACCESS_TYPE); } if (idattr[IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST] != IP_NULL) { nargs->args.home_prefix = IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST]); nargs->args.home_prefix_size = IPMIP_ATTR_PAYLOAD(idattr[IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST]) / sizeof(Ipmip6_address_t); IP_BIT_SET(nargs->search_params, IPMIP6PM_NODE_LOOKUP_HOME_PREFIX); } } IP_STATIC int ipmip6pm_attr_node_dump(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip_cli_message_t *request, Ipmip6pm_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr = 0; Ip_size_t rta; Ip_size_t rta_sub; if (node == IP_NULL) rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_ENOENT, IP_NULL); else { /* Do retrieve statistics */ ipmip6pm_netlink_get_handle_stat(ctx, proc, node); switch (IPMIP_ATTR_HDR_TYPE(hdr)) { case IPMIP6PM_CLI_BC_P_GET: { Ip_u32 f, i; /**/ rhdr = ipmip_attr_hdr_ack(&request->message, hdr); rta = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P); /* Put the home address entry */ ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_IFNAME, node->ifp_private.ipmip6.ifp->iff.ifname); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_COA_IFNAME, node->ifp_public->ipmip6.iff.ifname); /* Add the MO for MN NAI */ ipmip_attr_put_strn(&request->message, IPMIP6PM_CLI_ATTR_BC_P_MOBILE_NAI, (char *)&node->mo_nai_mn->nai[0], node->mo_nai_mn->hdr.len - 1); ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_ACCESS_TYPE, node->mo_access_type->att); ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HANDOFF_INDICATOR, node->mo_handoff_indicator->hi); ipmip_attr_put_inet6(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT, &node->homeagent); ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_TUNNEL_TYPE, node->transport_tunnel_type); ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HANDLE, node->identity); ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_TRANSPORT_MASK, node->supported_tunnel_types); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_TUNNEL_IFNAME, node->ifp_public->iftunnels[node->transport_tunnel_type]->ipmip6.iff.ifname); /* We're GRE */ if (IPMIP_TUNNELTYPE_IS_GRE(node->transport_tunnel_type)) { rta_sub = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_GRE); if (IPMIP6PM_NODE_USE_GRE_KEYS(node)) { Ip_size_t off = ipmip_buffer_append(&request->message, IP_NULL, sizeof(Ip_u32) * 2); Ip_u32 *v = ipmip_buffer_offset(&request->message, off); IP_SET_HTONL(&v[0], node->gre_key[0]); IP_SET_HTONL(&v[1], node->gre_key[1]); } ipmip_attr_end(&request->message, rta_sub); } if (IPMIP6PM_NODE_HOMEAGENT_INET(node)) { ipmip_attr_put_inet(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT_INET, IPMIP6PM_NODE_HOMEAGENT_INET(node)); } /* */ if (node->mo_link_layer_id) { ipmip_attr_put(&request->message, IPMIP6PM_CLI_ATTR_BC_P_IFIDENT, node->mo_link_layer_id->hdr.len - 2, &node->mo_link_layer_id->lli[0]); } /* Send the LLA if it exists */ if (node->lla) { ipmip_attr_put(&request->message, IPMIP6PM_CLI_ATTR_BC_P_IFLLA, node->lla->len, node->lla); } ipmip_attr_put_time_t(&request->message, IPMIP6PM_CLI_ATTR_BC_P_CREATED, node->created); ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_STATUS, node->status); rta_sub = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HOME_PREFIX_LIST); for (i = 0; i < node->mo_home_prefix_size; i++) { Ipmip6_address_t addr; ipcom_memcpy(&addr.prefix, &node->mo_home_prefix[i].prefix, sizeof(addr.prefix)); addr.len = node->mo_home_prefix[i].prefix_length; ipmip_buffer_append(&request->message, &addr, sizeof(addr)); } ipmip_attr_end(&request->message, rta_sub); #ifdef IPMIP_USE_INET if (node->mo_dsmipv6_home_prefix.prefix != 0) { ipmip_attr_put(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HOME_ADDRESS_INET, sizeof(node->mo_dsmipv6_home_prefix), &node->mo_dsmipv6_home_prefix); } #endif /**/ ipmip_attr_put(&request->message, IPMIP6PM_CLI_ATTR_BC_P_MIB_mip6MnBLTable, sizeof(node->mip6MnBLTable), &node->mip6MnBLTable); ipmip_attr_put(&request->message, IPMIP6PM_CLI_ATTR_BC_P_MIB_mip6NodeTrafficEntry, sizeof(node->mip6NodeTrafficEntry), &node->mip6NodeTrafficEntry); /* */ if (node->ifp_private.ipmip6.ifp->iff.lladdr) { ipmip_attr_put(&request->message, IPMIP6PM_CLI_ATTR_BC_P_MAG_Link_Layer, IPMIP_LLADDR_LEN(node->ifp_private.ipmip6.ifp->iff.lladdr), node->ifp_private.ipmip6.ifp->iff.lladdr); } for (f = 0; f < IPMIP6PM_FUNCTION_MAX; f++) { for (i = 0; i < ctx->extensions[f].num; i++) { if ((node->supported[f] & (1 << i)) && ctx->extensions[f].functions[i]->setup != IP_NULL) (*ctx->extensions[f].functions[i]->setup) (ctx, proc, IPMIP_CALLBACK_CONFIG_DUMP, ctx->extdata[f][i], node->ifp_public->extdata[f][i], node->extdata[f][i], node, IP_NULL, request); } } ipmip_attr_end(&request->message, rta); } break; } } /* If we have a reply header; terminate it */ ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request); } else { /* Free the request */ ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request); } /**/ return IPMIP_TIMER_RET_DONE; } /* *=========================================================================== * ipmip6pm_attr_node_create *=========================================================================== * Description: Create a node * Parameters: event - Current event * data - Data * proc - Current process * lock - Command locking structure * node - Node. * Returns: IP_FALSE * */ IP_STATIC int ipmip6pm_attr_node_create(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip_cli_message_t *request, Ipmip6pm_node_t *node) { int ret = IPCOM_SUCCESS; if (event == IPMIP_TIMER_EVENT_RUN) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr = 0; struct Ipmip_attr *idattr[IPMIP6PM_CLI_ATTR_BC_P_MAX + 1]; Ipmip6pm_node_lookup_t nargs; Ipmip6pm_node_t *head = node; Ipmip6pm_node_t *mnode = IP_NULL; Ip_u8 hi = IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_UNKNOWN; Ip_u32 identity = 0; ipcom_memset(&nargs, 0, sizeof(nargs)); /* parse it */ ipmip_attr_hdr_parse(IPMIP6PM_CLI_ATTR_BC_P_MAX, hdr, idattr); ipmip6pm_attr_build_lookup(&nargs, idattr); /* Need to determine HI */ if (idattr[IPMIP6PM_CLI_ATTR_BC_P_HANDOFF_INDICATOR]) hi = (Ip_u8)ipmip_attr_get_u32(idattr[IPMIP6PM_CLI_ATTR_BC_P_HANDOFF_INDICATOR]); if (node) { switch (hi) { case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_DIFFERENT_INTERFACE: { if (head->next != IP_NULL) { IPMIP6_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Ambigous specifiers for 'different interface' handover indication for node %s", ipmip6pm_node_describe(proc, node))); /* Unable to determine what node we're dealing with */ ret = -IP_ERRNO_EEXIST; goto error_out; } mnode = head; } break; case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_UNKNOWN: case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_SAME_INTERFACE_NEW_MAG: case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NEW_INTERFACE: { /* New interface? We need to match this and verify that nothing we currently have * matches it */ /* Attached IFINDEX may not be enough to identify */ nargs.search_params &= ~IPMIP6PM_NODE_LOOKUP_IFNAME; while (node != IP_NULL) { if (ipmip6pm_node_compare(node, &nargs)) { ret = -IP_ERRNO_EEXIST; IPMIP6_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Ambigous specifiers for 'unknown/new/same interface' handover indication for node %s", ipmip6pm_node_describe(proc, node))); goto error_out; } node = node->next; } } break; case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NOT_CHANGED: IPMIP6_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Invalid 'not changed' handover indication for node %s", ipmip6pm_node_describe(proc, node))); /* FALL THROUGH */ default: ret = -IP_ERRNO_EINVAL; goto error_out; } } else { switch (hi) { case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_DIFFERENT_INTERFACE: case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_UNKNOWN: case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_SAME_INTERFACE_NEW_MAG: case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NEW_INTERFACE: break; case IPMIP6_MH_MO_PMIPV6_HANDOFF_INDICATOR_NOT_CHANGED: IPMIP6_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Invalid 'not changed' handover indication for new node")); /* FALL THROUGH */ default: ret = -IP_ERRNO_EINVAL; goto error_out; } } if (mnode) { identity = mnode->identity; ret = ipmip6pm_node_handoff(ctx, proc, mnode, hi, idattr); } else { ret = ipmip6pm_node_create(ctx, proc, head, hi, hdr, idattr, &identity); } error_out: if (ret < 0) rhdr = ipmip_attr_hdr_err(&request->message, hdr, -ret, IP_NULL); else { rhdr = ipmip_attr_hdr_ack(&request->message, hdr); /* Return the Identity */ ipmip_attr_put_u32(&request->message, IPMIP6PM_CLI_ATTR_BC_P_HANDLE, identity); } /* If we have a reply header; terminate it */ ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request); } else { /* Free the request */ ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request); } /**/ return ret <= 0? IPMIP_TIMER_RET_DONE : ret; } /* *=========================================================================== * ipmip6pm_attr_node_delete *=========================================================================== * Description: Create a node * Parameters: event - Current event * data - Data * proc - Current process * lock - Command locking structure * node - Node. * Returns: IP_FALSE * */ IP_STATIC int ipmip6pm_attr_node_delete(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip_cli_message_t *request, Ipmip6pm_node_t *node) { int ret = IPMIP_TIMER_RET_DONE; if (event == IPMIP_TIMER_EVENT_RUN) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr = 0; Ip_u16 reqtype = IPMIP_ATTR_HDR_TYPE(hdr); if (node == IP_NULL) rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_ENOENT, IP_NULL); else { /* If we have a reply header; terminate it */ rhdr = ipmip_attr_hdr_ack(&request->message, hdr); switch (reqtype) { case IPMIP6PM_CLI_BC_P_DEREGISTER_DELETE: IP_BIT_SET(node->flags, IPMIP6PM_NODE_FLAG_DEREGISTER); ipmip6pm_mh_ha_send_binding_update(ctx, proc, node, IP_FALSE, IP_FALSE); /* FALL THROUGH */ case IPMIP6PM_CLI_BC_P_DELETE: ret = ipmip6pm_node_terminate(ctx, proc, node, "unconditional administrative deletion"); break; case IPMIP6PM_CLI_BC_P_DEREGISTER: /* Mark it as de-register, and transmit a binding update */ IP_BIT_SET(node->flags, IPMIP6PM_NODE_FLAG_DEREGISTER); ipmip6pm_mh_ha_send_binding_update(ctx, proc, node, IP_FALSE, IP_TRUE); break; } } ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request); } else { /* Free the request */ ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request); } /**/ return ret; } /* *=========================================================================== * ipmip6pm_attr_node_delete *=========================================================================== * Description: Create a node * Parameters: event - Current event * data - Data * proc - Current process * lock - Command locking structure * node - Node. * Returns: IP_FALSE * */ IP_STATIC int ipmip6pm_attr_node_revoke(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip_cli_message_t *request, Ipmip6pm_node_t *node) { int ret = IPMIP_TIMER_RET_DONE; if (event == IPMIP_TIMER_EVENT_RUN) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr = 0; Ip_u16 reqtype = IPMIP_ATTR_HDR_TYPE(hdr); if (node == IP_NULL) rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_ENOENT, IP_NULL); else { Ip_u8 reason = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_REVOKE_REASON); /* If we have a reply header; terminate it */ rhdr = ipmip_attr_hdr_ack(&request->message, hdr); if (reason == 0) reason = IPMIP6_MH_BRI_TRIGGER_ADMINISTRATIVE_REASON; /* Do revoke this node */ switch (reqtype) { case IPMIP6PM_CLI_BC_P_REVOKE: ret = ipmip6pm_node_revoke(ctx, proc, node, IP_FALSE, reason, IP_NULL); break; case IPMIP6PM_CLI_BC_P_REVOKE_INET: ret = ipmip6pm_node_revoke(ctx, proc, node, IP_TRUE, reason, IP_NULL); break; } } ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request); } else { /* Free the request */ ipmip_cli_message_free(&ctx->ipmip6.ipmip, proc, request); } /**/ return ret; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL int ipmip6pm_attr_command(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, struct Ipmip_cli_message *request) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr = 0; struct Ipmip_attr *idattr[IPMIP6PM_CLI_ATTR_BC_P_MAX + 1]; switch (IPMIP_ATTR_HDR_TYPE(hdr)) { case IPMIP6PM_CLI_BC_P_LIST: { struct Ipmip6pm_attr_op aop; ipcom_memset(&aop, 0, sizeof(aop)); aop.request = request; ipmip_attr_hdr_parse(IPMIP6PM_CLI_ATTR_BC_P_MAX, hdr, idattr); ipmip6pm_attr_build_lookup(&aop.nargs, idattr); rhdr = ipmip_attr_hdr_ack(&request->message, hdr); /* Add all nodes */ ipmip_context_id_lock(ctx->idents); ipmip_context_id_foreach(&ctx->ipmip6.ipmip, proc, ctx->idents, (Ipmip_util_hash_foreach_t)ipmip6pm_attr_list_nodes, &aop, IP_NULL); ipmip_context_id_unlock(ctx->idents); } break; case IPMIP6PM_CLI_BC_P_GET: { Ip_u32 handle = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_HANDLE); /**/ if (handle == 0) return -IP_ERRNO_EINVAL; /* Get by identity */ ipmip6pm_node_lookup_handle(ctx, proc, handle, &request->timer, (Ipmip_timer_func_t)ipmip6pm_attr_node_dump, request); return 0; } case IPMIP6PM_CLI_BC_P_CREATE: { Ipmip6pm_node_lookup_t nargs; Ipmip6pm_if_t *coa_ifp = IP_NULL; ipcom_memset(&nargs, 0, sizeof(nargs)); /* parse it */ ipmip_attr_hdr_parse(IPMIP6PM_CLI_ATTR_BC_P_MAX,hdr, idattr); ipmip6pm_attr_build_lookup(&nargs, idattr); /* NAI */ if (nargs.nai_mn == IP_NULL) return -IP_ERRNO_EINVAL; if (IP_BIT_ISFALSE(nargs.search_params, IPMIP6PM_NODE_LOOKUP_ACCESS_TYPE)) return -IP_ERRNO_EINVAL; if (IP_BIT_ISFALSE(nargs.search_params, IPMIP6PM_NODE_LOOKUP_IFNAME)) return -IP_ERRNO_EINVAL; /* Dont match anything but NAI */ nargs.search_params = 0; if (idattr[IPMIP6PM_CLI_ATTR_BC_P_COA_IFNAME] == IP_NULL) { Ipmip6pm_if_notify_t *notify = IPCOM_LIST_FIRST(&ctx->ifs); if (notify) coa_ifp = (Ipmip6pm_if_t *)notify->ipmip6.ifp; } else { /* Locate this CoA */ coa_ifp = ipmip6pm_if_findbyifname(ctx, proc, IPMIP_ATTR_DATA(idattr[IPMIP6PM_CLI_ATTR_BC_P_COA_IFNAME])); } if (coa_ifp == IP_NULL) return -IP_ERRNO_ENXIO; /* Get by identity */ ipmip6pm_node_search(ctx, proc, coa_ifp, &nargs, &request->timer, (Ipmip_timer_func_t)ipmip6pm_attr_node_create, request); return 0; } case IPMIP6PM_CLI_BC_P_DELETE: case IPMIP6PM_CLI_BC_P_DEREGISTER_DELETE: case IPMIP6PM_CLI_BC_P_DEREGISTER: { Ip_u32 handle = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_HANDLE); /**/ if (handle == 0) return -IP_ERRNO_EINVAL; /* Get by identity */ ipmip6pm_node_lookup_handle(ctx, proc, handle, &request->timer, (Ipmip_timer_func_t)ipmip6pm_attr_node_delete, request); return 0; } case IPMIP6PM_CLI_BC_P_REVOKE: #ifdef IPMIP_USE_INET case IPMIP6PM_CLI_BC_P_REVOKE_INET: #endif { Ip_u32 handle = ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_HANDLE); /**/ if (handle == 0) return -IP_ERRNO_EINVAL; /* Get by identity */ ipmip6pm_node_lookup_handle(ctx, proc, handle, &request->timer, (Ipmip_timer_func_t)ipmip6pm_attr_node_revoke, request); return 0; } case IPMIP_CLI_NAME_LIST: rhdr = ipmip_attr_hdr_ack(&request->message, hdr); { /* Dump each configuration item we've currently got in human readable form */ Ipmip6pm_if_notify_t *notify; ipmip_attr_put_str(&request->message, IPMIP_CLI_ITEM_NAME, "global"); /* Add interfaces */ for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next)) ipmip_attr_put_str(&request->message, IPMIP_CLI_ITEM_NAME, notify->ipmip6.ifp->iff.ifname); } break; case IPMIP6PM_CLI_BC_P_LIST_LINK: case IPMIP6PM_CLI_BC_P_LIST_SERVICE: rhdr = ipmip_attr_hdr_ack(&request->message, hdr); { Ip_u32 i; Ip_u32 elem = IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP6PM_CLI_BC_P_LIST_SERVICE? IPMIP6PM_FUNCTION_SERVICE : IPMIP6PM_FUNCTION_LINK; Ip_u32 rta_elem = IPMIP_ATTR_HDR_TYPE(hdr) == IPMIP6PM_CLI_BC_P_LIST_SERVICE? IPMIP6PM_CLI_ATTR_BC_P_SERVICE : IPMIP6PM_CLI_ATTR_BC_P_LINK; for (i = 0; i < ctx->extensions[elem].num; i++) { if (ctx->extensions[elem].functions[i]->syntax) { Ip_size_t rta = ipmip_attr_begin(&request->message, rta_elem); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_MODULE, ctx->extensions[elem].functions[i]->name); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_VALUE, ctx->extensions[elem].functions[i]->syntax); ipmip_attr_end(&request->message, rta); } } } break; case IPMIP6PM_CLI_BC_P_GET_LMA: rhdr = ipmip_attr_hdr_ack(&request->message, hdr); { Ipmip6pm_if_notify_t *notify; /* Clear any old interfaces */ for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next)) ipmip6pm_lma_attr_get(ctx, proc, (Ipmip6pm_if_t *)notify->ipmip6.ifp, &request->message); } break; case IPMIP6PM_CLI_BC_P_REVOKE_LMA: /* Must locate MAG and */ { const char *m_ifname = ipmip_attr_hdr_find_str(hdr, IPMIP6PM_CLI_ATTR_BC_P_IFNAME); struct Ip_in6_addr *m_addr = ipmip_attr_hdr_find_inet6(hdr, IPMIP6PM_CLI_ATTR_BC_P_HOME_AGENT); Ipmip6pm_if_notify_t *notify; Ipmip6pm_if_t *ife; Ipmip6pm_lma_t *lma; /**/ if (m_ifname == IP_NULL || m_addr == IP_NULL) return -IP_ERRNO_EINVAL; for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next)) { ife = (Ipmip6pm_if_t *)notify->ipmip6.ifp; if (ipcom_strcasecmp(ife->ipmip6.iff.ifname, m_ifname) == 0) break; } if (notify == IP_NULL) return -IP_ERRNO_ENXIO; /* Time to find the MAG */ lma = ipmip6pm_lma_get(ctx, proc, ife, m_addr, 0, 0); if (lma == IP_NULL) return -IP_ERRNO_ENOENT; /* Time to revoke */ ipmip6pm_lma_revoke(ctx, proc, lma, ipmip_attr_hdr_find_u32(hdr, IPMIP6PM_CLI_ATTR_BC_P_REVOKE_REASON)); /* Must release */ ipmip6pm_lma_release(ctx, proc, lma); rhdr = ipmip_attr_hdr_ack(&request->message, hdr); } break; case IPMIP_CLI_CONFIG_GET: rhdr = ipmip_attr_hdr_ack(&request->message, hdr); { /* Dump each configuration item we've currently got in human readable form */ unsigned int si, f; Ipmip6pm_if_notify_t *notify; char *name = ipmip_attr_hdr_find_str(hdr, IPMIP_CLI_ITEM_NAME); if (name == IP_NULL || ipcom_strcasecmp("global", name) == 0) { for (f = 0; f < IPMIP6PM_FUNCTION_MAX; f++) { for (si = 0; si < ctx->extensions[f].num; si++) { if (ctx->extensions[f].functions[si]->config_global != IP_NULL && ctx->extdata[f][si] != IP_NULL) (*ctx->extensions[f].functions[si]->config_global) (ctx, proc, IPMIP_CALLBACK_CONFIG_DUMP, ctx->extdata[f][si], request); } } } /* Clear any old interfaces */ for (notify = IPCOM_LIST_FIRST(&ctx->ifs); notify != IP_NULL; notify = IPCOM_LIST_NEXT(¬ify->next)) { Ipmip6pm_if_t *ife = (Ipmip6pm_if_t *)notify->ipmip6.ifp; if (name != IP_NULL && ipcom_strcasecmp(ife->ipmip6.iff.ifname, name) != 0) continue; /**/ ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.lifetime=%d", ife->ipmip6.iff.ifname, ife->lifetime); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.tunnel.ip6ip6=%s", ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_IP6IP6]? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.tunnel.gre=%s", ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_GRE6]? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.care_of_address=%s", ife->ipmip6.iff.ifname, ipmip_ntop_inet6(proc, &ife->ifaddr.prefix, IP_NULL)); #ifdef IPMIP_USE_INET ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.care_of_address=%s", ife->ipmip6.iff.ifname, ipmip_ntop_inet(proc, ife->ifinet)); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.tunnel.gre=%s", ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_GRE]? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.tunnel.ipip=%s", ife->ipmip6.iff.ifname, ife->ifenabled[IPMIP_TUNNELTYPE_IPIP]? "enabled" : "disabled"); #endif ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.InitialBindackTimeoutFirstReg=%d", ife->ipmip6.iff.ifname, ife->InitialBindackTimeoutFirstReg); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.TimestampBasedApproachInUse=%s", ife->ipmip6.iff.ifname, ife->TimestampBasedApproachInUse? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.BRIMaxRetriesNumber=%d", ife->ipmip6.iff.ifname, ife->BRIMaxRetriesNumber); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.MINDelayBRIs=%d", ife->ipmip6.iff.ifname, ife->MINDelayBRIs); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.tunnel.gre.Preferred=%s", ife->ipmip6.iff.ifname, ife->GRE_Preferred? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.tunnel.gre.UseKeys=%s", ife->ipmip6.iff.ifname, ife->GRE_UseKeys? "enabled" : "disabled"); #ifdef IPMIP_USE_INET ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.UseIPv4UDPEncapForSignalingMessages=%s", ife->ipmip6.iff.ifname, ife->UseIPv4UDPEncapForSignalingMessages? "true" : "false"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.ForceIPv4UDPEncapsulationSupport=%s", ife->ipmip6.iff.ifname, ife->ForceIPv4UDPEncapsulationSupport? "true" : "false"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.IPv4UDPEncapsulationNATTimeout=%d", ife->ipmip6.iff.ifname, ife->IPv4UDPEncapsulationNATTimeout); #endif ipmip6pm_lma_configure_dump(ctx, proc, ife, &request->message); for (f = 0; f < IPMIP6PM_FUNCTION_MAX; f++) { for (si = 0; si < ctx->extensions[f].num; si++) { if (ctx->extensions[f].functions[si]->config_ifp != IP_NULL && ife->extdata[f][si] != IP_NULL) (*ctx->extensions[f].functions[si]->config_ifp) (ctx, proc, IPMIP_CALLBACK_CONFIG_DUMP, ife, ctx->extdata[f][si], ife->extdata[f][si], request); } } } } /* */ break; default: /**/ return ipmip6_attr_command(&ctx->ipmip6, proc, request); } /* If we have a reply header; terminate it */ ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip6.ipmip, proc, request); return 0; } /**/ IP_GLOBAL void ipmip6pm_attr_status_change(Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip6pm_node_t *node, Ip_u32 status) { /* Status updates */ if (status != node->status) { #ifdef IPMIP6PM_MULTICAST_STATUS /* If there's anyone listening */ if (ctx->ipmip6.ipmip.cli->clients.size > 0) { Ipmip_cli_message_t *msg = ipmip_cli_message_alloc(IP_NULL); Ip_size_t rhdr = ipmip_attr_hdr_ack_create(&msg->message, 0, 0, IPMIP6PM_CLI_BC_P_STATUS); Ip_size_t rta = ipmip_attr_begin(&msg->message, IPMIP6PM_CLI_ATTR_BC_P); ipmip_attr_put_u32(&msg->message, IPMIP6PM_CLI_ATTR_BC_P_HANDLE, node->identity); ipmip_attr_put_u32(&msg->message, IPMIP6PM_CLI_ATTR_BC_P_STATUS, status); ipmip_attr_end(&msg->message, rta); /* If we have a reply header; terminate it */ ipmip_attr_hdr_finalize(&msg->message, rhdr); /* Broadcast */ ipmip_cli_message_multicast(&ctx->ipmip6.ipmip, proc, IP_NULL, IPMIP6PM_CLI_BC_P_STATUS, msg); } #endif node->status = status; } } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */