//----------------------------------------------------------------------------- int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) { #ifdef PDCP_USE_NETLINK protocol_ctxt_t ctxt_cpy = *ctxt_pP; protocol_ctxt_t ctxt; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; struct pdcp_netlink_element_s* data_p = NULL; module_id_t ue_id = 0; pdcp_t* pdcp_p = NULL; # if defined(PDCP_USE_NETLINK_QUEUES) rb_id_t rab_id = 0; pdcp_transmission_mode_t pdcp_mode = PDCP_TRANSMISSION_MODE_UNKNOWN; while (pdcp_netlink_dequeue_element(ctxt_pP, &data_p) != 0) { DevAssert(data_p != NULL); rab_id = data_p->pdcp_read_header.rb_id % maxDRB; // ctxt_pP->rnti is NOT_A_RNTI ctxt_cpy.rnti = pdcp_module_id_to_rnti[ctxt_cpy.module_id][data_p->pdcp_read_header.inst]; key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_cpy.rnti, ctxt_pP->enb_flag, rab_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); if (h_rc != HASH_TABLE_OK) { LOG_W(PDCP, PROTOCOL_CTXT_FMT" Dropped IP PACKET cause no PDCP instanciated\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); free(data_p->data); free(data_p); data_p = NULL; continue; } CHECK_CTXT_ARGS(&ctxt_cpy); AssertFatal (rab_id < maxDRB, "RB id is too high (%u/%d)!\n", rab_id, maxDRB); if (rab_id != 0) { LOG_D(PDCP, "[FRAME %05d][%s][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ " "/ %d Bytes --->][PDCP][MOD %u][RB %u]\n", ctxt_cpy.frame, (ctxt_cpy.enb_flag) ? "eNB" : "UE", data_p->pdcp_read_header.inst, data_p->pdcp_read_header.rb_id, data_p->pdcp_read_header.data_size, ctxt_cpy.module_id, rab_id); #ifdef OAI_NW_DRIVER_TYPE_ETHERNET if ((data_p->pdcp_read_header.traffic_type == TRAFFIC_IPV6_TYPE_MULTICAST) /*TRAFFIC_IPV6_TYPE_MULTICAST */ || (data_p->pdcp_read_header.traffic_type == TRAFFIC_IPV4_TYPE_MULTICAST) /*TRAFFIC_IPV4_TYPE_MULTICAST */ || (data_p->pdcp_read_header.traffic_type == TRAFFIC_IPV4_TYPE_BROADCAST) /*TRAFFIC_IPV4_TYPE_BROADCAST */ ) { #if defined (Rel10) PDCP_TRANSMISSION_MODE_TRANSPARENT; #else pdcp_mode= PDCP_TRANSMISSION_MODE_DATA; #endif } else if ((data_p->pdcp_read_header.traffic_type == TRAFFIC_IPV6_TYPE_UNICAST) /* TRAFFIC_IPV6_TYPE_UNICAST */ || (data_p->pdcp_read_header.traffic_type == TRAFFIC_IPV4_TYPE_UNICAST) /*TRAFFIC_IPV4_TYPE_UNICAST*/ ) { pdcp_mode= PDCP_TRANSMISSION_MODE_DATA; } else { pdcp_mode= PDCP_TRANSMISSION_MODE_DATA; LOG_W(PDCP,"unknown IP traffic type \n"); } #else // OAI_NW_DRIVER_TYPE_ETHERNET NASMESH driver does not curreenlty support multicast traffic pdcp_mode = PDCP_TRANSMISSION_MODE_DATA; #endif pdcp_data_req(&ctxt_cpy, SRB_FLAG_NO, rab_id % maxDRB, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, data_p->pdcp_read_header.data_size, data_p->data, pdcp_mode); } else if (ctxt_cpy.enb_flag) { /* rb_id = 0, thus interpreated as broadcast and transported as * multiple unicast is a broadcast packet, we have to send this * packet on all default RABS of all connected UEs */ LOG_D(PDCP, "eNB Try Forcing send on DEFAULT_RAB_ID first_ue_local %u nb_ue_local %u\n", oai_emulation.info.first_ue_local, oai_emulation.info.nb_ue_local); for (ue_id = 0; ue_id < NB_UE_INST; ue_id++) { if (pdcp_module_id_to_rnti[ctxt_cpy.module_id][ue_id] != NOT_A_RNTI) { LOG_D(PDCP, "eNB Try Forcing send on DEFAULT_RAB_ID UE %d\n", ue_id); ctxt.module_id = ctxt_cpy.module_id; ctxt.rnti = ctxt_cpy.pdcp_module_id_to_rnti[ctxt_cpy.module_id][ue_id]; ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ctxt_cpy.enb_flag; pdcp_data_req( &ctxt, SRB_FLAG_NO, DEFAULT_RAB_ID, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, data_p->pdcp_read_header.data_size, data_p->data, PDCP_TRANSMISSION_MODE_DATA); } } } else { LOG_D(PDCP, "Forcing send on DEFAULT_RAB_ID\n"); pdcp_data_req( &ctxt_cpy, SRB_FLAG_NO, DEFAULT_RAB_ID, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, data_p->pdcp_read_header.data_size, data_p->data, PDCP_TRANSMISSION_MODE_DATA); } free(data_p->data); free(data_p); data_p = NULL; } return 0; # else /* PDCP_USE_NETLINK_QUEUES*/ int len = 1; rb_id_t rab_id = 0; while (len > 0) { len = recvmsg(nas_sock_fd, &nas_msg_rx, 0); if (len<=0) { // nothing in pdcp NAS socket //LOG_D(PDCP, "[PDCP][NETLINK] Nothing in socket, length %d \n", len); } else { for (nas_nlh_rx = (struct nlmsghdr *) nl_rx_buf; NLMSG_OK (nas_nlh_rx, len); nas_nlh_rx = NLMSG_NEXT (nas_nlh_rx, len)) { if (nas_nlh_rx->nlmsg_type == NLMSG_DONE) { LOG_D(PDCP, "[PDCP][NETLINK] RX NLMSG_DONE\n"); //return; } if (nas_nlh_rx->nlmsg_type == NLMSG_ERROR) { LOG_D(PDCP, "[PDCP][NETLINK] RX NLMSG_ERROR\n"); } if (pdcp_read_state_g == 0) { if (nas_nlh_rx->nlmsg_len == sizeof (pdcp_data_req_header_t) + sizeof(struct nlmsghdr)) { pdcp_read_state_g = 1; //get memcpy((void *)&pdcp_read_header_g, (void *)NLMSG_DATA(nas_nlh_rx), sizeof(pdcp_data_req_header_t)); LOG_D(PDCP, "[PDCP][NETLINK] RX pdcp_data_req_header_t inst %u, rb_id %u data_size %d\n", pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size); } else { LOG_E(PDCP, "[PDCP][NETLINK] WRONG size %d should be sizeof (pdcp_data_req_header_t) + sizeof(struct nlmsghdr)\n", nas_nlh_rx->nlmsg_len); } } else { pdcp_read_state_g = 0; // print_active_requests() #ifdef PDCP_DEBUG LOG_D(PDCP, "[PDCP][NETLINK] Something in socket, length %d \n", nas_nlh_rx->nlmsg_len - sizeof(struct nlmsghdr)); #endif #ifdef OAI_EMU // overwrite function input parameters, because only one netlink socket for all instances if (pdcp_read_header_g.inst < oai_emulation.info.nb_enb_local) { ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ENB_FLAG_YES; ctxt.module_id = pdcp_read_header_g.inst + oai_emulation.info.first_enb_local; ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id ][pdcp_read_header_g.rb_id / maxDRB + oai_emulation.info.first_ue_local]; rab_id = pdcp_read_header_g.rb_id % maxDRB; } else { ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ENB_FLAG_NO; ctxt.module_id = pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local + oai_emulation.info.first_ue_local; ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; rab_id = pdcp_read_header_g.rb_id; } CHECK_CTXT_ARGS(&ctxt); AssertFatal (rab_id < maxDRB, "RB id is too high (%u/%d)!\n", rab_id, maxDRB); /*LGpdcp_read_header.inst = (pdcp_read_header_g.inst >= oai_emulation.info.nb_enb_local) ? \ pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local+ NB_eNB_INST + oai_emulation.info.first_ue_local : pdcp_read_header_g.inst + oai_emulation.info.first_enb_local;*/ #else // OAI_EMU pdcp_read_header_g.inst = 0; #warning "TO DO CORRCT VALUES FOR ue mod id, enb mod id" ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ctxt_cpy.enb_flag; if (ctxt_cpy.enb_flag) { ctxt.module_id = 0; rab_id = pdcp_read_header_g.rb_id % maxDRB; ctxt.rnti = pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index]; } else { ctxt.module_id = 0; rab_id = pdcp_read_header_g.rb_id % maxDRB; ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; } #endif if (ctxt.enb_flag) { if (rab_id != 0) { rab_id = rab_id % maxDRB; key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); if (h_rc == HASH_TABLE_OK) { #ifdef PDCP_DEBUG LOG_D(PDCP, "[FRAME %5u][eNB][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n", ctxt.frame, pdcp_read_header_g.inst, len, nas_nlh_rx->nlmsg_len-sizeof(struct nlmsghdr), pdcp_read_header_g.rb_id); #endif MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, rab_id, pdcp_read_header_g.data_size); LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u]UE %u][RB %u]\n", ctxt_cpy.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id); pdcp_data_req(&ctxt, SRB_FLAG_NO, rab_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pdcp_read_header_g.data_size, (unsigned char *)NLMSG_DATA(nas_nlh_rx), PDCP_TRANSMISSION_MODE_DATA); } else { LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %u][RB %u] NON INSTANCIATED INSTANCE, DROPPED\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id); } } else { // rb_id =0, thus interpreated as broadcast and transported as multiple unicast // is a broadcast packet, we have to send this packet on all default RABS of all connected UEs #warning CODE TO BE REVIEWED, ONLY WORK FOR SIMPLE TOPOLOGY CASES for (ue_id = 0; ue_id < NB_UE_INST; ue_id++) { if (oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt_cpy.module_id][ue_id] != NOT_A_RNTI) { ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt_cpy.module_id][ue_id]; LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %u][RB DEFAULT_RAB_ID %u]\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, DEFAULT_RAB_ID); pdcp_data_req ( &ctxt, SRB_FLAG_NO, DEFAULT_RAB_ID, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pdcp_read_header_g.data_size, (unsigned char *)NLMSG_DATA(nas_nlh_rx), PDCP_TRANSMISSION_MODE_DATA); } } } } else { // enb_flag if (rab_id != 0) { rab_id = rab_id % maxDRB; key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); if (h_rc == HASH_TABLE_OK) { #ifdef PDCP_DEBUG LOG_D(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n", ctxt.frame, pdcp_read_header_g.inst, len, nas_nlh_rx->nlmsg_len-sizeof(struct nlmsghdr), pdcp_read_header_g.rb_id); LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %u][RB %u]\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id); #endif MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, rab_id, pdcp_read_header_g.data_size); pdcp_data_req( &ctxt, SRB_FLAG_NO, rab_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pdcp_read_header_g.data_size, (unsigned char *)NLMSG_DATA(nas_nlh_rx), PDCP_TRANSMISSION_MODE_DATA); } else { MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, rab_id, pdcp_read_header_g.data_size); LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %u][RB %u] NON INSTANCIATED INSTANCE key 0x%"PRIx64", DROPPED\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id, key); } } else { LOG_D(PDCP, "Forcing send on DEFAULT_RAB_ID\n"); LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %u][RB DEFAULT_RAB_ID %u]\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, DEFAULT_RAB_ID); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL,0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u default rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, DEFAULT_RAB_ID, pdcp_read_header_g.data_size); pdcp_data_req ( &ctxt, SRB_FLAG_NO, DEFAULT_RAB_ID, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pdcp_read_header_g.data_size, (unsigned char *)NLMSG_DATA(nas_nlh_rx), PDCP_TRANSMISSION_MODE_DATA); } } } } } } return len; # endif #else // neither PDCP_USE_NETLINK nor PDCP_USE_RT_FIFO return 0; #endif // PDCP_USE_NETLINK }
//------------------------------------------------------------------------------ int s1ap_eNB_handle_nas_downlink(const uint32_t assoc_id, const uint32_t stream, struct s1ap_message_s* message_p) //------------------------------------------------------------------------------ { const S1ap_DownlinkNASTransportIEs_t *downlink_NAS_transport_p = NULL; s1ap_eNB_mme_data_t *mme_desc_p = NULL; s1ap_eNB_ue_context_t *ue_desc_p = NULL; s1ap_eNB_instance_t *s1ap_eNB_instance = NULL; DevAssert(message_p != NULL); downlink_NAS_transport_p = &message_p->msg.s1ap_DownlinkNASTransportIEs; /* UE-related procedure -> stream != 0 */ if (stream == 0) { S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream == 0\n", assoc_id); return -1; } if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) { S1AP_ERROR( "[SCTP %d] Received NAS downlink message for non existing MME context\n", assoc_id); return -1; } s1ap_eNB_instance = mme_desc_p->s1ap_eNB_instance; if ((ue_desc_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance, downlink_NAS_transport_p->eNB_UE_S1AP_ID)) == NULL) { MSC_LOG_RX_DISCARDED_MESSAGE( MSC_S1AP_ENB, MSC_S1AP_MME, (const char *)downlink_NAS_transport_p, sizeof(S1ap_DownlinkNASTransportIEs_t), MSC_AS_TIME_FMT" downlinkNASTransport eNB_ue_s1ap_id %u mme_ue_s1ap_id %u", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), downlink_NAS_transport_p->eNB_UE_S1AP_ID, downlink_NAS_transport_p->mme_ue_s1ap_id); S1AP_ERROR("[SCTP %d] Received NAS downlink message for non existing UE context eNB_UE_S1AP_ID: 0x%"PRIx32" %u\n", assoc_id, downlink_NAS_transport_p->eNB_UE_S1AP_ID, downlink_NAS_transport_p->eNB_UE_S1AP_ID); return -1; } if (0 == ue_desc_p->rx_stream) { ue_desc_p->rx_stream = stream; } else if (stream != ue_desc_p->rx_stream) { S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream %u, expecting %u\n", assoc_id, stream, ue_desc_p->rx_stream); return -1; } /* Is it the first outcome of the MME for this UE ? If so store the mme * UE s1ap id. */ if (ue_desc_p->mme_ue_s1ap_id == 0) { ue_desc_p->mme_ue_s1ap_id = downlink_NAS_transport_p->mme_ue_s1ap_id; } else { /* We already have a mme ue s1ap id check the received is the same */ if (ue_desc_p->mme_ue_s1ap_id != downlink_NAS_transport_p->mme_ue_s1ap_id) { S1AP_ERROR("[SCTP %d] Mismatch in MME UE S1AP ID (0x%"PRIx32" != 0x%"PRIx32")\n", assoc_id, downlink_NAS_transport_p->mme_ue_s1ap_id, ue_desc_p->mme_ue_s1ap_id ); return -1; } } MSC_LOG_RX_MESSAGE( MSC_S1AP_ENB, MSC_S1AP_MME, (const char *)downlink_NAS_transport_p, sizeof(S1ap_DownlinkNASTransportIEs_t), MSC_AS_TIME_FMT" downlinkNASTransport eNB_ue_s1ap_id %u mme_ue_s1ap_id %u", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), downlink_NAS_transport_p->eNB_UE_S1AP_ID, downlink_NAS_transport_p->mme_ue_s1ap_id); /* Forward the NAS PDU to RRC */ s1ap_eNB_itti_send_nas_downlink_ind(s1ap_eNB_instance->instance, ue_desc_p->ue_initial_id, ue_desc_p->eNB_ue_s1ap_id, downlink_NAS_transport_p->nas_pdu.buf, downlink_NAS_transport_p->nas_pdu.size); // LG: Why set to 0 ?? //ue_desc_p->ue_initial_id = 0; return 0; }
//----------------------------------------------------------------------------- int gtpv1u_create_s1u_tunnel( const instance_t instanceP, const gtpv1u_enb_create_tunnel_req_t * const create_tunnel_req_pP, gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP ) { /* Create a new nw-gtpv1-u stack req using API */ NwGtpv1uUlpApiT stack_req; NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; /* Local tunnel end-point identifier */ teid_t s1u_teid = 0; gtpv1u_teid_data_t *gtpv1u_teid_data_p = NULL; gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL; //MessageDef *message_p = NULL; hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS; int i; ebi_t eps_bearer_id = 0; // int ipv4_addr = 0; int ip_offset = 0; in_addr_t in_addr; int addrs_length_in_bytes= 0; MSC_LOG_RX_MESSAGE( MSC_GTPU_ENB, MSC_RRC_ENB, NULL,0, MSC_AS_TIME_FMT" CREATE_TUNNEL_REQ RNTI %"PRIx16" inst %u ntuns %u ebid %u sgw-s1u teid %u", 0,0,create_tunnel_req_pP->rnti, instanceP, create_tunnel_req_pP->num_tunnels, create_tunnel_req_pP->eps_bearer_id[0], create_tunnel_req_pP->sgw_S1u_teid[0]); create_tunnel_resp_pP->rnti = create_tunnel_req_pP->rnti; create_tunnel_resp_pP->status = 0; create_tunnel_resp_pP->num_tunnels = 0; for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) { ip_offset = 0; eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i]; LOG_D(GTPU, "Rx GTPV1U_ENB_CREATE_TUNNEL_REQ ue rnti %x eps bearer id %u\n", create_tunnel_req_pP->rnti, eps_bearer_id); memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT)); stack_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT; do { s1u_teid = gtpv1u_new_teid(); LOG_D(GTPU, "gtpv1u_create_s1u_tunnel() 0x%x %u(dec)\n", s1u_teid, s1u_teid); stack_req.apiInfo.createTunnelEndPointInfo.teid = s1u_teid; stack_req.apiInfo.createTunnelEndPointInfo.hUlpSession = 0; stack_req.apiInfo.createTunnelEndPointInfo.hStackSession = 0; rc = nwGtpv1uProcessUlpReq(gtpv1u_data_g.gtpv1u_stack, &stack_req); LOG_D(GTPU, ".\n"); } while (rc != NW_GTPV1U_OK); //----------------------- // PDCP->GTPV1U mapping //----------------------- hash_rc = hashtable_get(gtpv1u_data_g.ue_mapping, create_tunnel_req_pP->rnti, (void **)>pv1u_ue_data_p); if ((hash_rc == HASH_TABLE_KEY_NOT_EXISTS) || (hash_rc == HASH_TABLE_OK)) { if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { gtpv1u_ue_data_p = calloc (1, sizeof(gtpv1u_ue_data_t)); hash_rc = hashtable_insert(gtpv1u_data_g.ue_mapping, create_tunnel_req_pP->rnti, gtpv1u_ue_data_p); AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting ue_mapping in GTPV1U hashtable"); } gtpv1u_ue_data_p->ue_id = create_tunnel_req_pP->rnti; gtpv1u_ue_data_p->instance_id = 0; // TO DO memcpy(&create_tunnel_resp_pP->enb_addr.buffer, >pv1u_data_g.enb_ip_address_for_S1u_S12_S4_up, sizeof (in_addr_t)); create_tunnel_resp_pP->enb_addr.length = sizeof (in_addr_t); addrs_length_in_bytes = create_tunnel_req_pP->sgw_addr[i].length / 8; AssertFatal((addrs_length_in_bytes == 4) || (addrs_length_in_bytes == 16) || (addrs_length_in_bytes == 20), "Bad transport layer address length %d (bits) %d (bytes)", create_tunnel_req_pP->sgw_addr[i].length, addrs_length_in_bytes); if ((addrs_length_in_bytes == 4) || (addrs_length_in_bytes == 20)) { in_addr = *((in_addr_t*)create_tunnel_req_pP->sgw_addr[i].buffer); ip_offset = 4; gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].sgw_ip_addr = in_addr; } if ((addrs_length_in_bytes == 16) || (addrs_length_in_bytes == 20)) { memcpy(gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].sgw_ip6_addr.s6_addr, &create_tunnel_req_pP->sgw_addr[i].buffer[ip_offset], 16); } gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].state = BEARER_IN_CONFIG; gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_eNB = s1u_teid; gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_eNB_stack_session = stack_req.apiInfo.createTunnelEndPointInfo.hStackSession; gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_sgw = create_tunnel_req_pP->sgw_S1u_teid[i]; create_tunnel_resp_pP->enb_S1u_teid[i] = s1u_teid; } else { create_tunnel_resp_pP->enb_S1u_teid[i] = 0; create_tunnel_resp_pP->status = 0xFF; } create_tunnel_resp_pP->eps_bearer_id[i] = eps_bearer_id; create_tunnel_resp_pP->num_tunnels += 1; //----------------------- // GTPV1U->PDCP mapping //----------------------- hash_rc = hashtable_get(gtpv1u_data_g.teid_mapping, s1u_teid, (void**)>pv1u_teid_data_p); if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { gtpv1u_teid_data_p = calloc (1, sizeof(gtpv1u_teid_data_t)); gtpv1u_teid_data_p->enb_id = 0; // TO DO gtpv1u_teid_data_p->ue_id = create_tunnel_req_pP->rnti; gtpv1u_teid_data_p->eps_bearer_id = eps_bearer_id; hash_rc = hashtable_insert(gtpv1u_data_g.teid_mapping, s1u_teid, gtpv1u_teid_data_p); AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting teid mapping in GTPV1U hashtable"); } else { create_tunnel_resp_pP->enb_S1u_teid[i] = 0; create_tunnel_resp_pP->status = 0xFF; } } MSC_LOG_TX_MESSAGE( MSC_GTPU_ENB, MSC_RRC_ENB, NULL,0, "0 GTPV1U_ENB_CREATE_TUNNEL_RESP rnti %x teid %x", create_tunnel_resp_pP->rnti, s1u_teid); LOG_D(GTPU, "Tx GTPV1U_ENB_CREATE_TUNNEL_RESP ue rnti %x status %d\n", create_tunnel_req_pP->rnti, create_tunnel_resp_pP->status); return 0; }
static int s1ap_eNB_handle_ue_context_release_command(uint32_t assoc_id, uint32_t stream, struct s1ap_message_s *s1ap_message_p) { s1ap_eNB_mme_data_t *mme_desc_p = NULL; s1ap_eNB_ue_context_t *ue_desc_p = NULL; MessageDef *message_p = NULL; S1ap_UEContextReleaseCommandIEs_t *ueContextReleaseCommand_p; DevAssert(s1ap_message_p != NULL); ueContextReleaseCommand_p = &s1ap_message_p->msg.s1ap_UEContextReleaseCommandIEs; if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) { S1AP_ERROR("[SCTP %d] Received UE context release command for non " "existing MME context\n", assoc_id); return -1; } S1ap_MME_UE_S1AP_ID_t mme_ue_s1ap_id; S1ap_ENB_UE_S1AP_ID_t enb_ue_s1ap_id; switch (ueContextReleaseCommand_p->uE_S1AP_IDs.present) { case S1ap_UE_S1AP_IDs_PR_uE_S1AP_ID_pair: enb_ue_s1ap_id = ueContextReleaseCommand_p->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID; mme_ue_s1ap_id = ueContextReleaseCommand_p->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID; MSC_LOG_RX_MESSAGE( MSC_S1AP_ENB, MSC_S1AP_MME, NULL,0, "0 UEContextRelease/%s eNB_ue_s1ap_id "S1AP_UE_ID_FMT" mme_ue_s1ap_id "S1AP_UE_ID_FMT" len %u", s1ap_direction2String[s1ap_message_p->direction], enb_ue_s1ap_id, mme_ue_s1ap_id); if ((ue_desc_p = s1ap_eNB_get_ue_context(mme_desc_p->s1ap_eNB_instance, enb_ue_s1ap_id)) == NULL) { S1AP_ERROR("[SCTP %d] Received UE context release command for non " "existing UE context 0x%06x\n", assoc_id, enb_ue_s1ap_id); /*MessageDef *msg_complete_p; msg_complete_p = itti_alloc_new_message(TASK_RRC_ENB, S1AP_UE_CONTEXT_RELEASE_COMPLETE); S1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_complete_p).eNB_ue_s1ap_id = enb_ue_s1ap_id; itti_send_msg_to_task(TASK_S1AP, ue_desc_p->eNB_instance->instance <=> 0, msg_complete_p); */ return -1; } else { MSC_LOG_TX_MESSAGE( MSC_S1AP_ENB, MSC_RRC_ENB, NULL,0, "0 S1AP_UE_CONTEXT_RELEASE_COMMAND/%d eNB_ue_s1ap_id "S1AP_UE_ID_FMT" ", enb_ue_s1ap_id); message_p = itti_alloc_new_message(TASK_S1AP, S1AP_UE_CONTEXT_RELEASE_COMMAND); S1AP_UE_CONTEXT_RELEASE_COMMAND(message_p).eNB_ue_s1ap_id = enb_ue_s1ap_id; itti_send_msg_to_task(TASK_RRC_ENB, ue_desc_p->eNB_instance->instance, message_p); return 0; } break; #warning "TODO mapping mme_ue_s1ap_id enb_ue_s1ap_id?" case S1ap_UE_S1AP_IDs_PR_mME_UE_S1AP_ID: mme_ue_s1ap_id = ueContextReleaseCommand_p->uE_S1AP_IDs.choice.mME_UE_S1AP_ID; S1AP_ERROR("TO DO mapping mme_ue_s1ap_id enb_ue_s1ap_id"); case S1ap_UE_S1AP_IDs_PR_NOTHING: default: S1AP_ERROR("S1AP_UE_CONTEXT_RELEASE_COMMAND not processed, missing info elements"); return -1; } }
void config_req_rlc_um_asn1 ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, const MBMS_flag_t mbms_flagP, const mbms_session_id_t mbms_session_idP, const mbms_service_id_t mbms_service_idP, const UL_UM_RLC_t * const ul_rlc_pP, const DL_UM_RLC_t * const dl_rlc_pP, const rb_id_t rb_idP) { uint32_t ul_sn_FieldLength = 0; uint32_t dl_sn_FieldLength = 0; uint32_t t_Reordering = 0; rlc_union_t *rlc_union_p = NULL; rlc_um_entity_t *rlc_p = NULL; hash_key_t key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); hashtable_rc_t h_rc; #if Rel10 if (mbms_flagP) { AssertFatal(dl_rlc_pP, "No RLC UM DL config"); AssertFatal(ul_rlc_pP == NULL, "RLC UM UL config present"); key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_service_idP, mbms_session_idP); h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); AssertFatal (h_rc == HASH_TABLE_OK, "RLC NOT FOUND enb id %u rnti %i enb flag %u service id %u, session id %u", ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_service_idP, mbms_session_idP); rlc_p = &rlc_union_p->rlc.um; } else #endif { key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); AssertFatal (h_rc == HASH_TABLE_OK, "RLC NOT FOUND enb id %u ue id %i enb flag %u rb id %u, srb flag %u", ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); rlc_p = &rlc_union_p->rlc.um; } //----------------------------------------------------------------------------- LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" CONFIG_REQ timer_reordering=%dms sn_field_length= RB %u \n", PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_p), (dl_rlc_pP && dl_rlc_pP->t_Reordering<31)?t_Reordering_tab[dl_rlc_pP->t_Reordering]:-1, rb_idP); rlc_um_init(ctxt_pP, rlc_p); if (rlc_um_fsm_notify_event (ctxt_pP, rlc_p, RLC_UM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT)) { rlc_um_set_debug_infos(ctxt_pP,rlc_p, srb_flagP, rb_idP); if (ul_rlc_pP != NULL) { switch (ul_rlc_pP->sn_FieldLength) { case SN_FieldLength_size5: ul_sn_FieldLength = 5; break; case SN_FieldLength_size10: ul_sn_FieldLength = 10; break; default: LOG_E(RLC,PROTOCOL_RLC_UM_CTXT_FMT" [CONFIGURE] RB %u INVALID UL sn_FieldLength %d, RLC NOT CONFIGURED\n", PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_p), rlc_p->rb_id, ul_rlc_pP->sn_FieldLength); MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE, NULL, 0, MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ UL sn_FieldLength %u", MSC_AS_TIME_ARGS(ctxt_pP), PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc_p), ul_rlc_pP->sn_FieldLength); return; } } if (dl_rlc_pP != NULL) { switch (dl_rlc_pP->sn_FieldLength) { case SN_FieldLength_size5: dl_sn_FieldLength = 5; break; case SN_FieldLength_size10: dl_sn_FieldLength = 10; break; default: LOG_E(RLC,PROTOCOL_RLC_UM_CTXT_FMT" [CONFIGURE] RB %u INVALID DL sn_FieldLength %d, RLC NOT CONFIGURED\n", PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_p), rlc_p->rb_id, dl_rlc_pP->sn_FieldLength); MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE, NULL, 0, MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ DL sn_FieldLength %u", MSC_AS_TIME_ARGS(ctxt_pP), PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc_p), dl_rlc_pP->sn_FieldLength); return; } if (dl_rlc_pP->t_Reordering<T_Reordering_spare1) { t_Reordering = t_Reordering_tab[dl_rlc_pP->t_Reordering]; } else { LOG_E(RLC,PROTOCOL_RLC_UM_CTXT_FMT" [CONFIGURE] RB %u INVALID T_Reordering %d, RLC NOT CONFIGURED\n", PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_p), rlc_p->rb_id, dl_rlc_pP->t_Reordering); MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE, NULL, 0, MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ t_Reord %u", MSC_AS_TIME_ARGS(ctxt_pP), PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc_p), dl_rlc_pP->t_Reordering); return; } } if (ctxt_pP->enb_flag > 0) { rlc_um_configure(ctxt_pP,rlc_p, t_Reordering, ul_sn_FieldLength, dl_sn_FieldLength, mbms_flagP); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE, NULL, 0, MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ t_Reord %u rx snfl %u tx snfl %u", MSC_AS_TIME_ARGS(ctxt_pP), PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc_p), t_Reordering, ul_sn_FieldLength, dl_sn_FieldLength); } else { rlc_um_configure(ctxt_pP,rlc_p, t_Reordering, dl_sn_FieldLength, ul_sn_FieldLength, mbms_flagP); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE, NULL, 0, MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ t_Reord %u rx snfl %u tx snfl %u", MSC_AS_TIME_ARGS(ctxt_pP), PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc_p), t_Reordering, dl_sn_FieldLength, ul_sn_FieldLength); } } }
static NwGtpv1uRcT nwGtpv1uHandleEchoReq(NW_IN NwGtpv1uStackT *thiz, NW_IN uint8_t *msgBuf, NW_IN uint32_t msgBufLen, NW_IN uint16_t peerPort, NW_IN uint32_t peerIp) { NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; uint16_t seqNum = 0; NwGtpv1uMsgHandleT hMsg = 0; int bufLen = 0; seqNum = ntohs(*(uint16_t *) (msgBuf + (((*msgBuf) & 0x02) ? 8 : 4))); MSC_LOG_RX_MESSAGE( (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_ENB:MSC_GTPU_SGW, (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_SGW:MSC_GTPU_ENB, NULL, 0, MSC_AS_TIME_FMT" ECHO-REQ seq %u size %u", 0,0,seqNum, msgBufLen); /* Send Echo Response */ rc = nwGtpv1uMsgNew( (NwGtpv1uStackHandleT)thiz, NW_TRUE, /* SeqNum flag */ NW_FALSE, NW_FALSE, NW_GTP_ECHO_RSP, /* Msg Type */ 0x00000000U, /* TEID */ seqNum, /* Seq Number */ 0, 0, (&hMsg)); bufLen = sizeof(NwGtpv1uIeTv1T)+ ((NwGtpv1uMsgT*)hMsg)->msgLen; ((NwGtpv1uMsgT*)hMsg)->msgBuf = itti_malloc( TASK_GTPV1_U, TASK_UDP, bufLen); ((NwGtpv1uMsgT*)hMsg)->msgBufLen = bufLen; NW_ASSERT(NW_GTPV1U_OK == rc); /* * The Restart Counter value in the Recovery information element shall * not be used, i.e. it shall be set to zero by the sender and shall be * ignored by the receiver. */ rc = nwGtpv1uMsgAddIeTV1(hMsg, NW_GTPV1U_IE_RECOVERY, 0x00); #if defined(LOG_GTPU) && LOG_GTPU > 0 GTPU_INFO("Sending NW_GTP_ECHO_RSP message to %x:%x with seq %u\n", peerIp, peerPort, seqNum); #endif MSC_LOG_TX_MESSAGE( (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_ENB:MSC_GTPU_SGW, (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_SGW:MSC_GTPU_ENB, NULL, 0, MSC_AS_TIME_FMT" ECHO-RSP seq %u", 0,0,seqNum); rc = nwGtpv1uCreateAndSendMsg( thiz, peerIp, peerPort, (NwGtpv1uMsgT *) hMsg); rc = nwGtpv1uMsgDelete((NwGtpv1uStackHandleT)thiz, hMsg); NW_ASSERT(NW_GTPV1U_OK == rc); return rc; }
static NwGtpv1uRcT nwGtpv1uProcessGpdu( NwGtpv1uStackT *thiz, NW_IN uint8_t *gpdu, NW_IN uint32_t gpduLen, NW_IN uint32_t peerIp) { NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; NwGtpv1uMsgHeaderT *msgHdr = NULL; NwGtpv1uTunnelEndPointT *pTunnelEndPoint = NULL; NwGtpv1uTunnelEndPointT tunnelEndPointKey; // uint16_t hdr_len = 0; #if defined(LOG_GTPU) && LOG_GTPU > 0 NW_ENTER(thiz); #endif // no buffer offset msgHdr = (NwGtpv1uMsgHeaderT *) gpdu; tunnelEndPointKey.teid = ntohl(msgHdr->teid); pTunnelEndPoint = RB_FIND(NwGtpv1uTunnelEndPointIdentifierMap, &(thiz->teidMap), &tunnelEndPointKey); if(pTunnelEndPoint) { NwGtpv1uMsgHandleT hMsg; rc = nwGtpv1uMsgFromBufferNew( (NwGtpv1uStackHandleT)thiz, (uint8_t *)gpdu, gpduLen, &hMsg); /* uint8_t* msgBuf; uint32_t msgBufLen; uint32_t msgBufOffset; */ if(NW_GTPV1U_OK == rc) { NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; #if defined(LOG_GTPU) && LOG_GTPU > 0 GTPU_DEBUG("Received T-PDU over tunnel end-point '%x' of size %u (%u) (decapsulated %u)from "NW_IPV4_ADDR"\n", ntohl(msgHdr->teid), gpduLen, pMsg->msgLen, pMsg->msgBufLen, NW_IPV4_ADDR_FORMAT((peerIp))); #endif MSC_LOG_RX_MESSAGE( (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_ENB:MSC_GTPU_SGW, (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_SGW:MSC_GTPU_ENB, NULL, 0, " G-PDU ltid %u size %u", tunnelEndPointKey.teid, gpduLen); rc = nwGtpSessionSendMsgApiToUlpEntity(pTunnelEndPoint, pMsg); } } else { MSC_LOG_RX_DISCARDED_MESSAGE( (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_ENB:MSC_GTPU_SGW, (thiz->stackType == GTPU_STACK_ENB) ? MSC_GTPU_SGW:MSC_GTPU_ENB, NULL, 0, " G-PDU ltid %u size %u", tunnelEndPointKey.teid, gpduLen); GTPU_ERROR("Received T-PDU over non-existent tunnel end-point '%x' from "NW_IPV4_ADDR"\n", ntohl(msgHdr->teid), NW_IPV4_ADDR_FORMAT((peerIp))); } #if defined(LOG_GTPU) && LOG_GTPU > 0 NW_LEAVE(thiz); #endif return rc; }