/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipha_reg.c,v $ $Revision: 1.26.10.2 $ * $Source: /home/interpeak/CVSRoot/ipmipha/src/ipmipha_reg.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmipha_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 "ipmipha.h" #include "ipmip4_mib.h" #include "ipmipha_h.h" #include "ipmipha_attr_h.h" #include "ipmipha_reg.h" #include "ipmipha_if.h" #include "ipmipha_node.h" #include "ipmipha_agent.h" #include "ipmipha_pktbuf.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmipha_reg_revoke_ack *=========================================================================== * Description: Send a revocation request for this particular binding * Parameters: data - Data * proc - Process * node - Node * binding - Binding * pbuf - Packet buffer * Returns: * */ IP_STATIC void ipmipha_reg_revoke_ack(struct Ipmipha_data *data, struct Ipmip_proc *proc, struct Ipmipha_node *node, struct Ipmipha_node_binding *binding, struct Ipmipha_pktbuf *pbuf) { /**/ Ipmip4_regrevack_t regrev; IPMIP_UNUSED_PARAMETER(node); ipcom_memset(®rev, 0, sizeof(regrev)); if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL) goto error_out; regrev.type = IPMIP4_TYPE_REG_REGREVACK; regrev.home_address = pbuf->pktinfo.haBindingHomeAddress; regrev.identifier = ip_htonl(pbuf->pktinfo.haBindingRevocationTimeStamp); /**/ if ((binding == IP_NULL || IP_BIT_ISSET(binding->haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_INFORM)) && IP_BIT_ISTRUE(pbuf->pktinfo.haBindingOptions, IPMIP4_REG_EXT_REGREV_FLAG_INFORM)) regrev.flags |= ip_htons(IPMIP4_REG_EXT_REGREV_FLAG_INFORM); /* Reset the buffer */ ipmip_buffer_shrink(&pbuf->ipmip4.ipmip.packet, 0); /* Add the header */ ipmip_buffer_append(&pbuf->ipmip4.ipmip.packet, ®rev, sizeof(regrev)); /* Add the foreign to home authentication */ if (ipmip4_auth_append_foreign_to_home(&pbuf->ipmip4.ipmip.packet, pbuf->pktinfo.haBindingSPIForeignHome) == IP_FALSE) goto error_out; /* Send packet using UDP socket */ if (ipmip4_pkt_udp_sendmsg(&data->ipmip4, proc, &pbuf->ipmip4.ipmip.packet, pbuf->iff.pub->ifaddr, data->ipmip4.pkt->s_udp_out.sin_port, pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr, pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port, IP_NULL) == IP_FALSE) { /**/ } error_out: /* Remove the reference */ ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } /* *=========================================================================== * ipmipha_reg_tunnel_type *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_u8 ipmipha_reg_tunnel_type(Ipmipha_pktbuf_t *pbuf) { if (IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_MINIMAL_ENC)) return IPMIP_TUNNELTYPE_MINENC; else if (IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_GRE_ENC)) return IPMIP_TUNNELTYPE_GRE; return IPMIP_TUNNELTYPE_IPIP; } /* *=========================================================================== * ipmipha_reg_spi_lookup_home_sa *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ipmip4_auth_spi_t * ipmipha_reg_spi_lookup_home_sa(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf) { int i; Ipmip4_auth_spi_t *spi = IP_NULL; IPMIP_UNUSED_PARAMETER(data); IPMIP_UNUSED_PARAMETER(proc); for (i = 0; pbuf->iff.priv->security.spi_mn_lookup_order[i] != IPMIPHA_SPI_MN_NONE; i++) { switch (pbuf->iff.priv->security.spi_mn_lookup_order[i]) { case IPMIPHA_SPI_MN_HOA: if (pbuf->pktinfo.haBindingHomeAddress != 0) spi = ipmip4_auth_spi_table_get(pbuf->iff.priv->security.spi_mn, pbuf->pktinfo.haBindingHomeAddress); break; case IPMIPHA_SPI_MN_NAI: if (pbuf->ipmip4.ext.mobile.nai_mobile) spi = ipmip4_auth_spi_hash_get(pbuf->iff.priv->security.spi_nai, (char *)IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ipmip4.ext.mobile.nai_mobile), IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ipmip4.ext.mobile.nai_mobile)); break; } if (spi) return spi; } return 0; } /* *=========================================================================== * ipmipha_reg_spi_lookup_home_sa *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ipmip4_auth_spi_t * ipmipha_reg_spi_lookup_foreign_sa(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf) { IPMIP_UNUSED_PARAMETER(data); IPMIP_UNUSED_PARAMETER(proc); if (pbuf->pktinfo.haBindingCOA != 0) return ipmip4_auth_spi_table_get(pbuf->iff.priv->security.spi_fa, pbuf->pktinfo.haBindingCOA); return IP_NULL; } /* *=========================================================================== * ipmipha_reg_reply *=========================================================================== * Description: Send a reply based on the parameters in the packet buffer. * Parameters: * Returns: * */ IP_STATIC void ipmipha_reg_reply(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_node_t *node, Ipmipha_pktbuf_t *pbuf) { /**/ Ipmipha_pktbuf_t *rpbuf = (Ipmipha_pktbuf_t *)ipmip_pktbuf_alloc(&data->ipmip4.ipmip, proc, 512); Ipmip4_regrep_t reply; reply.type = IPMIP4_TYPE_REG_REPLY; reply.code = pbuf->pktinfo.haBindingHAErrorCode; reply.lifetime = ip_htons(pbuf->pktinfo.haBindingTimeGranted); reply.home_addr = pbuf->pktinfo.haBindingHomeAddress; reply.home_agent = pbuf->iff.pub->ifaddr; reply.id[0] = ip_htonl( ((Ip_u32)pbuf->haBindingTimeStamp) + IPMIP4_JAN_1970); reply.id[1] = pbuf->pktinfo.haBindingRegIDLow; /* Add the header */ ipmip_buffer_append(&rpbuf->ipmip4.ipmip.packet, &reply, sizeof(reply)); /* Add the home agent's NAI, if applicable */ if (pbuf->iff.priv->nai_ha) ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, pbuf->iff.priv->nai_ha); /* If there's a mobile NAI; add it */ if (pbuf->ipmip4.ext.mobile.nai_mobile) ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, pbuf->ipmip4.ext.mobile.nai_mobile); /* We're DHAAD redirecting */ if (pbuf->pktinfo.haBindingHAErrorCode == IPMIP4_CODE_REP_HA_REGISTER_REDIRECTED) { Ip_u8 redir[8]; redir[0] = IPMIP4_EXT_TYPE_DYNAMIC_HA; redir[1] = IPMIP4_DYNAMIC_HA_SUBTYPE_REDIRECTED; IP_SET_HTONS(&redir[2], 4); IP_SET_32ON8(&redir[4], pbuf->pktinfo.haBindingHomeAgentAddress); ipmip4_msgext_buffer_append_lhdr(&rpbuf->ipmip4.ipmip.packet, (void *)redir); } /* Do we have a mobile node UDP tunneling request */ if (pbuf->pktinfo.haBindingHAErrorCode < 2) ipmip_buffer_append(&rpbuf->ipmip4.ipmip.packet, IPMIP_BUFFER_DATA(&pbuf->reply_mn), IPMIP_BUFFER_SIZE(&pbuf->reply_mn)); /* Do we have a selected AAAH home server? */ if (node != IP_NULL) { if (node->nai_aaah != IP_NULL) ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, node->nai_aaah); } /* Add any mobile node specific external extensions */ ipmipha_node_function_rep_mobile_home(data, proc, node, pbuf, rpbuf); /* Try append mobile to home; if set */ if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL) { Ipmip4_auth_spi_t *spi = IP_NULL; /**/ if (pbuf->ipmip4.ext.mobile.mobile_home) { Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.mobile_home; spi = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi)); } if (pbuf->iff.priv->security.spi_mn_lookup_required || (pbuf->pktinfo.haBindingSPIMobileHome = spi) == IP_NULL) pbuf->pktinfo.haBindingSPIMobileHome = ipmipha_reg_spi_lookup_home_sa(data, proc, pbuf); if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Failed locating mobile-home extension SPI for RegReply (%d) to %s:%d", pbuf->pktinfo.haBindingHAErrorCode, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port))); goto error_out; } } if (!ipmip4_auth_append_mobile_to_home(&rpbuf->ipmip4.ipmip.packet, pbuf->pktinfo.haBindingSPIMobileHome)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Failed adding mobile-home extension to RegReply (%d) to %s:%d", pbuf->pktinfo.haBindingHAErrorCode, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port))); goto error_out; } /* Time to add any HA <-> FA */ if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION)) { /* Do we have a mobile node UDP tunneling request */ if (pbuf->pktinfo.haBindingHAErrorCode < 2) ipmip_buffer_append(&rpbuf->ipmip4.ipmip.packet, IPMIP_BUFFER_DATA(&pbuf->reply_fa), IPMIP_BUFFER_SIZE(&pbuf->reply_fa)); /* Add any challenges */ if (pbuf->ipmip4.ext.mobile.challenge != IP_NULL) ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, (void *)pbuf->ipmip4.ext.mobile.challenge); /* Add any mobile node specific external extensions */ ipmipha_node_function_rep_mobile_foreign(data, proc, node, pbuf, rpbuf); if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL) pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_table_get(pbuf->iff.priv->security.spi_fa, pbuf->pktinfo.haBindingCOA); if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL && pbuf->ipmip4.ext.mobile.foreign_home != IP_NULL) { Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home; pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi)); } if (pbuf->pktinfo.haBindingSPIForeignHome != IP_NULL) { if (!ipmip4_auth_append_foreign_to_home(&rpbuf->ipmip4.ipmip.packet, pbuf->pktinfo.haBindingSPIForeignHome)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Failed adding foreign-home extension to RegReply (%d) to %s:%d", pbuf->pktinfo.haBindingHAErrorCode, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port))); goto error_out; } } } /**/ if (pbuf->reply_transport != IP_NULL) (*pbuf->reply_transport->pkt_rep_transport) (data, proc, data->conf->extdata[pbuf->reply_transport->func][pbuf->reply_transport->type], pbuf->iff.priv->extdata[pbuf->reply_transport->func][pbuf->reply_transport->type], node->extdata[pbuf->reply_transport->func][pbuf->reply_transport->type], node, pbuf, rpbuf); else { /* Send packet using UDP socket */ if (ipmip4_pkt_udp_sendmsg(&data->ipmip4, proc, &rpbuf->ipmip4.ipmip.packet, pbuf->iff.pub->ifaddr, data->ipmip4.pkt->s_udp_out.sin_port, pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr, pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port, IP_NULL) == IP_FALSE) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haReasonUnspecified, 1); IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Failed Sending RegReply (%d) to %s:%d", pbuf->pktinfo.haBindingHAErrorCode, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port))); } else { if (pbuf->pktinfo.haBindingTimeGranted == 0) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haDeRegRepliesSent, 1); } else { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRepliesSent, 1); } IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Sending RegReply id=0x%08x (%d) to %s:%d", pbuf->pktinfo.haBindingRegIDLow, pbuf->pktinfo.haBindingHAErrorCode, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port))); } } error_out: /* Remove the reference */ ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &rpbuf->ipmip4.ipmip); } /* *=========================================================================== * ipmipha_reg_request_error *=========================================================================== * Description: Error stage * Parameters: pbuf - The packet buffer * req - Type of major request * Returns: * */ IP_STATIC int ipmipha_reg_request_error(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf, Ip_u8 code) { if (code != 0) { pbuf->ipmip4.ipmip.error_code = code; pbuf->pktinfo.haBindingHAErrorCode = pbuf->ipmip4.ipmip.error_code; switch (pbuf->ipmip4.ipmip.error_code) { case IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haPoorlyFormedRequest, 1); break; case IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haAdmProhibited, 1); break; case IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haInsufficientResource, 1); break; case IPMIP4_CODE_REP_HA_MN_FAILED_AUTH: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haMNAuthenticationFailure, 1); break; case IPMIP4_CODE_REP_HA_FA_FAILED_AUTH: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haFAAuthenticationFailure, 1); break; case IPMIP4_CODE_REP_HA_REG_ID_MISMATCH: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haIDMismatch, 1); break; case IPMIP4_CODE_REP_HA_UNKNOWN_HOME_AGENT_ADDR: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haUnknownHA, 1); break; case IPMIP4_CODE_REP_HA_TOO_MANY_SIM: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haTooManyBindings, 1); break; default: IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haReasonUnspecified, 1); break; } /* Reg reply consumes the buffer */ ipmipha_reg_reply(data, proc, (Ipmipha_node_t *)pbuf->node, pbuf); } else { /* Free it */ ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } return IPMIP_TIMER_RET_DONE; } /* *=========================================================================== * ipmipha_reg_verify_keygen *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_bool ipmipha_reg_verify_keygen(Ipmip4_auth_spi_t *spi, Ipmip4_ext_auth_t *auth) { /* No generated SPI */ /* No auth; we do have a generated SPI. Auth must be set */ if (auth == IP_NULL) return IP_FALSE; /* Does the SPI match? */ return IP_GET_HTONL(auth->spi) == spi->spi; } /* *=========================================================================== * ipmipha_reg_input_request *=========================================================================== * Description: Handles registration request packages. * Either forwards a request from mn -> ha, * or replies to mn cause of mn's bad request. * Parameters: pbuf - Packet buffer * Returns: * */ IP_STATIC void ipmipha_reg_input_request(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1); if (!ipmipha_reg_input_parse_request(data, proc, pbuf)) return; if (pbuf->pktinfo.haBindingTimeGranted == 0) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haDeRegRequestsReceived, 1); } else { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1); } /* Update pending information */ IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Received RegReq id=0x%08x lifetime=%u CoA=%s from %s:%d", pbuf->pktinfo.haBindingRegIDLow, pbuf->pktinfo.haBindingTimeGranted, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port))); /* Try locate the mobile node */ ipmipha_node_lookup(data, proc, pbuf->iff.priv, pbuf->pktinfo.haBindingHomeAddress, &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipha_reg_request_process, pbuf); return; } enum { IPMIPHA_REG_REGREVACK_INIT, IPMIPHA_REG_REGREVACK_VERIFY }; /* *=========================================================================== * ipmipha_reg_ret_process *=========================================================================== * Description: Process a container stage * Parameters: pbuf - The packet buffer * req - Type of major request * Returns: IP_FALSE * */ IP_STATIC int ipmipha_reg_regrevack_process(int event, Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf, Ipmipha_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmipha_node_binding_t *binding = IP_NULL; if (node == IP_NULL) node = (Ipmipha_node_t *)pbuf->node; if (node == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to unknown node specified in registration revocation ack", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } switch (pbuf->pktinfo.haBindingParsingState) { case IPMIPHA_REG_REGREVACK_INIT: pbuf->node = node; { Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home; Ipmip4_auth_spi_t *spi_fa; /* Verify the SPI we should use for foreign agent */ spi_fa = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi)); if (spi_fa == IP_NULL) { /* Unknown security association */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to foreign agent requested a non-existant security association", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } if (pbuf->iff.priv->security.spi_fa_lookup_required) { Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_foreign_sa(data, proc, pbuf); if (spi == IP_NULL) { /* Unknown security association */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to foreign agent lacks configured security association with this home agent", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } else if(spi->spi != spi_fa->spi) { /* Go use the configured value */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to foreign agent used an invalid security association SPI %d, configured to use %d", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), spi_fa->spi, spi->spi)); goto done_out; } } pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REGREVACK_VERIFY; if (ipmip4_auth_verify(&data->ipmip4, proc, &pbuf->ipmip4, pbuf->ipmip4.ext.mobile.foreign_home, spi_fa, node->lock, (Ipmip_timer_func_t)ipmipha_reg_regrevack_process)) return IPMIP_TIMER_RET_PENDING; } /* this is an intentional fall through to the next case */ case IPMIPHA_REG_REGREVACK_VERIFY: if (pbuf->ipmip4.ipmip.message != 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to %s", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message)); goto done_out; } binding = ipmipha_node_binding_revoked(data, proc, node, pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr, pbuf->pktinfo.haBindingRevocationTimeStamp); if (binding == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to unknown binding requested in registration revocation ack", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } ipmipha_node_binding_revoked_complete(data, proc, node, binding); IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request successful", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); } } done_out: ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IPMIP_TIMER_RET_DONE; } /* *=========================================================================== * ipmipha_reg_input_regrevack *=========================================================================== * Description: Handles registration request packages. * Either forwards a request from mn -> ha, * or replies to mn cause of mn's bad request. * Parameters: pbuf - Packet buffer * Returns: * */ IP_STATIC void ipmipha_reg_input_regrevack(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1); /* Check length */ if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < IPMIP4_REGREVACK_LENGTH) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Truncated registration revocation ack [%d]", IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet))); goto done_out; } else { /* Pointers to the packet */ Ipmip4_regrevack_t *regrev = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); /* Store pending reg information */ pbuf->pktinfo.haBindingRevocationTimeStamp = IP_GET_HTONL(®rev->identifier); pbuf->pktinfo.haBindingOptions = IP_GET_HTONS(®rev->flags); pbuf->pktinfo.haBindingHomeAddress = IP_GET_32ON8(®rev->home_address); } /* OK */ pbuf->ipmip4.ext.mobile.result = ipmip4_msgext_mobile_parse_ext(&data->ipmip4, proc, &pbuf->ipmip4, IPMIP4_REGREVACK_LENGTH); /* Parse extensions */ switch (pbuf->ipmip4.ext.mobile.result) { case IPMIP4_REG_EXT_UNKNOWN_VSE: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to bad or unknown VSE", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; case IPMIP4_REG_EXT_FAILED_AUTH: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to bad or duplicate authentication extensions", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; case IPMIP4_REG_EXT_POORLY_FORMED: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to poorly formed request", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; case IPMIP4_REG_EXT_DISCARD: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } /* Do we have a foreign-home authentication? */ if (pbuf->ipmip4.ext.mobile.foreign_home == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation ack silently discarded due to no foreign-home extension in revocation acknowledgement", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } /* Try locate the mobile node */ ipmipha_node_lookup(data, proc, pbuf->iff.priv, pbuf->pktinfo.haBindingHomeAddress, &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipha_reg_regrevack_process, pbuf); return; done_out: ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } enum { IPMIPHA_REG_REGREVREQ_INIT, IPMIPHA_REG_REGREVREQ_VERIFY }; /* *=========================================================================== * ipmipha_reg_ret_process *=========================================================================== * Description: Process a container stage * Parameters: pbuf - The packet buffer * req - Type of major request * Returns: IP_FALSE * */ IP_STATIC int ipmipha_reg_regrevreq_process(int event, Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf, Ipmipha_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmipha_node_binding_t *binding = IP_NULL; if (node == IP_NULL) node = (Ipmipha_node_t *)pbuf->node; binding = (Ipmipha_node_binding_t *)pbuf->binding; switch (pbuf->pktinfo.haBindingParsingState) { case IPMIPHA_REG_REGREVREQ_INIT: { Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home; /* Verify the SPI we should use for foreign agent */ pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi)); if (node == IP_NULL) { ipmipha_reg_revoke_ack(data, proc, IP_NULL, IP_NULL, pbuf); return IPMIP_TIMER_RET_DONE; } pbuf->node = node; binding = ipmipha_node_binding_coa(data, proc, node, pbuf->pktinfo.haBindingCOA); if (binding == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to unknown binding requested in registration revocation ack", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } pbuf->binding = binding; /* Found node & binding */ if (binding->haBindingForeignSA != IP_NULL) { pbuf->pktinfo.haBindingSPIForeignHome = binding->haBindingForeignSA; if (pbuf->pktinfo.haBindingSPIForeignHome->spi != IP_GET_HTONL(auth->spi)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to foreign agent used a security association that does not match AAA generated", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } } else { if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to foreign agent requested a non-existant security association", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } if (pbuf->iff.priv->security.spi_fa_lookup_required) { Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_foreign_sa(data, proc, pbuf); if (spi == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to foreign agent lacks configured security association with this home agent", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } else if(spi->spi != pbuf->pktinfo.haBindingSPIForeignHome->spi) { /* Go use the configured value */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to foreign agent used an invalid security association SPI %d, configured to use %d", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->pktinfo.haBindingSPIForeignHome->spi, spi->spi)); goto done_out; } } } pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REGREVREQ_VERIFY; if (ipmip4_auth_verify(&data->ipmip4, proc, &pbuf->ipmip4, pbuf->ipmip4.ext.mobile.foreign_home, pbuf->pktinfo.haBindingSPIForeignHome, node->lock, (Ipmip_timer_func_t)ipmipha_reg_regrevreq_process)) return IPMIP_TIMER_RET_PENDING; } /* this is an intentional fall through to the next case */ case IPMIPHA_REG_REGREVREQ_VERIFY: if (pbuf->ipmip4.ipmip.message != 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to %s", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message)); goto done_out; } if (!IP_BIT_ARESET(binding->haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_CONFIRMED)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to this binding does not accept revocation usage", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } /**/ if (binding->haBindingRevocationTimeStamp >= pbuf->pktinfo.haBindingRevocationTimeStamp) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to bad revocation time stamp", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } /* Time to revoke */ IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request acknowledged", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_revoke_ack(data, proc, node, binding, pbuf); ipmipha_node_binding_delete(data, proc, node, binding); } } else { done_out: /* Cancelled or aborted */ ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } return IPMIP_TIMER_RET_DONE; } /* *=========================================================================== * ipmipha_reg_input_regrevreq *=========================================================================== * Description: Handles registration request packages. * Either forwards a request from mn -> ha, * or replies to mn cause of mn's bad request. * Parameters: pbuf - Packet buffer * Returns: * */ IP_STATIC void ipmipha_reg_input_regrevreq(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1); /* Check length */ if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < IPMIP4_REGREVREQ_LENGTH) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Truncated registration revocation request [%d]", IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet))); goto done_out; } else { /* Pointers to the packet */ Ipmip4_regrevreq_t *regrev = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); /* Store pending reg information */ pbuf->pktinfo.haBindingHomeAgentAddress = IP_GET_32ON8(®rev->home_domain); pbuf->pktinfo.haBindingRevocationTimeStamp = IP_GET_HTONL(®rev->identifier); pbuf->pktinfo.haBindingOptions = IP_GET_HTONS(®rev->flags); pbuf->pktinfo.haBindingHomeAddress = IP_GET_32ON8(®rev->home_address); pbuf->pktinfo.haBindingCOA = IP_GET_32ON8(®rev->foreign_domain); } /* OK */ pbuf->ipmip4.ext.mobile.result = ipmip4_msgext_mobile_parse_ext(&data->ipmip4, proc, &pbuf->ipmip4, IPMIP4_REGREVREQ_LENGTH); /* Parse extensions */ switch (pbuf->ipmip4.ext.mobile.result) { case IPMIP4_REG_EXT_UNKNOWN_VSE: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to bad or unknown VSE", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; case IPMIP4_REG_EXT_FAILED_AUTH: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to bad or duplicate authentication extensions", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; case IPMIP4_REG_EXT_POORLY_FORMED: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to poorly formed request", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; case IPMIP4_REG_EXT_DISCARD: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } if (IP_BIT_ISTRUE(pbuf->pktinfo.haBindingOptions, IPMIP4_REG_EXT_REGREV_FLAG_AGENT)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to home agent flag set in revocation request", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } /* Do we have a foreign-home authentication? */ if (pbuf->ipmip4.ext.mobile.foreign_home == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration revocation request silently discarded due to no foreign-home extension in revocation request", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); goto done_out; } /* Try locate the mobile node */ ipmipha_node_lookup(data, proc, pbuf->iff.priv, pbuf->pktinfo.haBindingHomeAddress, &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipha_reg_regrevreq_process, pbuf); return; done_out: ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmipha_reg_recv *=========================================================================== * Description: Handles registration request packages. * Parameters: data - Context * proc - Current process. * pbuf - Packet buffer * Returns: * */ IP_GLOBAL void ipmipha_reg_recv(struct Ipmipha_data *data, struct Ipmip_proc *proc, Ipmipha_pktbuf_t *pbuf, void *arg) { /* Locate the interface */ IPMIP_UNUSED_PARAMETER(arg); if (data->conf == IP_NULL) { /* Failure */ IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "No valid configuration availble, discarding registration request")); goto error_out; } if (pbuf->ipmip4.ipmip.srcinfo.lladdr == IP_NULL) { /* Failure */ IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "No MAC found in message, discarding registration request")); goto error_out; } /* Try locate the interface */ pbuf->iff.pub = ipmip4_if_findbypktinfo(&data->conf->if_head, pbuf->ipmip4.ipmip.srcinfo.dst); if (pbuf->iff.priv == IP_NULL) { /* Failure */ IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "No configured interface found in message, discarding registration request")); goto error_out; } /* Retrieve the first byte */ pbuf->pktinfo.haBindingRegType = *(Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet); pbuf->haBindingTimeStamp = ipmip_util_time(); switch (pbuf->pktinfo.haBindingRegType) { case IPMIP4_TYPE_REG_REQUEST: if (IP_BIT_ISFALSE(data->shutdown, IPMIPHA_SHUTDOWN_REG)) { ipmipha_reg_input_request(data, proc, pbuf); return; } break; case IPMIP4_TYPE_REG_REGREVACK: ipmipha_reg_input_regrevack(data, proc, pbuf); return; case IPMIP4_TYPE_REG_REGREVREQ: ipmipha_reg_input_regrevreq(data, proc, pbuf); return; case IPMIP4_TYPE_REG_NAT_ENCAP: IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "NAT Encapsulation registration type %d received on %s from %s [%d]", pbuf->pktinfo.haBindingRegType, pbuf->iff.pub->ipmip.ifname, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src), ((Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet))[1])); goto error_out; case IPMIP4_TYPE_REG_REPLY: case IPMIP4_TYPE_REG_HRQST: case IPMIP4_TYPE_REG_HRPLY: default: IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Unknown registration type %d received on %s from %s, discarding registration message", pbuf->pktinfo.haBindingRegType, pbuf->iff.pub->ipmip.ifname, ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src))); goto error_out; } error_out: ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } /* *=========================================================================== * ipmipha_reg_revoke_request *=========================================================================== * Description: Send a revocation request for this particular binding * Parameters: data - Data * proc - Process * node - Node * binding - Binding * Returns: * */ IP_GLOBAL Ip_bool ipmipha_reg_revoke_request(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_node_t *node, Ipmipha_node_binding_t *binding) { /**/ Ipmip_buffer_t rbuf; Ipmip4_regrevreq_t regrev; ipcom_memset(®rev, 0, sizeof(regrev)); regrev.type = IPMIP4_TYPE_REG_REGREVREQ; regrev.home_address = node->haNodeHomeAddress.prefix; regrev.home_domain = node->ifp->iff.ifaddr; regrev.foreign_domain = binding->mib.haMobilityBindingCOA.s_addr; binding->haBindingRevocationTimeStamp = ipmip4_util_now() + 1; regrev.identifier = ip_htonl(binding->haBindingRevocationTimeStamp); regrev.flags = ip_htons(IPMIP4_REG_EXT_REGREV_FLAG_AGENT); if (IP_BIT_ISSET(binding->haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_INFORM)) regrev.flags |= ip_htons(IPMIP4_REG_EXT_REGREV_FLAG_INFORM); ipmip_buffer_init(&rbuf); /* Add the header */ ipmip_buffer_append(&rbuf, ®rev, sizeof(regrev)); if (IP_BIT_ISTRUE(binding->mib.haMobilityBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION)) { if (node->haLastHomeSA == IP_NULL) goto error_out; if (!ipmip4_auth_append_mobile_to_home(&rbuf, node->haLastHomeSA)) goto error_out; } else { if (binding->haLastForeignSA == IP_NULL) goto error_out; if (!ipmip4_auth_append_foreign_to_home(&rbuf, binding->haLastForeignSA)) goto error_out; } /* Send packet using UDP socket */ if (ipmip4_pkt_udp_sendmsg(&data->ipmip4, proc, &rbuf, node->ifp->iff.ifaddr, data->ipmip4.pkt->s_udp_out.sin_port, binding->haBindingTunnelingEndpoint, binding->haBindingTunnelingPort, IP_NULL) == IP_TRUE) { ipmip_buffer_release(&rbuf); return IP_TRUE; } error_out: /* Remove the reference */ ipmip_buffer_release(&rbuf); return IP_FALSE; } enum { IPMIPHA_REG_REQUEST_INIT, IPMIPHA_REG_REQUEST_CREATE, IPMIPHA_REG_REQUEST_PROCESS, IPMIPHA_REG_REQUEST_AAA, IPMIPHA_REG_REQUEST_FA_AUTH, IPMIPHA_REG_REQUEST_HA_AUTH, IPMIPHA_REG_REQUEST_AUTH_DONE, IPMIPHA_REG_REQUEST_EXT, IPMIPHA_REG_REQUEST_PARAMS, IPMIPHA_REG_REQUEST_HOME_ADDRESS, IPMIPHA_REG_REQUEST_BINDING_UPDATE, IPMIPHA_REG_REQUEST_ENABLE }; /* *=========================================================================== * ipmipha_reg_request_process *=========================================================================== * Description: Process a container stage * Parameters: pbuf - The packet buffer * req - Type of major request * Returns: IP_FALSE * */ IP_GLOBAL int ipmipha_reg_request_process(int event, Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf, Ipmipha_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmipha_node_binding_t *binding = IP_NULL; if (node != IP_NULL) pbuf->node = node; else { /* Restore any stored values */ node = (Ipmipha_node_t *)pbuf->node; } /* Always init binding */ binding = (Ipmipha_node_binding_t *)pbuf->binding; if (node) ipmip_timer_prepare(&data->ipmip4.ipmip, proc, &node->service, node->lock, (Ipmip_timer_func_t)ipmipha_reg_request_process, pbuf, node); switch (pbuf->pktinfo.haBindingParsingState) { case IPMIPHA_REG_REQUEST_INIT: if (node == IP_NULL) { /* Are we trying to use address allocation? */ if (pbuf->pktinfo.haBindingHomeAddress == 0) { /* Check if there's a NAI already matching this particular node */ pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_CREATE; if (ipmipha_node_nai_lookup(data, proc, pbuf->iff.priv, pbuf->ipmip4.ext.mobile.nai_mobile, &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipha_reg_request_process, pbuf)) return IPMIP_TIMER_RET_DONE; } } else { /* Flag up the last SA used for mobile home bindings; */ pbuf->pktinfo.haBindingSPIMobileHome = node->haLastHomeSA; } /* this is an intentional fall through to the next case */ case IPMIPHA_REG_REQUEST_CREATE: if (node == IP_NULL) { /* Silently discard */ if (IP_BIT_ISSET(data->shutdown, IPMIPHA_SHUTDOWN_NODE)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to agent being paused", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); return ipmipha_reg_request_error(data, proc, pbuf, 0); } if (pbuf->pktinfo.haBindingHomeAddress == 0 && pbuf->ipmip4.ext.mobile.nai_mobile == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to neither nai nor home address is specified (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST); } /* No node found; create one */ node = ipmipha_node_create(data, proc, pbuf->iff.priv, pbuf->pktinfo.haBindingHomeAddress, pbuf->ipmip4.ext.mobile.nai_mobile); if (node == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to out of memory allocating node (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES); } /* Store the node */ pbuf->node = node; /* Invoke recursively */ pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_PROCESS; ipmip_timer_call(&data->ipmip4.ipmip, proc, node->lock, (Ipmip_timer_func_t)ipmipha_reg_request_process, pbuf, node); return IPMIP_TIMER_RET_DONE; } /* FALL THROUGH */ case IPMIPHA_REG_REQUEST_PROCESS: if (pbuf->ipmip4.ipmip.message != 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to %s (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message, pbuf->ipmip4.ipmip.error_code)); return ipmipha_reg_request_error(data, proc, pbuf, pbuf->ipmip4.ipmip.error_code); } /* Try find the appropriate binding */ if (binding == IP_NULL) { if ((binding = ipmipha_node_binding_coa(data, proc, node, pbuf->pktinfo.haBindingCOA)) != IP_NULL) pbuf->binding = binding; } /* No keyreq's */ if (node->haBindingHomeSA != IP_NULL) pbuf->pktinfo.haBindingMobileHomeSAPolicyOK = ipmipha_reg_verify_keygen(node->haBindingHomeSA, (Ipmip4_ext_auth_t*)pbuf->ipmip4.ext.mobile.mobile_home); /* FALL THROUGH */ case IPMIPHA_REG_REQUEST_AAA: pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_AAA; if (ipmipha_node_function_request_validate(data, proc, node, pbuf, IPMIPHA_FUNCTION_AAA)) return IPMIP_TIMER_RET_PENDING; if (pbuf->ipmip4.ipmip.message != IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to %s (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message, IPMIP4_CODE_REP_HA_BAD_AAA_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_BAD_AAA_AUTH); } if (pbuf->haBindingAAAVerified == IP_TRUE) node->haNodeAAAVerificationTime = pbuf->haBindingTimeStamp; else if (pbuf->pktinfo.haBindingForeignHomeSAPolicyOK == 0 || pbuf->pktinfo.haBindingMobileHomeSAPolicyOK == 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to Insufficient security extensions supplied, and the mn-aaa extension could not be processed (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); return ipmipha_reg_request_error(data, proc, pbuf, 0); } /* FALL THROUGH */ case IPMIPHA_REG_REQUEST_HA_AUTH: /* If there's a security association created due to AAA; indicate it */ if (node->haBindingHomeSA != IP_NULL) pbuf->pktinfo.haBindingSPIMobileHome = node->haBindingHomeSA; /* Verify */ if (pbuf->ipmip4.ext.mobile.mobile_home) { /**/ Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.mobile_home; /* We have SPI's assigned to this particular node; these SPI's has been created * due to AAA, and aren't globally available -- If they exist, the MUST be matched */ if (pbuf->pktinfo.haBindingSPIMobileHome != IP_NULL) { /* Use packet buffer's new SA first; fall back on nodes otherwise */ if (pbuf->pktinfo.haBindingSPIMobileHome->spi != IP_GET_HTONL(auth->spi)) { /* Bad SPI */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to bad SPI %d in mobile-home authentication extension, do not match AAA generated SPI %d (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IP_GET_HTONL(auth->spi), pbuf->pktinfo.haBindingSPIMobileHome->spi, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH); } } else { if (node->haLastHomeSA == IP_NULL || node->haLastHomeSA->spi != IP_GET_HTONL(auth->spi)) { pbuf->pktinfo.haBindingSPIMobileHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi)); if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to bad SPI in mobile-home authentication extension, do not match any configured security association SPI %d (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IP_GET_HTONL(auth->spi), IPMIP4_CODE_REP_HA_MN_FAILED_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH); } if (pbuf->iff.priv->security.spi_mn_lookup_required) { if (node->haLastHomeSA != IP_NULL) { /* Go use the configured value */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to mobile node used an invalid security association SPI %d, configured to use %d (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->pktinfo.haBindingSPIMobileHome->spi, node->haLastHomeSA->spi, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH)); pbuf->pktinfo.haBindingSPIMobileHome = node->haLastHomeSA; return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH); } else { Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_home_sa(data, proc, pbuf); if (spi == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to mobile node lacks configured security association with this home agent", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); pbuf->pktinfo.haBindingSPIMobileHome = IP_NULL; return ipmipha_reg_request_error(data, proc, pbuf, 0); } else if(spi->spi != pbuf->pktinfo.haBindingSPIMobileHome->spi) { /* Go use the configured value */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to mobile node used an invalid security association SPI %d, configured to use %d (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->pktinfo.haBindingSPIMobileHome->spi, spi->spi, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH)); pbuf->pktinfo.haBindingSPIMobileHome = spi; return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH); } } } } else { /* Use the cached SPI */ pbuf->pktinfo.haBindingSPIMobileHome = node->haLastHomeSA; } } pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_FA_AUTH; if (ipmip4_auth_verify(&data->ipmip4, proc, &pbuf->ipmip4, pbuf->ipmip4.ext.mobile.mobile_home, pbuf->pktinfo.haBindingSPIMobileHome, node->lock, (Ipmip_timer_func_t)ipmipha_reg_request_process)) return IPMIP_TIMER_RET_PENDING; } else if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL) { /* Set it to the binding SA */ if ((pbuf->pktinfo.haBindingSPIMobileHome = ipmipha_reg_spi_lookup_home_sa(data, proc, pbuf)) == IP_NULL) { /* Unknown security association */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to mobile node lacks security association with home agent", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); return ipmipha_reg_request_error(data, proc, pbuf, 0); } } /* FALL THROUGH */ /* this is an intentional fall through to the next case */ case IPMIPHA_REG_REQUEST_FA_AUTH: if (pbuf->ipmip4.ipmip.message != IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to %s (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH); } /* Verify */ if (pbuf->pktinfo.haBindingTimeGranted != 0) { if (pbuf->ipmip4.ext.mobile.foreign_home) { Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home; /* Verify the SPI we should use for foreign agent */ if (pbuf->haBindingForeignSA != IP_NULL || (binding != IP_NULL && binding->haBindingForeignSA != IP_NULL)) { pbuf->pktinfo.haBindingSPIForeignHome = pbuf->haBindingForeignSA? pbuf->haBindingForeignSA : binding->haBindingForeignSA; if(IP_GET_HTONL(auth->spi) != pbuf->pktinfo.haBindingSPIForeignHome->spi) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to foreign agent used an invalid security association SPI %d, should use generated %d (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IP_GET_HTONL(auth->spi), pbuf->pktinfo.haBindingSPIForeignHome->spi, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH); } } else if (binding == IP_NULL || binding->haLastForeignSA == IP_NULL || binding->haLastForeignSA->spi != IP_GET_HTONL(auth->spi)) { pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi)); if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL) { /* Unknown security association */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to foreign agent requested a non-existant security association (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_FA_FAILED_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH); } if (pbuf->iff.priv->security.spi_fa_lookup_required) { Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_foreign_sa(data, proc, pbuf); if (spi == IP_NULL) { /* Unknown security association */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to foreign agent lacks configured security association with this home agent (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_FA_FAILED_AUTH)); pbuf->pktinfo.haBindingSPIForeignHome = IP_NULL; return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH); } else if(spi->spi != pbuf->pktinfo.haBindingSPIForeignHome->spi) { /* Go use the configured value */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to foreign agent used an invalid security association SPI %d, configured to use %d (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->pktinfo.haBindingSPIForeignHome->spi, spi->spi, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH)); pbuf->pktinfo.haBindingSPIForeignHome = spi; return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH); } } } else { pbuf->pktinfo.haBindingSPIForeignHome = binding->haLastForeignSA; } pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_AUTH_DONE; if (ipmip4_auth_verify(&data->ipmip4, proc, &pbuf->ipmip4, pbuf->ipmip4.ext.mobile.foreign_home, pbuf->pktinfo.haBindingSPIForeignHome, node->lock, (Ipmip_timer_func_t)ipmipha_reg_request_process)) return IPMIP_TIMER_RET_PENDING; } else { /* Store the SA */ if (pbuf->haBindingForeignSA != IP_NULL || (binding != IP_NULL && binding->haBindingForeignSA != IP_NULL)) pbuf->pktinfo.haBindingSPIForeignHome = pbuf->haBindingForeignSA? pbuf->haBindingForeignSA : binding->haBindingForeignSA; } } /* this is an intentional fall through to the next case */ case IPMIPHA_REG_REQUEST_AUTH_DONE: if (pbuf->ipmip4.ipmip.message != 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to %s (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH); } if (pbuf->ipmip4.ext.mobile.nai_mobile == IP_NULL && pbuf->iff.priv->mn_nai_require) { /* Go use the configured value */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to mobile node did not provide mobile NAI, and home agent configured to require it (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT); } /* Deal with the CVSE; */ switch (pbuf->ipmip4.ext.mobile.result) { case IPMIP4_REG_EXT_UNKNOWN_VSE: if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.erronous, pbuf->pktinfo.haBindingAAAAuth)) { /* Mobile node provided VSE */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to invalid or unsupported CVSE sent by the mobile node (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_ERROR_HA_1)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ERROR_HA_1); } else { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to invalid or unsupported CVSE sent by the foreign agent (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_ERROR_HA_2)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ERROR_HA_2); } } if (IP_BIT_ISTRUE(node->state, IPMIPHA_NODE_STATE_HOME_ADDRESS)) pbuf->pktinfo.haBindingResolvedHomeAddress = node->haNodeHomeAddress.prefix; /* this is an intentional fall through to the next case */ case IPMIPHA_REG_REQUEST_EXT: pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_EXT; if (ipmipha_node_function_request_validate(data, proc, node, pbuf, IPMIPHA_FUNCTION_REGEXT)) return IPMIP_TIMER_RET_PENDING; if (node->registrations == 0) { if (pbuf->pktinfo.haBindingResolvedHomeAgentAddress) pbuf->pktinfo.haBindingHomeAgentAddress = pbuf->pktinfo.haBindingResolvedHomeAgentAddress; } else { /**/ pbuf->pktinfo.haBindingHomeAgentAddress = pbuf->iff.pub->ifaddr; } if (pbuf->ipmip4.ipmip.message != 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to %s (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), pbuf->ipmip4.ipmip.message, pbuf->ipmip4.ipmip.error_code)); return ipmipha_reg_request_error(data, proc, pbuf, pbuf->ipmip4.ipmip.error_code); } if (pbuf->pktinfo.haBindingHomeAgentAddress != pbuf->iff.pub->ifaddr) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to request not destined for this home agent(discovery?) (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_UNKNOWN_HOME_AGENT_ADDR)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_UNKNOWN_HOME_AGENT_ADDR); } /* FALL THROUGH */ case IPMIPHA_REG_REQUEST_PARAMS: /* Set the agent bit */ if (pbuf->iff.priv->replay_diff != 0) { Ip_time_t packet_time = (Ip_time_t) (ip_ntohl(pbuf->pktinfo.haBindingRegIDHigh) - IPMIP4_JAN_1970); if ((unsigned)(pbuf->haBindingTimeStamp - packet_time) > pbuf->iff.priv->replay_diff) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to replay protection: request time = %s, HA time = %s, diff=%d seconds (allowed=%d) (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), ipmip_ntop_time(proc, packet_time), ipmip_ntop_time(proc, pbuf->haBindingTimeStamp), pbuf->haBindingTimeStamp - packet_time, pbuf->iff.priv->replay_diff, IPMIP4_CODE_REP_HA_REG_ID_MISMATCH)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_REG_ID_MISMATCH); } } if (pbuf->pktinfo.haBindingTimeGranted != 0) { pbuf->pktinfo.haBindingTunnelType = ipmipha_reg_tunnel_type(pbuf); if (pbuf->iff.priv->tunnel.enabled[pbuf->pktinfo.haBindingTunnelType] == IP_FALSE) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to encapsulation %s unavailable (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), ipmip_util_tunnel_to_name(pbuf->pktinfo.haBindingTunnelType), IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL); } /* Reverse tunneling required but not set */ if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_REVERSE_TUNNELING) && pbuf->iff.priv->tunnel.reverse == IPMIP_SYSVAR_MODE_REQUIRED) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to reverse tunneling required - T bit not set (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_REV_TUNNEL_MANDATORY)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_REV_TUNNEL_MANDATORY); } /* Reverse tunneling forbidden but set */ else if (IP_BIT_ISTRUE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_REVERSE_TUNNELING) && pbuf->iff.priv->tunnel.reverse == IPMIP_SYSVAR_MODE_DISABLED) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to reverse tunneling forbidden - T bit is set (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_REV_TUNNEL_UNAVAIL)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_REV_TUNNEL_UNAVAIL); } } if (pbuf->ipmip4.ext.mobile.revocation != IP_NULL) { IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_REQUESTED); if (pbuf->iff.priv->revocation) { Ipmip4_reg_ext_revocation_t *req = (Ipmip4_reg_ext_revocation_t *)pbuf->ipmip4.ext.mobile.revocation; Ip_u16 flags; /* Mobile node 'extension', but no 'D' flag set? */ if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION)) { if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.revocation, pbuf->pktinfo.haBindingInnerAuth)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to 'D' flag not set in request, but mobile node appended revocation extension (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST); } if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.revocation, pbuf->pktinfo.haBindingOuterAuth)) IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_RECEIVED); } else { if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.revocation, pbuf->pktinfo.haBindingInnerAuth)) IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_RECEIVED); } if (IP_BIT_ARESET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_CONFIRMED)) { Ipmip4_reg_ext_revocation_t rev_rep; ipcom_memset(&rev_rep, 0, sizeof(rev_rep)); flags = IP_GET_NTOHS(&req->flags); pbuf->pktinfo.haBindingRevocationInform = IP_BIT_ISTRUE(flags, IPMIP4_REG_EXT_REVOCATION_INFORM); pbuf->pktinfo.haBindingRevocationTimeStamp = IP_GET_NTOHL(&req->timestamp); rev_rep.type = IPMIP4_EXT_TYPE_REVOCATION; rev_rep.length = sizeof(rev_rep) - 2; rev_rep.timestamp = ipmip4_util_now(); rev_rep.timestamp = ip_htonl(rev_rep.timestamp); /* */ if (pbuf->pktinfo.haBindingRevocationInform) rev_rep.flags |= ip_htons(IPMIP4_REG_EXT_REVOCATION_INFORM); if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION)) ipmip4_msgext_buffer_append_shdr(&pbuf->reply_fa, (void *)&rev_rep); else ipmip4_msgext_buffer_append_shdr(&pbuf->reply_mn, (void *)&rev_rep); } } } if (pbuf->ipmip4.ext.mobile.udp_tunnel_req != IP_NULL) { IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_NAT_T_REQUESTED); /* UDP encapsulation requested */ if (pbuf->iff.priv->nat_t) { Ipmip4_reg_ext_udp_tunnel_req_t *req = (Ipmip4_reg_ext_udp_tunnel_req_t *) pbuf->ipmip4.ext.mobile.udp_tunnel_req; Ip_u8 encap; encap = ipmip_util_proto_to_tunnel(req->encap); /**/ if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.udp_tunnel_req, pbuf->pktinfo.haBindingInnerAuth)) { /* Mobile node 'extension', but no 'D' flag set? */ if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to 'D' flag not set in request, but mobile node used NAT-T (RFC3519) UDP Tunnel request (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST); } /* This registration is done through the FA; co-located forced registration */ if (IP_BIT_ISTRUE(req->flags, IPMIP4_REG_EXT_UDP_FLAG_REGREQ)) { /* Mark it as a pending NAT-T */ IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_NAT_T_UNRESOLVED); } } else { /* Foreign agent 'extension', but co-located flag set? */ if (IP_BIT_ISTRUE(req->flags, IPMIP4_REG_EXT_UDP_FLAG_REGREQ)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to 'R' flag set in NAT-T (RFC3519) UDP Tunnel requests, but extension outside MN-HA authentication (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST); } } pbuf->pktinfo.haBindingTunnelEndpoint = pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr; { Ipmip4_reg_ext_udp_tunnel_rep_t rep; ipcom_memset(&rep, 0, sizeof(rep)); if (pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr == pbuf->pktinfo.haBindingCOA && IP_BIT_ISFALSE(req->flags, IPMIP4_REG_EXT_UDP_FLAG_FORCED)) rep.code = 64; else { IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_NAT_T_RECEIVED); if (encap != IPMIP_TUNNELTYPE_NONE && encap != pbuf->pktinfo.haBindingTunnelType) { if (pbuf->iff.priv->tunnel.enabled[encap] == IP_FALSE) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to nat traversal encapsulation %s unavailable (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), ipmip_util_tunnel_to_name(encap), IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL); } pbuf->pktinfo.haBindingTunnelType = encap; } } rep.keep_alive = ip_htons(pbuf->iff.priv->nat_t_keepalive); rep.type = IPMIP4_EXT_TYPE_UDP_TUNNEL_REP; rep.length = sizeof(rep) - 2; rep.flags = req->flags & IPMIP4_REG_EXT_UDP_FLAG_FORCED; if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.udp_tunnel_req, pbuf->pktinfo.haBindingInnerAuth)) ipmip4_msgext_buffer_append_shdr(&pbuf->reply_mn, (void *)&rep); else ipmip4_msgext_buffer_append_shdr(&pbuf->reply_fa, (void *)&rep); } } } /* FALL THROUGH */ case IPMIPHA_REG_REQUEST_HOME_ADDRESS: if (node->haNodeHomeAddress.prefix != 0) pbuf->pktinfo.haBindingHomeAddress = node->haNodeHomeAddress.prefix; else if (pbuf->pktinfo.haBindingResolvedHomeAddress != 0) pbuf->pktinfo.haBindingHomeAddress = pbuf->pktinfo.haBindingResolvedHomeAddress; if (pbuf->pktinfo.haBindingHomeAddress == 0) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to unable to assign home address to request (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT); } if (IP_BIT_ISFALSE(node->state, IPMIPHA_NODE_STATE_HOME_ADDRESS)) { /**/ if (node->haNodeHomeAddress.prefix == 0 && !ipmipha_node_home_address_assign(data, proc, node, pbuf->pktinfo.haBindingHomeAddress)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to home address collision in dynamic assignment (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT); } IP_BIT_SET(node->state, IPMIPHA_NODE_STATE_HOME_ADDRESS); } /* FALL THROUGH */ case IPMIPHA_REG_REQUEST_BINDING_UPDATE: /* */ if (pbuf->pktinfo.haBindingTimeGranted == 0) { if (pbuf->pktinfo.haBindingCOA == node->haNodeHomeAddress.prefix) { /* Complete de-registration */ ipmipha_node_binding_delete(data, proc, node, IP_NULL); ipmipha_node_silence(data, proc, node); } else if (binding != IP_NULL) { /* Delete this particular binding */ ipmipha_node_binding_delete(data, proc, node, binding); } /* Remove the pointers to this binding */ pbuf->binding = IP_NULL; binding = IP_NULL; } else { /**/ if (binding == IP_NULL) { if (pbuf->iff.priv->simbind_enabled && IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_SIM_BINDINGS)) { Ipmipha_node_binding_t *collission; /* Too many simbinds? */ if (node->bindings.size >= pbuf->iff.priv->simbind_max) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to too many simultaneous bindings (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_TOO_MANY_SIM)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_TOO_MANY_SIM); } collission = ipmipha_node_binding_endpoint(data, proc, node, pbuf->pktinfo.haBindingTunnelEndpoint); /* If we collide; revoke the colliding endpoint */ if (collission) { IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Node %s registration of binding collided with a previous binding due to NAT-T. Old binding deleted", ipmipha_node_describe(proc, node, binding))); ipmipha_node_binding_delete(data, proc, node, collission); } } else { if (IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_SIM_BINDINGS)) { IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haMultiBindingUnsupported, 1); pbuf->pktinfo.haBindingHAErrorCode = IPMIP4_CODE_REP_REG_ACCEPTED_BUT_NO_SIM_BINDS; } /* No SIM binds; revoke all other */ IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Node %s is moving, revoke old bindings", ipmipha_node_describe(proc, node, binding))); ipmipha_node_binding_revoke(data, proc, node, IP_NULL, IPMIP_SYSVAR_MODE_OPTIONAL, IP_TRUE); } /**/ binding = ipmipha_node_binding_create(data, proc, node, pbuf); /* */ if (binding == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to out of memory allocating binding (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES)); return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES); } /* reregister */ IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Node %s registered", ipmipha_node_describe(proc, node, binding))); } else { /* reregister */ IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Node %s re-registered", ipmipha_node_describe(proc, node, binding))); ipmipha_node_binding_update(data, proc, node, binding, pbuf); } /**/ ipmipha_node_function_request_accept(data, proc, node, binding, pbuf); } /* */ IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegistrationAccepted, 1); /* Update security associations */ ipmipha_node_security_associations(data, proc, node, binding, pbuf); case IPMIPHA_REG_REQUEST_ENABLE: pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_ENABLE; if (ipmipha_node_enable(data, proc, node)) return IPMIP_TIMER_RET_PENDING; /* Reply */ ipmipha_reg_reply(data, proc, node, pbuf); break; } return IPMIP_TIMER_RET_DONE; } else { /* Cancelled or aborted */ ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IPMIP_TIMER_RET_DONE; } } /* *=========================================================================== * ipmipha_reg_input_parse_request *=========================================================================== * Description: Parses basic values in a registration request. * Parameters: data - Data context * proc - Process * pbuf - Packet buffer. * Returns: IP_TRUE on success * */ IP_GLOBAL Ip_bool ipmipha_reg_input_parse_request(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_pktbuf_t *pbuf) { /* Check length */ if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < IPMIP4_REGREQ_LENGTH) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Truncated registration request [%d]", IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } else { /* Pointers to the packet */ Ipmip4_regreq_t *regreq = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); /* Store pending reg information */ pbuf->pktinfo.haBindingRegIDLow = IP_GET_32ON8(®req->id[1]); pbuf->pktinfo.haBindingRegIDHigh = IP_GET_32ON8(®req->id[0]); pbuf->pktinfo.haBindingHomeAgentAddress = IP_GET_32ON8(®req->home_agent); pbuf->pktinfo.haBindingHomeAddress = IP_GET_32ON8(®req->home_addr); pbuf->pktinfo.haBindingHomeAddressRequested = pbuf->pktinfo.haBindingHomeAddress; pbuf->pktinfo.haBindingTimeGranted = IP_GET_HTONS(®req->lifetime); pbuf->pktinfo.haBindingTimeGranted = IP_MIN(pbuf->pktinfo.haBindingTimeGranted, pbuf->iff.priv->lifetime); /* Store vital registration information */ pbuf->pktinfo.haBindingCOA = IP_GET_32ON8(®req->care_of_addr); pbuf->pktinfo.haBindingTunnelEndpoint = pbuf->pktinfo.haBindingCOA; pbuf->pktinfo.haBindingRegFlags = regreq->code; /* If its a DHAA request; make certain to home address isn't explicitly set */ if ((pbuf->pktinfo.haBindingHomeAgentAddress == 0 || pbuf->pktinfo.haBindingHomeAgentAddress == 0xffffffff)) { /* This home address is tentative; dont be too certain about it */ pbuf->pktinfo.haBindingHomeAddress = 0; } } /* OK */ pbuf->ipmip4.ext.mobile.result = ipmip4_msgext_mobile_parse_ext(&data->ipmip4, proc, &pbuf->ipmip4, IPMIP4_REGREQ_LENGTH); /* Parse extensions */ switch (pbuf->ipmip4.ext.mobile.result) { case IPMIP4_REG_EXT_FAILED_AUTH: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to bad or duplicate authentication extensions (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_FA_MN_FAILED_AUTH)); ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH); return IP_FALSE; case IPMIP4_REG_EXT_POORLY_FORMED: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to poorly formed request (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_FA_MN_FAILED_AUTH)); ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST); return IP_FALSE; case IPMIP4_REG_EXT_DISCARD: IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } /* Do we have an error code? */ if (pbuf->ipmip4.ipmip.message != 0) return IP_FALSE; /* Process this packet buffer */ /* No mobile home? */ /* No mobile home? */ if (pbuf->ipmip4.ext.mobile.mobile_home == IP_NULL && pbuf->ipmip4.ext.mobile.mn_aaa == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to no mobile-home authentication or mn-aaa extension header found", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } else if (pbuf->ipmip4.ext.mobile.mobile_home && pbuf->ipmip4.ext.mobile.mn_aaa && IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.mn_aaa, pbuf->ipmip4.ext.mobile.mobile_home)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to mn-aaa extension within mobile-home authentication", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } if (pbuf->ipmip4.ext.mobile.mobile_home != IP_NULL) { pbuf->pktinfo.haBindingInnerAuth = pbuf->ipmip4.ext.mobile.mobile_home; pbuf->pktinfo.haBindingInnerAuthSize = IPMIP4_MSGEXT_SHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.mobile_home); pbuf->pktinfo.haBindingMobileHomeSAPolicyOK = IP_TRUE; } if (pbuf->ipmip4.ext.mobile.foreign_home != IP_NULL) { pbuf->pktinfo.haBindingOuterAuth = pbuf->ipmip4.ext.mobile.foreign_home; pbuf->pktinfo.haBindingOuterAuthSize = IPMIP4_MSGEXT_SHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.foreign_home); pbuf->pktinfo.haBindingForeignHomeSAPolicyOK = IP_TRUE; } /**/ if (pbuf->ipmip4.ext.mobile.mn_aaa != IP_NULL) { pbuf->pktinfo.haBindingAAAAuth = pbuf->ipmip4.ext.mobile.mn_aaa; pbuf->pktinfo.haBindingAAAAuthSize = IPMIP4_MSGEXT_LHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.mn_aaa); if (pbuf->pktinfo.haBindingInnerAuth == IP_NULL) { pbuf->pktinfo.haBindingInnerAuth = pbuf->pktinfo.haBindingAAAAuth; pbuf->pktinfo.haBindingInnerAuthSize = pbuf->pktinfo.haBindingAAAAuthSize; } if (pbuf->pktinfo.haBindingOuterAuth == IP_NULL) { pbuf->pktinfo.haBindingOuterAuth = pbuf->pktinfo.haBindingAAAAuth; pbuf->pktinfo.haBindingOuterAuthSize = pbuf->pktinfo.haBindingAAAAuthSize; } } else { pbuf->pktinfo.haBindingAAAAuth = pbuf->ipmip4.ext.mobile.mobile_home; pbuf->pktinfo.haBindingAAAAuthSize = IPMIP4_MSGEXT_SHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.mobile_home); } /* Truncate; remove any mobile to foreign data */ ipmip_buffer_shrink(&pbuf->ipmip4.ipmip.packet, ((Ip_u8 *)pbuf->pktinfo.haBindingAAAAuth - (Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet)) + pbuf->pktinfo.haBindingAAAAuthSize); /* Dont use a NAI that's not authenticated */ if (pbuf->ipmip4.ext.mobile.nai_mobile != IP_NULL && IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.nai_mobile, pbuf->pktinfo.haBindingInnerAuth) == IP_FALSE) pbuf->ipmip4.ext.mobile.nai_mobile = IP_NULL; /* Do we have a foreign-home authentication? */ if (pbuf->pktinfo.haBindingForeignHomeSAPolicyOK == IP_FALSE) { /* Do we require it? */ if (pbuf->pktinfo.haBindingTimeGranted != 0 && pbuf->iff.priv->fa_auth != 0 && IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request discarded due to required foreign-home authentication extension header not found (%d)", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA), IPMIP4_CODE_REP_HA_FA_FAILED_AUTH)); ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH); return IP_FALSE; } pbuf->pktinfo.haBindingForeignHomeSAPolicyOK = IP_TRUE; } if (pbuf->ipmip4.ext.mobile.challenge) { if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.challenge, pbuf->ipmip4.ext.mobile.mobile_home)) { /* The challenge is not part of the MF authentication extension */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to challenge extension within mobile-home authentication", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.challenge, pbuf->pktinfo.haBindingAAAAuth) == IP_FALSE) { /* The challenge is not part of the MF authentication extension */ IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to challenge extension not properly protected with mobile-foreign authentication", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } } /* Verify keyreq */ if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq != IP_NULL && !IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.mn_ha_keyreq, pbuf->ipmip4.ext.mobile.mn_aaa)) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "%s@%s[%s] registration request silently discarded due to mn-ha key generation request not protected by mn-aaa authentication extension", ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress), pbuf->iff.pub->ipmip.ifname, ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA))); ipmipha_reg_request_error(data, proc, pbuf, 0); return IP_FALSE; } return IP_TRUE; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */