/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_service_testext.c,v $ $Revision: 1.6 $ * $Source: /home/interpeak/CVSRoot/ipmip6ha/config/ipmip6ha_service_testext.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6ha_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 "ipmip6ha_h.h" #include "ipmip6ha_attr_h.h" #include "ipmip6ha_if.h" #include "ipmip6ha_node.h" #include "ipmip6ha_pktbuf.h" #include "ipmip6ha_nemo.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP6HA_SERVICE_SERVICE_SELECTION "SERVICE-SELECTION" #define IPMIP6HA_SERVICE_VENDOR_EXTENSION "VENDOR-EXTENSION" /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6ha_service_selection_config { Ip_bool enabled; Ip_bool change_allowed; } Ipmip6ha_service_selection_config_t; typedef struct Ipmip6ha_service_selection_node_handle { Ip_bool enabled; Ipmip6_mh_mo_service_selection_mobility_option_t *selection; } Ipmip6ha_service_selection_node_handle_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC void ipmip6ha_service_selection_config_global(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6ha_service_selection_config_t *gcfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_CONFIG_READ) { gcfg->enabled = ipmip_sysvar_bool(IP_FALSE, "ipmip6ha.service_selection.enabled"); gcfg->change_allowed = ipmip_sysvar_bool(IP_FALSE, "ipmip6ha.service_selection.changeable"); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6ha.service_selection.enabled=%s", gcfg->enabled? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6ha.service_selection.changeable=%s", gcfg->change_allowed? "enabled" : "disabled"); } } IP_STATIC void ipmip6ha_service_selection_config(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6ha_if *ifp, Ipmip6ha_service_selection_config_t *gcfg, Ipmip6ha_service_selection_config_t *cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(ifp); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_CONFIG_READ) { cfg->enabled = ipmip_sysvar_bool(gcfg->enabled, "ipmip6ha.interface.%s.service_selection.enabled", ifp->ipmip6.iff.ifname); cfg->change_allowed = ipmip_sysvar_bool(gcfg->enabled, "ipmip6ha.interface.%s.service_selection.changeable", ifp->ipmip6.iff.ifname); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6ha.interface.%s.service_selection.enabled=%s", ifp->ipmip6.iff.ifname, cfg->enabled? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6ha.interface.%s.service_selection.changeable=%s", ifp->ipmip6.iff.ifname, cfg->change_allowed? "enabled" : "disabled"); } } IP_STATIC Ip_bool ipmip6ha_service_selection_pkt_request_validate(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, Ipmip6ha_service_selection_config_t *gcfg, Ipmip6ha_service_selection_config_t *cfg, Ipmip6ha_service_selection_node_handle_t *handle, struct Ipmip6ha_node *node, struct Ipmip6ha_pktbuf *pbuf, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(handle); IPMIP_UNUSED_PARAMETER(gcfg); if (pbuf->ipmip6.mo.service_selection != IP_NULL) { if (cfg->enabled) { /* Here's the time to verify if the selection's valid */ if (handle->enabled != IP_FALSE) { /* Already have a service setup?*/ if (!ipmip6_mh_mo_cmp(&pbuf->ipmip6.mo.service_selection->hdr, &handle->selection->hdr)) { if (cfg->change_allowed) { /* Mismatch; redo selection */ IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s changing service selection to '%s'", ipmip6ha_node_describe(proc, node), ipmip_ntop_strn(proc, (char *)&pbuf->ipmip6.mo.service_selection->identifier[0], pbuf->ipmip6.mo.service_selection->hdr.len))); pbuf->update_services = IP_TRUE; } else { ipmip_pktbuf_error(&pbuf->ipmip6.ipmip, IPMIP6_MH_BA_STATUS_ERROR_SERVICE_AUTHORIZATION_FAILED, "service selection '%s' specified, but not provided by home agent", ipmip_ntop_strn(proc, (char *)&pbuf->ipmip6.mo.service_selection->identifier[0], pbuf->ipmip6.mo.service_selection->hdr.len)); ipmip6ha_node_delete(ctx, proc, node, "service selection disallowed"); } } } } else { ipmip_pktbuf_error(&pbuf->ipmip6.ipmip, IPMIP6_MH_BA_STATUS_ERROR_SERVICE_AUTHORIZATION_FAILED, "service selection '%s' specified, but not provided by home agent", ipmip_ntop_strn(proc, (char *)&pbuf->ipmip6.mo.service_selection->identifier[0], pbuf->ipmip6.mo.service_selection->hdr.len)); } } /* Don't delay */ return IP_FALSE; } IP_STATIC Ip_bool ipmip6ha_service_selection_pkt_request_accept(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, Ipmip6ha_service_selection_config_t *gcfg, Ipmip6ha_service_selection_config_t *cfg, Ipmip6ha_service_selection_node_handle_t *handle, struct Ipmip6ha_node *node, struct Ipmip6ha_pktbuf *pbuf, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(handle); IPMIP_UNUSED_PARAMETER(gcfg); IPMIP_UNUSED_PARAMETER(cfg); if (pbuf->ipmip6.mo.service_selection != IP_NULL) { /* Only store the service first time around */ if (handle->enabled == IP_FALSE) { /* Store the selected service; we'll use it later in provde */ handle->selection = (void *)ipmip6_mh_mo_dup(&pbuf->ipmip6.mo.service_selection->hdr); handle->enabled = IP_TRUE; /* Mismatch; redo selection */ IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s accepting service selection '%s'", ipmip6ha_node_describe(proc, node), ipmip_ntop_strn(proc, (char *)&pbuf->ipmip6.mo.service_selection->identifier[0], pbuf->ipmip6.mo.service_selection->hdr.len))); } } /* Don't delay */ return IP_FALSE; } IP_STATIC int ipmip6ha_service_selection_provide(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6ha_service_selection_config_t *gcfg, Ipmip6ha_service_selection_config_t *cfg, Ipmip6ha_service_selection_node_handle_t *handle, struct Ipmip6ha_node *node, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_ENABLE) { if (handle->enabled) { /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s enabling service selection '%s'", ipmip6ha_node_describe(proc, node), ipmip_ntop_strn(proc, (char *)&handle->selection->identifier[0], handle->selection->hdr.len))); } } else if (action == IPMIP_CALLBACK_DISABLE) { if (handle->enabled) { /* Disable whatever service setup we've got */ /* Free & Reset */ ipcom_free(handle->selection); handle->enabled = IP_FALSE; } } else if (action == IPMIP_CALLBACK_UPDATE) { /* We're redoing the service setups */ if (handle->enabled) { /* Disable whatever service setup we've got */ /* Free & Reset */ ipcom_free(handle->selection); handle->enabled = IP_FALSE; } /* Indicate that this service needs to be re-setup; if you ignore UPDATE dont return failure */ return IPMIP_CALLBACK_RET_FAILED; } /* Don't delay */ return IPMIP_CALLBACK_RET_SUCCESS; } IP_STATIC Ip_bool ipmip6ha_service_vendor_extension_pkt_request_accept(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, void *gcfg, void *cfg, void *handle, struct Ipmip6ha_node *node, struct Ipmip6ha_pktbuf *pbuf, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(handle); IPMIP_UNUSED_PARAMETER(gcfg); IPMIP_UNUSED_PARAMETER(cfg); if (pbuf->ipmip6.mo.vendor_options.numelem > 0) { Ipmip6_mh_mo_vendor_specific_mobility_option_t *mo; unsigned i; for (i = 0; i < pbuf->ipmip6.mo.vendor_options.numelem; i++) { mo = (Ipmip6_mh_mo_vendor_specific_mobility_option_t*)pbuf->ipmip6.mo.vendor_options.hdrs[i]; /* Mismatch; redo selection */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s received Vendor Extension %u.%u", ipmip6ha_node_describe(proc, node), IP_GET_NTOHL(&mo->vendor_id), mo->sub_type)); } } /* Don't delay */ return IP_FALSE; } /* Echo the Vendor Extension */ IP_STATIC void ipmip6ha_service_selection_pkt_reply_apply(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, void *gcfg, void *cfg, void *handle, struct Ipmip6ha_node *node, struct Ipmip6ha_pktbuf *pbuf_reply, struct Ipmip6ha_pktbuf *pbuf_req) { IPMIP_UNUSED_PARAMETER(handle); IPMIP_UNUSED_PARAMETER(gcfg); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(node); if (pbuf_req->ipmip6.mo.vendor_options.numelem > 0) { Ipmip6_mh_mo_vendor_specific_mobility_option_t *mo; unsigned i; for (i = 0; i < pbuf_req->ipmip6.mo.vendor_options.numelem; i++) { mo = (Ipmip6_mh_mo_vendor_specific_mobility_option_t*)pbuf_req->ipmip6.mo.vendor_options.hdrs[i]; ipmip6_mh_pkt_opt_add_mo(&ctx->ipmip6, proc, &pbuf_reply->ipmip6, &mo->hdr); } } } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6ha_service_testext_install(struct Ipmip6ha_context *ctx); IP_GLOBAL void ipmip6ha_service_testext_install(struct Ipmip6ha_context *ctx) { static Ipmip6ha_extension_t srv_sel; static Ipmip6ha_extension_t srv_ven; ipcom_memset(&srv_sel, 0, sizeof(srv_sel)); srv_sel.name = IPMIP6HA_SERVICE_SERVICE_SELECTION; srv_sel.ifp_data_size = sizeof(Ipmip6ha_service_selection_config_t); srv_sel.global_data_size= sizeof(Ipmip6ha_service_selection_config_t); srv_sel.node_data_size = sizeof(Ipmip6ha_service_selection_node_handle_t); srv_sel.config_global = (Ipmip6ha_extension_config_global_t)ipmip6ha_service_selection_config_global; srv_sel.config_ifp = (Ipmip6ha_extension_config_ifp_t)ipmip6ha_service_selection_config; srv_sel.provide = (Ipmip6ha_extension_provide_t)ipmip6ha_service_selection_provide; srv_sel.pkt_req_accept = (Ipmip6ha_extension_pkt_req_accept_t)ipmip6ha_service_selection_pkt_request_accept; srv_sel.pkt_req_validate= (Ipmip6ha_extension_pkt_req_validate_t)ipmip6ha_service_selection_pkt_request_validate; /* This is a PMIP only feature */ ipmip6ha_context_register_extension(ctx, &srv_sel, IP_TRUE, IP_TRUE); ipcom_memset(&srv_ven, 0, sizeof(srv_ven)); srv_ven.name = IPMIP6HA_SERVICE_VENDOR_EXTENSION; srv_ven.pkt_req_accept = (Ipmip6ha_extension_pkt_req_accept_t)ipmip6ha_service_vendor_extension_pkt_request_accept; srv_ven.pkt_rep_apply = (Ipmip6ha_extension_pkt_rep_apply_t)ipmip6ha_service_selection_pkt_reply_apply; /* This is a PMIP only feature */ ipmip6ha_context_register_extension(ctx, &srv_ven, IP_TRUE, IP_TRUE); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */