/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipipsec_ctrl.c,v $ $Revision: 1.53.2.6 $ * $Source: /home/interpeak/CVSRoot/ipipsec2/src/ipipsec_ctrl.c,v $ * $Author: jren $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Lennart Bang ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipipsec_config.h" /* Define to support full ctrl api (deprecated, replaced by ioctls) #define IPIPSEC_USE_FULL_CTRL_API */ /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include "ipipsec_h.h" #include "ipipsec_pfkeyv2.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPIPSEC_LEAVE(xerrval) do { retval = xerrval; goto leave; } while(0) /* **************************************************************************** * 5 TYPES **************************************************************************** */ #ifndef IP_PORT_LAS /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_EXTERN Ipipsec_data ipipsec; /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC int ipipsec_get_sadir(Ipipsec_sa *sa); IP_STATIC Ipipsec_sa * ipipsec_sa_lex_get(Ipipsec_sa_handle *sah, Ipipsec_sa_handle *sah_next); /*IP_STATIC Ipipsec_flow *ipipsec_flow_lex_get(Ip_u32 id);*/ IP_STATIC Ipipsec_flow *ipipsec_flow_sort_get(Ip_u32 id); /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipipsec_sa_to_handle *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipipsec_sa_to_handle(Ipipsec_sa *sa, Ipipsec_sa_handle *handle) { ip_assert(sa != IP_NULL); ipcom_memset(handle, 0, sizeof(Ipipsec_sa_handle)); ipcom_memcpy(&handle->dst, &sa->key.dst, sa->in_addr_size); ipcom_memcpy(&handle->src, &sa->key.src, sa->in_addr_size); handle->spi_n = sa->key.ports.espah_spi_n; handle->protocol = IPIPSEC_SADB_GET_PROTO(sa->sadb_msg_satype); handle->direction = sa->key.direction; handle->domain = sa->key.domain; handle->satype = sa->sadb_msg_satype; handle->priority = sa->key.priority; handle->dscp = sa->key.dscp; } /* *=========================================================================== * ipipsec_handle_to_key *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipipsec_handle_to_key(Ipipsec_sa_handle *sah, Ipipsec_key *key) { ipcom_memset(key, 0, sizeof(Ipipsec_key)); ipcom_memcpy(&key->dst, &sah->dst, sah->domain == IP_AF_INET ? 4 : 16); ipcom_memcpy(&key->src, &sah->src, sah->domain == IP_AF_INET ? 4 : 16); key->ports.espah_spi_n = sah->spi_n; key->proto = sah->protocol; key->direction = sah->direction; key->domain = sah->domain; /* satype */ key->priority = sah->priority; key->dscp = sah->dscp; } /* *=========================================================================== * ipipsec_sa_get_dir *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipipsec_get_sadir(Ipipsec_sa *sa) { if (sa->bytes[IPIPSEC_DIR_IN] || sa->packets[IPIPSEC_DIR_IN]) return IPIPSEC_SADIR_INPUT; if (sa->bytes[IPIPSEC_DIR_OUT] || sa->packets[IPIPSEC_DIR_OUT]) return IPIPSEC_SADIR_OUTPUT; return IPIPSEC_SADIR_ANY; } /* *=========================================================================== * ipipsec_sa_lex_get *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ipipsec_sa * ipipsec_sa_lex_get(Ipipsec_sa_handle *sah, Ipipsec_sa_handle *sah_next) { Ipipsec_sa *cur, *sa; int domain_index; if (sah->spi_n) { Ipipsec_key key; ipipsec_handle_to_key(sah, &key); cur = ipipsec_sa_lookup_exact(&key); } else cur = IP_NULL; /* Scan SA's (IPv4 first) */ for (domain_index = 0; domain_index < 2; domain_index++) for (sa = IPCOM_LIST_FIRST(&ipipsec.shm->sa_head[domain_index]); sa != IP_NULL; sa = IPCOM_LIST_NEXT(&sa->sa_list)) { /* First fast-forward to the current SA */ if (cur != IP_NULL) { if (cur == sa) cur = IP_NULL; continue; } /* IP_IPPROTO_ESP, IP_IPPROTO_AH or 0 for any */ if (sah_next->protocol != 0 && sah_next->protocol != sa->key.proto) continue; /* 0,1 = input/output, 2 = any direction SA */ if (sah_next->direction != IPIPSEC_SADIR_ANY && sah_next->direction != ipipsec_get_sadir(sa)) continue; /* IP_AF_INET or IP_AF_INET6 or 0 for any */ if (sah_next->domain && sah_next->domain != sa->key.domain) continue; return sa; } return IP_NULL; } /* *=========================================================================== * ipipsec_flow_sort_get *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ipipsec_flow * ipipsec_flow_sort_get(Ip_u32 id) { Ipipsec_flow *flow, *next; int flowdir, domain_index; /* Check flows (IPv4 and input first) */ for (domain_index = 0; domain_index < 2; domain_index++) for (flowdir = 0; flowdir < 2; flowdir++) for (flow = IPCOM_LIST_FIRST(&ipipsec.shm->flow_head[domain_index][flowdir]); flow != IP_NULL; flow = next) { ip_assert(flow->magic == IPIPSEC_FLOW_MAGIC); next = IPCOM_LIST_NEXT(&flow->flow_list); if (id == 0) return flow; if (id != flow->id) continue; if (next) return next; else id = 0; } return IP_NULL; } /* *=========================================================================== * ipipsec_flow_to_selector *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipipsec_flow_to_selector(Ipipsec_flow *flow, Ipipsec_ctrl_selector *sel) { ipcom_memset(sel, 0, sizeof(Ipipsec_ctrl_selector)); sel->Index = flow->id; sel->Protocol = flow->flowsel.key.proto; sel->domain = flow->flowsel.key.domain; sel->direction = flow->flowsel.key.direction; sel->flowtype = flow->flowtype; sel->flowpri = flow->flowsel.key.priority; switch (sel->Protocol) { case IP_IPPROTO_TCP: case IP_IPPROTO_UDP: sel->LocalPort = flow->flowsel.key.ports.udptcp_srcdst_n[0]; sel->LocalMaxPort = ip_htons(flow->flowsel.src_max_port); sel->RemotePort = flow->flowsel.key.ports.udptcp_srcdst_n[1]; sel->RemoteMaxPort = ip_htons(flow->flowsel.dst_max_port); break; case IP_IPPROTO_ICMP: case IP_IPPROTO_ICMPV6: sel->ports[0] = flow->flowsel.key.ports.icmp_typecode[0]; sel->ports[1] = flow->flowsel.key.ports.icmp_typecode[1]; break; case IP_IPPROTO_MH: sel->ports[0] = flow->flowsel.key.ports.mh_type[0]; break; default: break; } #ifdef IPCOM_USE_INET if (flow->flowsel.key.domain == IP_AF_INET) { sel->LocalId.in.s_addr = flow->flowsel.key.src.in.s_addr; sel->LocalMaxId.in.s_addr = flow->flowsel.src_max.in.s_addr; sel->RemoteId.in.s_addr = flow->flowsel.key.dst.in.s_addr; sel->RemoteMaxId.in.s_addr = flow->flowsel.dst_max.in.s_addr; sel->local_mask.in.s_addr = flow->flowsel.mask.src.in.s_addr; sel->remote_mask.in.s_addr = flow->flowsel.mask.dst.in.s_addr; } #endif /* IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if (flow->flowsel.key.domain == IP_AF_INET6) { ipcom_memcpy(&sel->LocalId.in6, &flow->flowsel.key.src, sizeof(struct Ip_in6_addr)); ipcom_memcpy(&sel->LocalMaxId.in6, &flow->flowsel.src_max, sizeof(struct Ip_in6_addr)); ipcom_memcpy(&sel->RemoteId.in6, &flow->flowsel.key.dst, sizeof(struct Ip_in6_addr)); ipcom_memcpy(&sel->RemoteMaxId.in6, &flow->flowsel.dst_max, sizeof(struct Ip_in6_addr)); ipcom_memcpy(&sel->local_mask, &flow->flowsel.mask.src, sizeof(struct Ip_in6_addr)); ipcom_memcpy(&sel->remote_mask, &flow->flowsel.mask.dst, sizeof(struct Ip_in6_addr)); } #endif /* IPCOM_USE_INET6 */ if (flow->sa && flow->sasel == IP_NULL) ipipsec_sa_to_handle(flow->sa, &sel->sa); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipipsec_conf_internal *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipipsec_conf_internal(Ip_tag *ctrl_tags) { Ip_tag tagp[2]; Ip_err retval; #ifdef IPIPSEC_USE_DAEMONS Ipnet_sig *sig; sig = ipipsec_suspend_daemons(); if (sig == IP_NULL) return IPCOM_ERR_NO_MEMORY; ipipsec_poll_control_pipe(); #else IPIPSEC_DATA_LOCK(); #endif for(;; ctrl_tags += 2) { /* Read the TAG value; need to copy since it may * be a pointer in another memory space */ if (ipcom_memcpy(&tagp[0], ctrl_tags, sizeof(Ip_tag)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } if (tagp[0] == IP_TAG_END) break; /* Read data */ if (ipcom_memcpy(&tagp[1], ctrl_tags + 1, sizeof(Ip_tag)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } /* What are we dealing with? */ switch(tagp[0]) { case IPIPSEC_CONF_GET_ENABLE_OUTFILTER: tagp[1] = ipipsec_conf_enable_outfilter; break; case IPIPSEC_CONF_SET_ENABLE_OUTFILTER: ipipsec_conf_enable_outfilter = tagp[1]; break; case IPIPSEC_CONF_GET_ENABLE_ESP: tagp[1] = ipipsec_conf_esp_enable; break; case IPIPSEC_CONF_SET_ENABLE_ESP: ipipsec_conf_esp_enable = tagp[1]; break; case IPIPSEC_CONF_GET_ENABLE_AH: tagp[1] = ipipsec_conf_ah_enable; break; case IPIPSEC_CONF_SET_ENABLE_AH: ipipsec_conf_ah_enable = tagp[1]; break; case IPIPSEC_CONF_GET_ALLOW_IPIP: tagp[1] = ipipsec_conf_ipip_allow; break; case IPIPSEC_CONF_SET_ALLOW_IPIP: ipipsec_conf_ipip_allow = tagp[1]; break; default: IPIPSEC_LEAVE(IPCOM_ERR_UNSUPPORTED_TAG); } /* Restore value */ ipcom_memcpy(ctrl_tags + 1, &tagp[1], sizeof(Ip_tag)); } retval = IPCOM_SUCCESS; leave: #ifdef IPIPSEC_USE_DAEMONS ipipsec_resume_daemons(sig); #else IPIPSEC_DATA_UNLOCK(); #endif return retval; } /* *=========================================================================== * ipipsec_ctrl_internal *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipipsec_ctrl_internal(Ip_tag *ctrl_tags) { Ip_tag tagp[2]; Ip_err retval; #ifdef IPIPSEC_USE_DAEMONS Ipnet_sig *sig; sig = ipipsec_suspend_daemons(); if (sig == IP_NULL) return IPCOM_ERR_NO_MEMORY; ipipsec_poll_control_pipe(); #else IPIPSEC_DATA_LOCK(); #endif #if defined(IPIPSEC_USE_FULL_CTRL_API) || defined(IPIPSEC_USE_MIB) || defined(IPIPSEC_USE_TRAPS) for(;;ctrl_tags += 2) #endif { /* Read the TAG value; need to copy * since it may be a pointer in another memory space */ if (ipcom_memcpy(&tagp[0], ctrl_tags, sizeof(Ip_tag)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } if (tagp[0] == IP_TAG_END) IPIPSEC_LEAVE(IPCOM_SUCCESS); /*break;*/ /* Read data */ if (ipcom_memcpy(&tagp[1], ctrl_tags + 1, sizeof(Ip_tag)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } /* What are we dealing with? */ switch(tagp[0]) { #ifdef IPIPSEC_USE_FULL_CTRL_API case IPIPSEC_CTRLT_GET_SELECTOR: { Ipipsec_ctrl_selector sel; Ipipsec_flow *flow; if (ipcom_memcpy(&sel, (void *)tagp[1], sizeof(sel)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } flow = ipipsec_flow_sort_get(sel.Index); if (flow == IP_NULL) { sel.Index = 0; ipcom_memcpy((void *)tagp[1], &sel, sizeof(sel)); break; } ipipsec_flow_to_selector(flow, &sel); ipcom_memcpy((void *)tagp[1], &sel, sizeof(sel)); } break; #endif /* ifdef IPIPSEC_USE_FULL_CTRL_API */ #ifdef IPIPSEC_USE_MIB case IPIPSEC_CTRLT_GET_ipsecEspCurrentInboundSAs : tagp[1] = ipipsec.stats.ipsecEspCurrentInboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecEspTotalInboundSAs : tagp[1] = ipipsec.stats.ipsecEspTotalInboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecEspCurrentOutboundSAs : tagp[1] = ipipsec.stats.ipsecEspCurrentOutboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecEspTotalOutboundSAs : tagp[1] = ipipsec.stats.ipsecEspTotalOutboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecAhCurrentInboundSAs : tagp[1] = ipipsec.stats.ipsecAhCurrentInboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecAhTotalInboundSAs : tagp[1] = ipipsec.stats.ipsecAhCurrentInboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecAhCurrentOutboundSAs : tagp[1] = ipipsec.stats.ipsecAhCurrentOutboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecAhTotalOutboundSAs : tagp[1] = ipipsec.stats.ipsecAhTotalOutboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecDecryptionErrors : tagp[1] = ipipsec.stats.ipsecAhTotalOutboundSAs; break; case IPIPSEC_CTRLT_GET_ipsecAuthenticationErrors : tagp[1] = ipipsec.stats.ipsecAuthenticationErrors; break; case IPIPSEC_CTRLT_GET_ipsecReplayErrors : tagp[1] = ipipsec.stats.ipsecAuthenticationErrors; break; case IPIPSEC_CTRLT_GET_ipsecPolicyErrors : tagp[1] = ipipsec.stats.ipsecAuthenticationErrors; break; case IPIPSEC_CTRLT_GET_ipsecOtherReceiveErrors : tagp[1] = ipipsec.stats.ipsecOtherReceiveErrors; break; case IPIPSEC_CTRLT_GET_ipsecSendErrors : tagp[1] = ipipsec.stats.ipsecSendErrors; break; case IPIPSEC_CTRLT_GET_ipsecUnknownSpiErrors : tagp[1] = ipipsec.stats.ipsecUnknownSpiErrors; break; #endif /* IPIPSEC_USE_MIB */ #ifdef IPIPSEC_USE_TRAPS /* trap function */ case IPIPSEC_CTRLT_SET_TRAP_FUNCTION : ipipsec.trap_cb = (Ipipsec_trap_func)tagp[1]; break; /* traps get */ case IPIPSEC_CTRLT_GET_espAuthFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espAuthFailureTrap]; break; case IPIPSEC_CTRLT_GET_ahAuthFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahAuthFailureTrap]; break; case IPIPSEC_CTRLT_GET_espReplayFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espReplayFailureTrap]; break; case IPIPSEC_CTRLT_GET_ahReplayFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahReplayFailureTrap]; break; case IPIPSEC_CTRLT_GET_espPolicyFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espPolicyFailureTrap]; break; case IPIPSEC_CTRLT_GET_ahPolicyFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahPolicyFailureTrap]; break; case IPIPSEC_CTRLT_GET_invalidSpiTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_invalidSpiTrap]; break; case IPIPSEC_CTRLT_GET_otherPolicyFailureTrapEnable : tagp[1] = ipipsec.enable_trap[IPIPSEC_TRAPTYPE_otherPolicyFailureTrap]; break; /* traps set */ case IPIPSEC_CTRLT_SET_espAuthFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espAuthFailureTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_ahAuthFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahAuthFailureTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_espReplayFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espReplayFailureTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_ahReplayFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahReplayFailureTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_espPolicyFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_espPolicyFailureTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_ahPolicyFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_ahPolicyFailureTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_invalidSpiTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_invalidSpiTrap] = (Ip_u32)tagp[1]; break; case IPIPSEC_CTRLT_SET_otherPolicyFailureTrapEnable : ipipsec.enable_trap[IPIPSEC_TRAPTYPE_otherPolicyFailureTrap] = (Ip_u32)tagp[1]; break; #endif /* IPIPSEC_USE_TRAPS */ default: IPIPSEC_LEAVE(IPCOM_ERR_UNSUPPORTED_TAG); } /* Restore value */ #if defined(IPIPSEC_USE_FULL_CTRL_API) || defined(IPIPSEC_USE_MIB) || defined(IPIPSEC_USE_TRAPS) ipcom_memcpy(ctrl_tags + 1, &tagp[1], sizeof(Ip_tag)); #endif } #if defined(IPIPSEC_USE_FULL_CTRL_API) || defined(IPIPSEC_USE_MIB) || defined(IPIPSEC_USE_TRAPS) retval = IPCOM_SUCCESS; #endif leave: #ifdef IPIPSEC_USE_DAEMONS ipipsec_resume_daemons(sig); #else IPIPSEC_DATA_UNLOCK(); #endif return retval; } /* *=========================================================================== * ipipsec_sactrl_internal *=========================================================================== * Context: * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipipsec_sactrl_internal(Ipipsec_sa_handle *sah, Ip_tag *ctrl_tags) { Ip_tag tagp[5]; Ipipsec_sa *sa; Ip_err retval; Ipipsec_flow *flow; Ipipsec_sa_handle sah_next; Ip_tag *next_tag; #ifdef IPIPSEC_USE_DAEMONS Ipnet_sig *sig; sig = ipipsec_suspend_daemons(); if (sig == IP_NULL) return IPCOM_ERR_NO_MEMORY; ipipsec_poll_control_pipe(); #else IPIPSEC_DATA_LOCK(); #endif /* Just to make certain that its in the memory space */ if (ipcom_memcpy(&sah_next, sah, sizeof(sah_next)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } /* Get SA pointer for SA get/set */ if (sah_next.spi_n) { Ipipsec_key key; ipipsec_handle_to_key(&sah_next, &key); sa = ipipsec_sa_lookup_exact(&key); } else sa = IP_NULL; /* Parse the vtags */ for (next_tag = ctrl_tags;; next_tag += 2) { Ip_size_t szu = sizeof(Ip_tag); /* Go to next tag */ ctrl_tags = next_tag; /* Read the TAG value; need to copy since it may * be a pointer in another memory space */ if (ipcom_memcpy(&tagp[0], ctrl_tags, sizeof(Ip_tag)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } if (tagp[0] == IP_TAG_END) break; if (tagp[0] > IPIPSEC_SACTRLT_GET_NEXT_SA && tagp[0] <= IPIPSEC_SACTRLT_GET_LAST) { if (sa == IP_NULL) IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } /* Read data */ if (ipcom_memcpy(&tagp[1], ctrl_tags + 1, sizeof(Ip_tag)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_TAG_VALUE); } switch(tagp[0]) { #ifdef IPIPSEC_USE_FULL_CTRL_API /* This tag returns immediately after processing since it updates the 'sa' */ case IPIPSEC_SACTRLT_GET_NEXT_SA: { Ipipsec_sa *sa_next; if (ipcom_memcpy(&sah_next, (void *)tagp[1], sizeof(sah_next)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } sa_next = ipipsec_sa_lex_get(sah, &sah_next); if (sa_next != IP_NULL) ipipsec_sa_to_handle(sa_next, &sah_next); else sah_next.spi_n = 0; ipcom_memcpy((void *)tagp[1], &sah_next, sizeof(sah_next)); } break; #endif /* IPIPSEC_USE_FULL_CTRL_API */ case IPIPSEC_SACTRLT_GET_SaSelector: { Ipcom_list *list_element; ip_assert(sa); /* In MIB, only first selector is listed. Pick the output one first */ list_element = IPCOM_LIST_FIRST(&sa->flow_head); flow = IPIPSEC_LIST_ENTRY(list_element, Ipipsec_flow, sa_list); ip_assert(flow == IP_NULL || flow->magic == IPIPSEC_FLOW_MAGIC); if (flow) tagp[1] = flow->id; else tagp[1] = 0; } break; case IPIPSEC_SACTRLT_GET_SaCreator: tagp[1] = 1; /* 0=unknown,1=static,2=ike,3=other */ break; case IPIPSEC_SACTRLT_GET_Encapsulation: ip_assert(sa); if (IP_BIT_ISSET(sa->sadb_sa_flags, SADB_X_SAFLAGS_TUNNEL)) tagp[1] = 1; /* 0=reserved,1=tunnel,2=transport */ else tagp[1] = 2; break; case IPIPSEC_SACTRLT_GET_EncAlg: ip_assert(sa); tagp[1] = sa->sadb_sa_encrypt; break; case IPIPSEC_SACTRLT_GET_EncKeyLength: ip_assert(sa); tagp[1] = sa->encrypt ? (sa->encrypt->keyLen << 3) : 0; break; case IPIPSEC_SACTRLT_GET_AuthAlg: ip_assert(sa); tagp[1] = sa->sadb_sa_auth; break; case IPIPSEC_SACTRLT_GET_AuthKeyLength: ip_assert(sa); tagp[1] = sa->auth ? (sa->auth->keyLen << 3) : 0; break; case IPIPSEC_SACTRLT_GET_RepWinSize: ip_assert(sa); tagp[1] = sa->sadb_sa_replay; break; case IPIPSEC_SACTRLT_GET_LimitSeconds: ip_assert(sa); tagp[1] = sa->lthard.addtime; break; case IPIPSEC_SACTRLT_GET_LimitKbytes: tagp[1] = 0; /*!!auto*/ break; case IPIPSEC_SACTRLT_GET_AccSeconds: ip_assert(sa); if (sa->ltcurrent.usetime) tagp[1] = (Ip_tag)(ipcom_time(0) - sa->ltcurrent.addtime); else tagp[1] = 0; break; case IPIPSEC_SACTRLT_GET_InAccKbytes: ip_assert(sa); tagp[1] = (IP_U64_GETLO(sa->bytes[IPIPSEC_DIR_IN]) >> 10); tagp[1] += (IP_U64_GETHI(sa->bytes[IPIPSEC_DIR_IN]) << 22); break; case IPIPSEC_SACTRLT_GET_OutAccKbytes: ip_assert(sa); tagp[1] = (IP_U64_GETLO(sa->bytes[IPIPSEC_DIR_OUT]) >> 10); tagp[1] += (IP_U64_GETHI(sa->bytes[IPIPSEC_DIR_OUT]) << 22); break; #ifdef IPIPSEC_USE_FULL_CTRL_API case IPIPSEC_SACTRLT_GET_InUserOctets: ip_assert(sa); ipcom_memcpy((void *)tagp[1], &sa->bytes[IPIPSEC_DIR_IN], sizeof(Ip_u64)); break; case IPIPSEC_SACTRLT_GET_OutUserOctets: ip_assert(sa); ipcom_memcpy((void *)tagp[1], &sa->bytes[IPIPSEC_DIR_OUT], sizeof(Ip_u64)); break; case IPIPSEC_SACTRLT_GET_InPackets: ip_assert(sa); ipcom_memcpy((void *)tagp[1], &sa->packets[IPIPSEC_DIR_IN], sizeof(Ip_u64)); break; case IPIPSEC_SACTRLT_GET_OutPackets: ip_assert(sa); ipcom_memcpy((void *)tagp[1], &sa->packets[IPIPSEC_DIR_OUT], sizeof(Ip_u64)); break; #endif /* IPIPSEC_USE_FULL_CTRL_API */ #ifdef IPIPSEC_USE_MIB case IPIPSEC_SACTRLT_GET_DecryptErrors: ip_assert(sa); tagp[1] = sa->err_in_decrypt; break; case IPIPSEC_SACTRLT_GET_AuthErrors: ip_assert(sa); tagp[1] = sa->err_in_auth; break; case IPIPSEC_SACTRLT_GET_ReplayErrors: ip_assert(sa); tagp[1] = sa->err_in_replay; break; case IPIPSEC_SACTRLT_GET_PolicyErrors: ip_assert(sa); tagp[1] = sa->err_in_policy; break; case IPIPSEC_SACTRLT_GET_PadErrors: ip_assert(sa); tagp[1] = sa->err_in_pad; break; case IPIPSEC_SACTRLT_GET_OtherReceiveErrors: ip_assert(sa); tagp[1] = sa->err_in_other; break; case IPIPSEC_SACTRLT_GET_OutSendErrors: ip_assert(sa); tagp[1] = sa->err_out_send; break; #endif /* IPIPSEC_USE_MIB */ #ifdef IPIPSEC_USE_FULL_CTRL_API case IPIPSEC_SACTRLT_GET_Grouped: ip_assert(sa); if (ipcom_memcpy(&sah_next, (void *)tagp[1], sizeof(sah_next)) == IP_NULL) { IPIPSEC_LEAVE(IPCOM_ERR_INVALID_ARG); } if (sa->group_next != IP_NULL) ipipsec_sa_to_handle(sa->group_next, &sah_next); else sah_next.spi_n = 0; ipcom_memcpy((void *)tagp[1], &sah_next, sizeof(sah_next)); break; #endif /* #ifdef IPIPSEC_USE_FULL_CTRL_API */ case IPIPSEC_SACTRLT_GET_DstAddr: ip_assert(sa); tagp[1] = sa->key.dst.in.s_addr; break; case IPIPSEC_SACTRLT_GET_SrcAddr: ip_assert(sa); tagp[1] = sa->key.src.in.s_addr; break; case IPIPSEC_SACTRLT_GET_State: ip_assert(sa); tagp[1] = sa->sadb_sa_state; break; #ifdef IPCOM_USE_INET6 case IPIPSEC_SACTRLT_GET_DstAddr6: case IPIPSEC_SACTRLT_GET_SrcAddr6: ip_assert(sa); if (sa->key.domain != IP_AF_INET6) IPIPSEC_LEAVE(IPCOM_ERR_FAILED); if (*tagp == IPIPSEC_SACTRLT_GET_DstAddr6) ipcom_memcpy(&tagp[1], &sa->key.dst, 16); else ipcom_memcpy(&tagp[1], &sa->key.src, 16); /* Advance three more tags */ next_tag += 3; szu = 16; break; #endif /* IPCOM_USE_INET6 */ default: IPIPSEC_LEAVE(IPCOM_ERR_UNSUPPORTED_TAG); } /* Restore value */ ipcom_memcpy(ctrl_tags + 1, &tagp[1], szu); } retval = IPCOM_SUCCESS; leave: #ifdef IPIPSEC_USE_DAEMONS ipipsec_resume_daemons(sig); #else IPIPSEC_DATA_UNLOCK(); #endif return retval; } #endif /* !IP_PORT_LAS */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipipsec_sactrl *=========================================================================== * Context: * Description: * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipipsec_sactrl(Ipipsec_sa_handle *sah, Ip_tag *ctrl_tags) { #if defined(IPNET) Ip_fd pfd = IP_INVALID_SOCKET; int err = 0; void *ptr[2]; /* The arguments */ ptr[0] = sah; ptr[1] = ctrl_tags; /* Get a socket */ if ((pfd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2)) == IP_INVALID_SOCKET) return ipcom_errno; /* Do the sockopt */ if (ipcom_socketioctl(pfd, IP_SIOCXIPSEC_SA_CTL, ptr) < 0) err = ipcom_errno; ipcom_socketclose(pfd); return err; #elif defined(IPLITE) Ip_err ret; (void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_LOCK, IP_NULL); ret = (int)ipipsec_sactrl_internal(sah, ctrl_tags); (void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_UNLOCK, IP_NULL); return ret; #else return -IP_ERRNO_EINVAL #endif } /* *=========================================================================== * ipipsec_ctrl *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipipsec_ctrl(Ip_tag *ctrl_tags) { #if defined(IPNET) Ip_fd pfd; int err = 0; void *ptr = ctrl_tags; /* Get a socket to do the ioctl */ if ((pfd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2)) == IP_INVALID_SOCKET) return ipcom_errno; /* Do the sockopt */ if (ipcom_socketioctl(pfd, IP_SIOCXIPSEC_CTL, &ptr) < 0) err = ipcom_errno; ipcom_socketclose(pfd); return err; #elif defined(IPLITE) Ip_err ret; (void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_LOCK, IP_NULL); ret = ipipsec_ctrl_internal(ctrl_tags); (void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_UNLOCK, IP_NULL); return ret; #else return -IP_ERRNO_EINVAL #endif } /* *=========================================================================== * ipipsec_ctrl *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipipsec_conf(Ip_tag *ctrl_tags) { #if defined(IPNET) Ip_fd pfd; int err = 0; void *ptr = ctrl_tags; /* Get a socket to do the ioctl */ if ((pfd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2)) == IP_INVALID_SOCKET) return ipcom_errno; /* Do the sockopt */ if (ipcom_socketioctl(pfd, IP_SIOCXIPSEC_CONF_CTL, &ptr) < 0) err = ipcom_errno; ipcom_socketclose(pfd); return err; #elif defined(IPLITE) Ip_err ret; (void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_LOCK, IP_NULL); ret = ipipsec_conf_internal(ctrl_tags); (void)ipcom_ipsec_ioevent(IPIPSEC_EIOXCODE_UNLOCK, IP_NULL); return ret; #else return -IP_ERRNO_EINVAL #endif } #ifndef IP_PORT_LAS /* *=========================================================================== * ipipsec_sys_ioctl *=========================================================================== * Description: IO control. * Parameters: fd - A socket descriptor. * request - The IO control request. * argp - Request specific data. * Returns: 0 = success, -1 = error (error code from ipcom_errno). * */ IP_PUBLIC int ipipsec_sys_ioctl(Ip_fd fd, unsigned long request, void *argp) { int ret = 0; Ipipsec_sa *sa = IP_NULL; Ipipsec_ioctl_sactrl *isa = argp; #ifdef IPIPSEC_USE_DAEMONS Ipnet_sig *sig; sig = ipipsec_suspend_daemons(); if (sig == IP_NULL) return -IP_ERRNO_ENOMEM; ipipsec_poll_control_pipe(); #else IPIPSEC_DATA_LOCK(); #endif IPCOM_UNUSED_ARG(fd); ip_assert(isa != IP_NULL); switch(request) { case IP_SIOCXIPSEC_Grouped: case IP_SIOCXIPSEC_InUserOctets: case IP_SIOCXIPSEC_OutUserOctets: case IP_SIOCXIPSEC_InUserPackets: case IP_SIOCXIPSEC_OutUserPackets: /* Get SA pointer for SA get/set */ if (isa->sa.spi_n) { Ipipsec_key key; ipipsec_handle_to_key(&isa->sa, &key); sa = ipipsec_sa_lookup_exact(&key); } if (sa == IP_NULL) { ret = -IP_ERRNO_ESRCH; goto leave; } break; default: break; } switch (request) { case IP_SIOCXIPSEC_SELECTOR: { Ipipsec_ctrl_selector *sel = argp; Ipipsec_flow *flow; flow = ipipsec_flow_sort_get(sel->Index); if (flow == IP_NULL) sel->Index = 0; else ipipsec_flow_to_selector(flow, sel); } break; case IP_SIOCXIPSEC_NEXT_SA: { Ipipsec_sa *sa_next; sa_next = ipipsec_sa_lex_get(&isa->sa, &isa->arg.next); if (sa_next != IP_NULL) ipipsec_sa_to_handle(sa_next, &isa->arg.next); else isa->arg.next.spi_n = 0; } break; case IP_SIOCXIPSEC_Grouped: ip_assert(sa != IP_NULL); if (sa->group_next != IP_NULL) ipipsec_sa_to_handle(sa->group_next, &isa->arg.group); else isa->arg.group.spi_n = 0; break; case IP_SIOCXIPSEC_InUserOctets: ip_assert(sa); isa->arg.u64 = sa->bytes[IPIPSEC_DIR_IN]; break; case IP_SIOCXIPSEC_OutUserOctets: ip_assert(sa); isa->arg.u64 = sa->bytes[IPIPSEC_DIR_OUT]; break; case IP_SIOCXIPSEC_InUserPackets: ip_assert(sa); isa->arg.u64 = sa->packets[IPIPSEC_DIR_IN]; break; case IP_SIOCXIPSEC_OutUserPackets: ip_assert(sa); isa->arg.u64 = sa->packets[IPIPSEC_DIR_OUT]; break; default: ret = -IP_ERRNO_EINVAL; break; } leave: #ifdef IPIPSEC_USE_DAEMONS ipipsec_resume_daemons(sig); #else IPIPSEC_DATA_UNLOCK(); #endif return ret; } #endif /* !IP_PORT_LAS */ /* **************************************************************************** * END OF FILE **************************************************************************** */