--- /dev/null
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+
+/**
+ * @brief This file provides the API functions to build Control Plane Messages
+ * for XRAN Front Haul layer as defined in XRAN-FH.CUS.0-v02.01.
+ *
+ * @file xran_cp_api.c
+ * @ingroup group_lte_source_xran
+ * @author Intel Corporation
+ *
+ **/
+
+#include <rte_branch_prediction.h>
+
+#include "xran_common.h"
+#include "xran_transport.h"
+#include "xran_cp_api.h"
+#include "xran_hash.h"
+#include "xran_printf.h"
+
+
+struct xran_sectioninfo_db {
+ uint32_t max_num;
+ uint32_t cur_index;
+#if defined(XRAN_CP_USES_HASHTABLE)
+ struct rte_hash *hash;
+#endif
+ struct xran_section_info *list;
+ };
+
+
+static struct xran_sectioninfo_db *sectiondb[XRAN_DIR_MAX];
+
+int xran_cp_init_sectiondb(void *pHandle)
+{
+ int i, j, k;
+ uint32_t size;
+ uint16_t cid;
+ struct xran_sectioninfo_db *ptr;
+ uint8_t num_eAxc;
+
+
+#if !defined(PRACH_USES_SHARED_PORT)
+ num_eAxc = xran_get_num_eAxc(pHandle) * 2;
+#else
+ num_eAxc = xran_get_num_eAxc(pHandle);
+#endif
+
+ for(i=0; i < XRAN_DIR_MAX; i++) {
+ size = (xran_get_num_cc(pHandle) * num_eAxc * sizeof(struct xran_sectioninfo_db));
+ print_log("Allocation Size for Section DB : %d (%dx%dx%ld)", size
+ , xran_get_num_cc(pHandle)
+ , num_eAxc
+ , sizeof(struct xran_sectioninfo_db));
+ sectiondb[i] = malloc(size);
+
+ if(sectiondb[i] == NULL) {
+ print_err("Allocation Failed for Section DB!");
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+ for(j=0; j < xran_get_num_cc(pHandle); j++) { // CC
+ for(k=0; k < num_eAxc; k++) { // antenna
+ ptr = sectiondb[i] + num_eAxc*j + k;
+
+ ptr->max_num = xran_get_max_sections(pHandle);
+ ptr->cur_index = 0;
+
+ // allicate array to store section information
+ size = sizeof(struct xran_section_info)*xran_get_max_sections(pHandle);
+ print_log("Allocation Size for list : %d (%ldx%d)", size,
+ sizeof(struct xran_section_info),
+ xran_get_max_sections(pHandle));
+ ptr->list = malloc(size);
+ if(ptr-> list == NULL) {
+ print_err("Allocation Failed for Section DB!");
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+#if defined(XRAN_CP_USES_HASHTABLE)
+ // Create hash table for section information
+ cid = rte_be_to_cpu_16(xran_compose_cid(xran_get_llscuid(pHandle), xran_get_sectorid(pHandle), j, k));
+ print_log("Creating hash for %04X", cid);
+ ptr->hash = xran_section_init_hash(i, cid, xran_get_max_sections(pHandle));
+#endif
+ }
+ }
+ }
+
+ return (XRAN_ERRCODE_OK);
+}
+
+int xran_cp_free_sectiondb(void *pHandle)
+{
+ int i, j, k;
+ uint32_t size;
+ struct xran_sectioninfo_db *ptr;
+ uint8_t num_eAxc;
+
+#if !defined(PRACH_USES_SHARED_PORT)
+ num_eAxc = xran_get_num_eAxc(pHandle) * 2;
+#else
+ num_eAxc = xran_get_num_eAxc(pHandle);
+#endif
+
+ for(i=0; i < XRAN_DIR_MAX; i++) {
+ for(j=0; j < xran_get_num_cc(pHandle); j++) { // CC
+ for(k=0; k < num_eAxc; k++) { // antenna
+ ptr = sectiondb[i] + num_eAxc*j + k;
+
+#if defined(XRAN_CP_USES_HASHTABLE)
+ xran_section_free_hash(ptr->hash);
+#endif
+ if(ptr->list != NULL)
+ free(ptr->list);
+ else print_err("list is NULL");
+ }
+ }
+ if(sectiondb[i] != NULL)
+ free(sectiondb[i]);
+ else print_err("sectiondb[%d] is NULL", i);
+ }
+
+ return (XRAN_ERRCODE_OK);
+}
+
+static struct xran_sectioninfo_db *xran_get_section_db(void *pHandle,
+ uint8_t dir, uint8_t cc_id, uint8_t ruport_id)
+{
+ struct xran_sectioninfo_db *ptr;
+ uint8_t num_eAxc;
+
+ if(unlikely(dir>=XRAN_DIR_MAX)) {
+ print_err("Invalid direction - %d", dir);
+ return (NULL);
+ }
+
+ if(unlikely(cc_id >= xran_get_num_cc(pHandle))) {
+ print_err("Invalid CC id - %d", cc_id);
+ return (NULL);
+ }
+
+#if !defined(PRACH_USES_SHARED_PORT)
+ num_eAxc = xran_get_num_eAxc(pHandle) * 2;
+#else
+ num_eAxc = xran_get_num_eAxc(pHandle);
+#endif
+
+ if(unlikely(ruport_id >= num_eAxc)) {
+ print_err("Invalid eAxC id - %d", ruport_id);
+ return (NULL);
+ }
+
+ ptr = sectiondb[dir] + xran_get_num_eAxc(pHandle)*cc_id + ruport_id;
+
+ return(ptr);
+}
+
+static struct xran_section_info *xran_get_section_info(struct xran_sectioninfo_db *ptr, uint16_t index)
+{
+ if(unlikely(ptr == NULL))
+ return (NULL);
+
+ if(unlikely(ptr->max_num < index)) {
+ print_err("Index is out of range - %d", index);
+ return (NULL);
+ }
+
+ return(&(ptr->list[index]));
+}
+
+int xran_cp_add_section_info(void *pHandle,
+ uint8_t dir, uint8_t cc_id, uint8_t ruport_id,
+ uint8_t subframe_id, uint8_t slot_id,
+ struct xran_section_info *info)
+{
+ struct xran_sectioninfo_db *ptr;
+ struct xran_section_info *list;
+
+ ptr = xran_get_section_db(pHandle, dir, cc_id, ruport_id);
+ if(unlikely(ptr == NULL)) {
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ if(unlikely(ptr->cur_index >= ptr->max_num)) {
+ print_err("No more space to add section information!");
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+ list = xran_get_section_info(ptr, ptr->cur_index);
+
+ rte_memcpy(list, info, sizeof(struct xran_section_info));
+#if defined(XRAN_CP_USES_HASHTABLE)
+ xran_section_add_hash(ptr->hash, info->id, ptr->cur_index);
+#endif
+
+ ptr->cur_index++;
+
+ return (XRAN_ERRCODE_OK);
+}
+
+int xran_cp_add_multisection_info(void *pHandle,
+ uint8_t dir, uint8_t cc_id, uint8_t ruport_id,
+ uint8_t subframe_id, uint8_t slot_id,
+ uint8_t num_sections, struct xran_section_gen_info *gen_info)
+{
+ int i;
+ struct xran_sectioninfo_db *ptr;
+ struct xran_section_info *list;
+
+ ptr = xran_get_section_db(pHandle, dir, cc_id, ruport_id);
+ if(unlikely(ptr == NULL)) {
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ if(unlikely(ptr->cur_index >= (ptr->max_num+num_sections))) {
+ print_err("No more space to add section information!");
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+ list = xran_get_section_info(ptr, ptr->cur_index);
+
+ for(i=0; i<num_sections; i++) {
+ rte_memcpy(&list[i], &gen_info[i].info, sizeof(struct xran_section_info));
+#if defined(XRAN_CP_USES_HASHTABLE)
+ xran_section_add_hash(ptr->hash, gen_info[i].info.id, ptr->cur_index);
+#endif
+ ptr->cur_index++;
+ }
+
+ return (XRAN_ERRCODE_OK);
+}
+
+struct xran_section_info *xran_cp_find_section_info(void *pHandle,
+ uint8_t dir, uint8_t cc_id, uint8_t ruport_id,
+ uint8_t subframe_id, uint8_t slot_id,
+ uint16_t section_id)
+{
+ int index;
+ struct xran_sectioninfo_db *ptr;
+
+
+ ptr = xran_get_section_db(pHandle, dir, cc_id, ruport_id);
+ if(unlikely(ptr == NULL))
+ return (NULL);
+
+#if defined(XRAN_CP_USES_HASHTABLE)
+ index = xran_section_lookup(ptr->hash, section_id);
+ if(unlikely(index > ptr->max_num)) {
+ print_err("Invalid index - %d", index);
+ return (NULL);
+ }
+
+ if(index < 0) {
+ print_dbg("No section ID in the list - %d", section_id);
+ return (NULL);
+ }
+
+ return (xran_get_section_info(ptr, index));
+#else
+ for(index=0; index<ptr->cur_index; index++) {
+ if(ptr->list[index].id == section_id) {
+ print_dbg("Found section info %04X", section_id);
+ return (xran_get_section_info(ptr, index));
+ }
+ }
+
+ print_dbg("No section ID in the list - %d", section_id);
+ return (NULL);
+#endif
+
+}
+
+struct xran_section_info *xran_cp_iterate_section_info(void *pHandle,
+ uint8_t dir, uint8_t cc_id, uint8_t ruport_id,
+ uint8_t subframe_id, uint8_t slot_id, uint32_t *next)
+{
+ int index;
+ struct xran_sectioninfo_db *ptr;
+
+
+ ptr = xran_get_section_db(pHandle, dir, cc_id, ruport_id);
+ if(unlikely(ptr == NULL))
+ return (NULL);
+
+#if defined(XRAN_CP_USES_HASHTABLE)
+ index = xran_section_iterate(ptr->hash, next);
+ if(unlikely(index > ptr->max_num)) {
+ print_err("Invalid index - %d", index);
+ return (NULL);
+ }
+
+ if(index < 0) {
+ print_dbg("No section ID in the list - %d", section_id);
+ return (NULL);
+ }
+
+ return (xran_get_section_info(ptr, index));
+#else
+ index = *next;
+ if(*next < ptr->cur_index) {
+ (*next)++;
+ return (xran_get_section_info(ptr, index));
+ }
+ else
+ print_dbg("No more sections in the list");
+
+ return (NULL);
+#endif
+}
+
+int xran_cp_getsize_section_info(void *pHandle, uint8_t dir, uint8_t cc_id, uint8_t ruport_id)
+{
+ int i, index;
+ struct xran_sectioninfo_db *ptr;
+
+
+ ptr = xran_get_section_db(pHandle, dir, cc_id, ruport_id);
+ if(unlikely(ptr == NULL))
+ return (-1);
+
+ return (ptr->cur_index);
+}
+
+int xran_cp_reset_section_info(void *pHandle, uint8_t dir, uint8_t cc_id, uint8_t ruport_id)
+{
+ struct xran_sectioninfo_db *ptr;
+
+ ptr = xran_get_section_db(pHandle, dir, cc_id, ruport_id);
+ if(unlikely(ptr == NULL)) {
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ ptr->cur_index = 0;
+#if defined(XRAN_CP_USES_HASHTABLE)
+ xran_section_reset_hash(ptr->hash);
+#endif
+
+ return (XRAN_ERRCODE_OK);
+}
+
+int xran_dump_sectiondb(void)
+{
+ // TODO:
+ return (0);
+}
+
+
+// Cyclic Prefix Length 5.4.4.14
+// CP_length = cpLength * Ts * 2^u, Ts = 1/30.72MHz, if u is N/A, it shall be zero
+#define CPLEN_TS (30720000)
+inline uint16_t xran_get_cplength(int cpLength, int uval) // uval = -1 for N/A
+{
+ return ((cpLength * ((uval<0)?0:(2<<uval))) / (CPLEN_TS));
+}
+
+// Frequency offset 5.4.5.11
+// frequency_offset = freqOffset * SCS * 0.5
+inline int32_t xran_get_freqoffset(int freqOffset, int scs)
+{
+ return ((freqOffset * scs)>>1);
+}
+
+
+/**
+ * @brief Fill the section body of type 0 in C-Plane packet
+ *
+ * @param section
+ * A pointer to the section in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static int xran_prepare_section0(
+ struct xran_cp_radioapp_section0 *section,
+ struct xran_section_gen_info *params)
+{
+#if (XRAN_STRICT_PARM_CHECK)
+ if(unlikely(params->info.numSymbol > XRAN_SYMBOLNUMBER_MAX)) {
+ print_err("Invalid number of Symbols - %d", params->info.numSymbol);
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+#endif
+
+ section->hdr.sectionId = params->info.id;
+ section->hdr.rb = params->info.rb;
+ section->hdr.symInc = params->info.symInc;
+ section->hdr.startPrbc = params->info.startPrbc;
+ section->hdr.numPrbc = params->info.numPrbc;
+
+ section->hdr.u.s0.reMask = params->info.reMask;
+ section->hdr.u.s0.numSymbol = params->info.numSymbol;
+ section->hdr.u.s0.reserved = 0;
+
+ // for network byte order
+ *((uint64_t *)section) = rte_cpu_to_be_64(*((uint64_t *)section));
+
+ return (XRAN_ERRCODE_OK);
+}
+/**
+ * @brief Fill the section header of type 0 in C-Plane packet
+ *
+ * @param s0hdr
+ * A pointer to the section header in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static int xran_prepare_section0_hdr(
+ struct xran_cp_radioapp_section0_header *s0hdr,
+ struct xran_cp_gen_params *params)
+
+{
+ s0hdr->timeOffset = rte_cpu_to_be_16(params->hdr.timeOffset);
+ s0hdr->frameStructure.fftSize = params->hdr.fftSize;
+ s0hdr->frameStructure.uScs = params->hdr.scs;
+ s0hdr->cpLength = rte_cpu_to_be_16(params->hdr.cpLength);
+ s0hdr->reserved = 0;
+
+ return (XRAN_ERRCODE_OK);
+}
+
+/**
+ * @brief Fill the section body of type 1 in C-Plane packet
+ * Extension is not supported.
+ *
+ * @param section
+ * A pointer to the section header in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static int xran_prepare_section1(
+ struct xran_cp_radioapp_section1 *section,
+ struct xran_section_gen_info *params)
+{
+#if (XRAN_STRICT_PARM_CHECK)
+ if(unlikely(params->info.numSymbol > XRAN_SYMBOLNUMBER_MAX)) {
+ print_err("Invalid number of Symbols - %d", params->info.numSymbol);
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+#endif
+
+ section->hdr.sectionId = params->info.id;
+ section->hdr.rb = params->info.rb;
+ section->hdr.symInc = params->info.symInc;
+ section->hdr.startPrbc = params->info.startPrbc;
+ section->hdr.numPrbc = params->info.numPrbc;
+
+ section->hdr.u.s1.reMask = params->info.reMask;
+ section->hdr.u.s1.numSymbol = params->info.numSymbol;
+ section->hdr.u.s1.beamId = params->info.beamId;
+
+ if(params->info.ef) {
+ // TODO: need to handle extension
+ print_err("Extension is not supported!");
+ section->hdr.u.s1.ef = 0;
+// section->hdr.u.s1.ef = params->info.ef;
+ }
+ else
+ section->hdr.u.s1.ef = 0;
+
+ // for network byte order
+ *((uint64_t *)section) = rte_cpu_to_be_64(*((uint64_t *)section));
+
+ return (XRAN_ERRCODE_OK);
+}
+/**
+ * @brief Fill the section header of type 1 in C-Plane packet
+ *
+ * @param s1hdr
+ * A pointer to the section header in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static int xran_prepare_section1_hdr(
+ struct xran_cp_radioapp_section1_header *s1hdr,
+ struct xran_cp_gen_params *params)
+{
+ s1hdr->udComp.udIqWidth = params->hdr.iqWidth;
+ s1hdr->udComp.udCompMeth = params->hdr.compMeth;
+ s1hdr->reserved = 0;
+
+ return (XRAN_ERRCODE_OK);
+}
+
+/**
+ * @brief Fill the section body of type 3 in C-Plane packet
+ * Extension is not supported.
+ *
+ * @param section
+ * A pointer to the section header in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static int xran_prepare_section3(
+ struct xran_cp_radioapp_section3 *section,
+ struct xran_section_gen_info *params)
+{
+#if (XRAN_STRICT_PARM_CHECK)
+ if(unlikely(params->info.numSymbol > XRAN_SYMBOLNUMBER_MAX)) {
+ print_err("Invalid number of Symbols - %d", params->info.numSymbol);
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+#endif
+
+ section->hdr.sectionId = params->info.id;
+ section->hdr.rb = params->info.rb;
+ section->hdr.symInc = params->info.symInc;
+ section->hdr.startPrbc = params->info.startPrbc;
+ section->hdr.numPrbc = params->info.numPrbc;
+
+ section->hdr.u.s3.reMask = params->info.reMask;
+ section->hdr.u.s3.numSymbol = params->info.numSymbol;
+ section->hdr.u.s3.beamId = params->info.beamId;
+
+ section->freqOffset = rte_cpu_to_be_32(params->info.freqOffset)>>8;
+ section->reserved = 0;
+
+ if(params->info.ef) {
+ // TODO: need to handle extension
+ print_err("Extension is not supported!");
+ section->hdr.u.s3.ef = 0;
+// section->hdr.u.s3.ef = params->info.ef;
+ }
+ else
+ section->hdr.u.s3.ef = 0;
+
+ // for network byte order (header, 8 bytes)
+ *((uint64_t *)section) = rte_cpu_to_be_64(*((uint64_t *)section));
+
+ return (XRAN_ERRCODE_OK);
+}
+/**
+ * @brief Fill the section header of type 3 in C-Plane packet
+ *
+ * @param s3hdr
+ * A pointer to the section header in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static int xran_prepare_section3_hdr(
+ struct xran_cp_radioapp_section3_header *s3hdr,
+ struct xran_cp_gen_params *params)
+
+{
+ s3hdr->timeOffset = rte_cpu_to_be_16(params->hdr.timeOffset);
+ s3hdr->frameStructure.fftSize = params->hdr.fftSize;
+ s3hdr->frameStructure.uScs = params->hdr.scs;
+ s3hdr->cpLength = rte_cpu_to_be_16(params->hdr.cpLength);
+ s3hdr->udComp.udIqWidth = params->hdr.iqWidth;
+ s3hdr->udComp.udCompMeth = params->hdr.compMeth;
+
+ return (XRAN_ERRCODE_OK);
+}
+
+/**
+ * @brief add sections to C-Plane packet
+ * Section type 1 and 3 are supported.
+ *
+ * @param mbuf
+ * A pointer to the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+int xran_append_control_section(struct rte_mbuf *mbuf, struct xran_cp_gen_params *params)
+{
+ int i, ret;
+ uint32_t totalen;
+ void *section;
+ int section_size;
+ int (*xran_prepare_section_func)(void *section, void *params);
+
+
+ totalen = 0;
+ switch(params->sectionType) {
+ case XRAN_CP_SECTIONTYPE_0: /* Unused RB or Symbols in DL or UL, not supportted */
+ section_size = sizeof(struct xran_cp_radioapp_section0);
+ xran_prepare_section_func = (int (*)(void *, void *))xran_prepare_section0;
+ break;
+
+ case XRAN_CP_SECTIONTYPE_1: /* Most DL/UL Radio Channels */
+ section_size = sizeof(struct xran_cp_radioapp_section1);
+ xran_prepare_section_func = (int (*)(void *, void *))xran_prepare_section1;
+ break;
+
+ case XRAN_CP_SECTIONTYPE_3: /* PRACH and Mixed-numerology Channels */
+ section_size = sizeof(struct xran_cp_radioapp_section3);
+ xran_prepare_section_func = (int (*)(void *, void *))xran_prepare_section3;
+ break;
+
+ case XRAN_CP_SECTIONTYPE_5: /* UE scheduling information, not supported */
+ case XRAN_CP_SECTIONTYPE_6: /* Channel Information, not supported */
+ case XRAN_CP_SECTIONTYPE_7: /* LAA, not supported */
+ default:
+ section_size = 0;
+ xran_prepare_section_func = NULL;
+ print_err("Section Type %d is not supported!", params->sectionType);
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ if(unlikely(xran_prepare_section_func == NULL)) {
+ print_err("Section Type %d is not supported!", params->sectionType);
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ for(i=0; i<params->numSections; i++) {
+ section = rte_pktmbuf_append(mbuf, section_size);
+ if(section == NULL) {
+ print_err("Fail to allocate the space for section[%d]!", i);
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+ if(unlikely(xran_prepare_section_func((void *)section,
+ (void *)¶ms->sections[i]) < 0)) {
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ totalen += section_size;
+ }
+
+ return (totalen);
+}
+
+/**
+ * @brief fill the information of a radio application header in a C-Plane packet
+ *
+ * @param apphdr
+ * A pointer to the application header in the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+static inline int xran_prepare_radioapp_common_header(
+ struct xran_cp_radioapp_common_header *apphdr,
+ struct xran_cp_gen_params *params)
+{
+
+#if (XRAN_STRICT_PARM_CHECK)
+ if(unlikely(params->dir != XRAN_DIR_DL && params->dir != XRAN_DIR_UL)) {
+ print_err("Invalid direction!");
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+ if(unlikely(params->hdr.slotId > XRAN_SLOTID_MAX)) {
+ print_err("Invalid Slot ID!");
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+ if(unlikely(params->hdr.startSymId > XRAN_SYMBOLNUMBER_MAX)) {
+ print_err("Invalid Symbol ID!");
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+#endif
+
+ apphdr->dataDirection = params->dir;
+ apphdr->payloadVer = XRAN_PAYLOAD_VER;
+ apphdr->filterIndex = params->hdr.filterIdx;
+ apphdr->frameId = params->hdr.frameId;
+ apphdr->subframeId = params->hdr.subframeId;
+ apphdr->slotId = params->hdr.slotId;
+ apphdr->startSymbolId = params->hdr.startSymId;
+ apphdr->numOfSections = params->numSections;
+ apphdr->sectionType = params->sectionType;
+
+ // radio app header has common parts of 4bytes for all section types
+ *((uint32_t *)apphdr) = rte_cpu_to_be_32(*((uint32_t *)apphdr));
+
+ return (XRAN_ERRCODE_OK);
+}
+
+/**
+ * @brief add a radio application header in a C-Plane packet
+ *
+ * @param mbuf
+ * A pointer to the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @return
+ * 0 on success; non zero on failure
+ */
+int xran_append_radioapp_header(struct rte_mbuf *mbuf, struct xran_cp_gen_params *params)
+{
+ int ret;
+ uint32_t totalen;
+ struct xran_cp_radioapp_common_header *apphdr;
+ int (*xran_prepare_radioapp_section_hdr_func)(void *hdr, void *params);
+
+
+#if (XRAN_STRICT_PARM_CHECK)
+ if(unlikely(params->sectionType >= XRAN_CP_SECTIONTYPE_MAX)) {
+ print_err("Invalid Section Type - %d", params->sectionType);
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+#endif
+
+ switch(params->sectionType) {
+ case XRAN_CP_SECTIONTYPE_0: // Unused RB or Symbols in DL or UL, not supportted
+ xran_prepare_radioapp_section_hdr_func = (int (*)(void *, void*))xran_prepare_section0_hdr;
+ totalen = sizeof(struct xran_cp_radioapp_section0_header);
+ break;
+
+ case XRAN_CP_SECTIONTYPE_1: // Most DL/UL Radio Channels
+ xran_prepare_radioapp_section_hdr_func = (int (*)(void *, void*))xran_prepare_section1_hdr;
+ totalen = sizeof(struct xran_cp_radioapp_section1_header);
+ break;
+
+ case XRAN_CP_SECTIONTYPE_3: // PRACH and Mixed-numerology Channels
+ xran_prepare_radioapp_section_hdr_func = (int (*)(void *, void*))xran_prepare_section3_hdr;
+ totalen = sizeof(struct xran_cp_radioapp_section3_header);
+ break;
+
+ case XRAN_CP_SECTIONTYPE_5: // UE scheduling information, not supported
+ case XRAN_CP_SECTIONTYPE_6: // Channel Information, not supported
+ case XRAN_CP_SECTIONTYPE_7: // LAA, not supported
+ default:
+ print_err("Section Type %d is not supported!", params->sectionType);
+ xran_prepare_radioapp_section_hdr_func = NULL;
+ totalen = 0;
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ apphdr = (struct xran_cp_radioapp_common_header *)rte_pktmbuf_append(mbuf, totalen);
+ if(unlikely(apphdr == NULL)) {
+ print_err("Fail to reserve the space for radio application header!");
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+ ret = xran_prepare_radioapp_common_header(apphdr, params);
+ if(unlikely(ret < 0)) {
+ return (ret);
+ }
+
+ if(likely(xran_prepare_radioapp_section_hdr_func)) {
+ xran_prepare_radioapp_section_hdr_func(apphdr, params);
+ }
+ else {
+ print_err("xran_prepare_radioapp_section_hdr_func is NULL!");
+ return (-XRAN_ERRCODE_INVALIDPARAM);
+ }
+
+ return (totalen);
+}
+
+/**
+ * @brief Create a C-Plane packet
+ * Transport layer fragmentation is not supported.
+ *
+ * @ingroup xran_cp_pkt
+ *
+ * @param mbuf
+ * A pointer to the packet buffer
+ * @param params
+ * A porinter to the information to generate a C-Plane packet
+ * @param CC_ID
+ * Component Carrier ID for this C-Plane message
+ * @param Ant_ID
+ * Antenna ID(RU Port ID) for this C-Plane message
+ * @param seq_id
+ * Sequence ID for this C-Plane message
+ * @return
+ * 0 on success; non zero on failure
+ */
+int xran_prepare_ctrl_pkt(struct rte_mbuf *mbuf,
+ struct xran_cp_gen_params *params,
+ uint8_t CC_ID, uint8_t Ant_ID,
+ uint8_t seq_id)
+{
+ int ret;
+ uint32_t payloadlen;
+ struct xran_ecpri_hdr *ecpri_hdr;
+
+
+ ecpri_hdr = (struct xran_ecpri_hdr *)rte_pktmbuf_append(mbuf, sizeof(struct xran_ecpri_hdr));
+ if(unlikely(ecpri_hdr == NULL)) {
+ print_err("Fail to allocate the space for eCPRI hedaer!");
+ return (-XRAN_ERRCODE_OUTOFMEMORY);
+ }
+
+ ecpri_hdr->ecpri_ver = XRAN_ECPRI_VER;
+ ecpri_hdr->ecpri_resv = 0; // should be zero
+ ecpri_hdr->ecpri_concat = 0;
+ ecpri_hdr->ecpri_mesg_type = ECPRI_RT_CONTROL_DATA;
+ ecpri_hdr->ecpri_xtc_id = xran_compose_cid(0, 0, CC_ID, Ant_ID);
+ ecpri_hdr->ecpri_seq_id.seq_id = seq_id;
+
+ /* TODO: Transport layer fragmentation is not supported */
+ ecpri_hdr->ecpri_seq_id.sub_seq_id = 0;
+ ecpri_hdr->ecpri_seq_id.e_bit = 1;
+
+ payloadlen = 0;
+
+ ret = xran_append_radioapp_header(mbuf, params);
+ if(ret < 0) {
+ return (ret);
+ }
+ payloadlen += ret;
+
+ ret = xran_append_control_section(mbuf, params);
+ if(ret < 0) {
+ return (ret);
+ }
+ payloadlen += ret;
+
+// printf("Total Payload length = %d\n", payloadlen);
+ ecpri_hdr->ecpri_payl_size = rte_cpu_to_be_16(payloadlen);
+
+ return (XRAN_ERRCODE_OK);
+}
+
+///////////////////////////////////////
+// for Debug
+int xran_parse_cp_pkt(struct rte_mbuf *mbuf, struct xran_cp_gen_params *result)
+{
+ struct xran_ecpri_hdr *ecpri_hdr;
+ struct xran_cp_radioapp_common_header *apphdr;
+ int i, ret;
+ int extlen;
+
+
+ ret = 0;
+ ecpri_hdr = rte_pktmbuf_mtod(mbuf, void *);
+ if(ecpri_hdr == NULL) {
+ print_err("Invalid packet - eCPRI hedaer!");
+ return (-XRAN_ERRCODE_INVALIDPACKET);
+ }
+
+ /* Process eCPRI header. */
+ if(ecpri_hdr->ecpri_ver != XRAN_ECPRI_VER) {
+ print_err("Invalid eCPRI version - %d", ecpri_hdr->ecpri_ver);
+ ret = -XRAN_ERRCODE_INVALIDPACKET;
+ }
+
+ if(ecpri_hdr->ecpri_resv != 0) {
+ print_err("Invalid reserved field - %d", ecpri_hdr->ecpri_resv);
+ ret = -XRAN_ERRCODE_INVALIDPACKET;
+ }
+
+ if(ecpri_hdr->ecpri_mesg_type != ECPRI_RT_CONTROL_DATA) {
+ print_err("Not C-Plane Message - %d", ecpri_hdr->ecpri_mesg_type);
+ ret = -XRAN_ERRCODE_INVALIDPACKET;
+ }
+#if 0
+ printf("[CPlane] [%04X:%03d-%3d-%d] len=%5d\n",
+ rte_be_to_cpu_16(ecpri_hdr->ecpri_xtc_id),
+ ecpri_hdr->ecpri_seq_id.seq_id, ecpri_hdr->ecpri_seq_id.sub_seq_id,
+ ecpri_hdr->ecpri_seq_id.e_bit,
+ rte_be_to_cpu_16(ecpri_hdr->ecpri_payl_size));
+#endif
+
+ /* Process radio header. */
+ apphdr = (void *)rte_pktmbuf_adj(mbuf, sizeof(struct xran_ecpri_hdr));
+ if(apphdr == NULL) {
+ print_err("Invalid packet - radio app hedaer!");
+ return (-XRAN_ERRCODE_INVALIDPACKET);
+ }
+
+ *((uint32_t *)apphdr) = rte_cpu_to_be_32(*((uint32_t *)apphdr));
+
+ if(apphdr->payloadVer != XRAN_PAYLOAD_VER) {
+ print_err("Invalid Payload version - %d", apphdr->payloadVer);
+ ret = -XRAN_ERRCODE_INVALIDPACKET;
+ }
+
+ result->dir = apphdr->dataDirection;
+ result->hdr.filterIdx = apphdr->filterIndex;
+ result->hdr.frameId = apphdr->frameId;
+ result->hdr.subframeId = apphdr->subframeId;
+ result->hdr.slotId = apphdr->slotId;
+ result->hdr.startSymId = apphdr->startSymbolId;
+ result->sectionType = apphdr->sectionType;
+ result->numSections = apphdr->numOfSections;
+
+ switch(apphdr->sectionType) {
+ case XRAN_CP_SECTIONTYPE_0: // Unused RB or Symbols in DL or UL, not supportted
+ {
+ struct xran_cp_radioapp_section0_header *hdr;
+ struct xran_cp_radioapp_section0 *section;
+
+ hdr = (struct xran_cp_radioapp_section0_header*)apphdr;
+
+ result->hdr.fftSize = rte_be_to_cpu_16(hdr->timeOffset);
+ result->hdr.scs = hdr->frameStructure.fftSize;
+ result->hdr.timeOffset = hdr->frameStructure.uScs;
+ result->hdr.cpLength = rte_be_to_cpu_16(hdr->cpLength);
+ //hdr->reserved; /* should be zero */
+
+ section = (void *)rte_pktmbuf_adj(mbuf, sizeof(struct xran_cp_radioapp_section0_header));
+ if(section == NULL) {
+ print_err("Invalid packet 0 - radio app hedaer!");
+ return (-XRAN_ERRCODE_INVALIDPACKET);
+ }
+ for(i=0; i<result->numSections; i++) {
+ *((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
+
+ result->sections[i].info.type = apphdr->sectionType;
+ result->sections[i].info.id = section->hdr.sectionId;
+ result->sections[i].info.rb = section->hdr.rb;
+ result->sections[i].info.symInc = section->hdr.symInc;
+ result->sections[i].info.startPrbc = section->hdr.startPrbc;
+ result->sections[i].info.numPrbc = section->hdr.numPrbc,
+ result->sections[i].info.numSymbol = section->hdr.u.s0.numSymbol;
+ result->sections[i].info.reMask = section->hdr.u.s0.reMask;
+ //section->hdr.u.s0.reserved; /* should be zero */
+
+ section = (void *)rte_pktmbuf_adj(mbuf, sizeof(struct xran_cp_radioapp_section0));
+ if(section == NULL) {
+ print_err("Invalid packet 0 - number of section [%d:%d]!",
+ result->numSections, i);
+ result->numSections = i;
+ ret = (-XRAN_ERRCODE_INVALIDPACKET);
+ break;
+ }
+ }
+ }
+ break;
+
+ case XRAN_CP_SECTIONTYPE_1: // Most DL/UL Radio Channels
+ {
+ struct xran_cp_radioapp_section1_header *hdr;
+ struct xran_cp_radioapp_section1 *section;
+
+ hdr = (struct xran_cp_radioapp_section1_header*)apphdr;
+
+ result->hdr.iqWidth = hdr->udComp.udIqWidth;
+ result->hdr.compMeth = hdr->udComp.udCompMeth;
+
+ section = (void *)rte_pktmbuf_adj(mbuf, sizeof(struct xran_cp_radioapp_section1_header));
+ if(section == NULL) {
+ print_err("Invalid packet 1 - radio app hedaer!");
+ return (-XRAN_ERRCODE_INVALIDPACKET);
+ }
+
+ for(i=0; i<result->numSections; i++) {
+ *((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
+
+ result->sections[i].info.type = apphdr->sectionType;
+ result->sections[i].info.id = section->hdr.sectionId;
+ result->sections[i].info.rb = section->hdr.rb;
+ result->sections[i].info.symInc = section->hdr.symInc;
+ result->sections[i].info.startPrbc = section->hdr.startPrbc;
+ result->sections[i].info.numPrbc = section->hdr.numPrbc,
+ result->sections[i].info.numSymbol = section->hdr.u.s1.numSymbol;
+ result->sections[i].info.reMask = section->hdr.u.s1.reMask;
+ result->sections[i].info.beamId = section->hdr.u.s1.beamId;
+ result->sections[i].info.ef = section->hdr.u.s1.ef;
+
+ if(section->hdr.u.s1.ef) {
+ // TODO: handle section extension
+ extlen = 0;
+ }
+ else extlen = 0;
+
+ section = (void *)rte_pktmbuf_adj(mbuf,
+ sizeof(struct xran_cp_radioapp_section1)+extlen);
+ if(section == NULL) {
+ print_err("Invalid packet 1 - number of section [%d:%d]!",
+ result->numSections, i);
+ result->numSections = i;
+ ret = (-XRAN_ERRCODE_INVALIDPACKET);
+ break;
+ }
+ }
+ }
+ break;
+
+ case XRAN_CP_SECTIONTYPE_3: // PRACH and Mixed-numerology Channels
+ {
+ struct xran_cp_radioapp_section3_header *hdr;
+ struct xran_cp_radioapp_section3 *section;
+
+ hdr = (struct xran_cp_radioapp_section3_header*)apphdr;
+
+ result->hdr.timeOffset = rte_be_to_cpu_16(hdr->timeOffset);
+ result->hdr.scs = hdr->frameStructure.uScs;
+ result->hdr.fftSize = hdr->frameStructure.fftSize;
+ result->hdr.cpLength = rte_be_to_cpu_16(hdr->cpLength);
+ result->hdr.iqWidth = hdr->udComp.udIqWidth;
+ result->hdr.compMeth = hdr->udComp.udCompMeth;
+
+ section = (void *)rte_pktmbuf_adj(mbuf, sizeof(struct xran_cp_radioapp_section3_header));
+ if(section == NULL) {
+ print_err("Invalid packet 3 - radio app hedaer!");
+ return (-XRAN_ERRCODE_INVALIDPACKET);
+ }
+
+ for(i=0; i<result->numSections; i++) {
+ *((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
+
+ result->sections[i].info.type = apphdr->sectionType;
+ result->sections[i].info.id = section->hdr.sectionId;
+ result->sections[i].info.rb = section->hdr.rb;
+ result->sections[i].info.symInc = section->hdr.symInc;
+ result->sections[i].info.startPrbc = section->hdr.startPrbc;
+ result->sections[i].info.numPrbc = section->hdr.numPrbc,
+ result->sections[i].info.numSymbol = section->hdr.u.s3.numSymbol;
+ result->sections[i].info.reMask = section->hdr.u.s3.reMask;
+ result->sections[i].info.beamId = section->hdr.u.s3.beamId;
+ result->sections[i].info.ef = section->hdr.u.s3.ef;
+ result->sections[i].info.freqOffset = ((int32_t)rte_be_to_cpu_32(section->freqOffset))>>8;
+
+ if(section->reserved) {
+ print_err("Invalid packet 3 - section[%d:%d]", i, section->reserved);
+ ret = -XRAN_ERRCODE_INVALIDPACKET;
+ }
+
+ if(section->hdr.u.s3.ef) {
+ // TODO: handle section extension
+ extlen = 0;
+ }
+ else extlen = 0;
+
+ section = (void *)rte_pktmbuf_adj(mbuf,
+ sizeof(struct xran_cp_radioapp_section3)+extlen);
+ if(section == NULL) {
+ print_err("Invalid packet 3 - number of section [%d:%d]!",
+ result->numSections, i);
+ result->numSections = i;
+ ret = (-XRAN_ERRCODE_INVALIDPACKET);
+ break;
+ }
+ }
+ }
+ break;
+
+ case XRAN_CP_SECTIONTYPE_5: // UE scheduling information, not supported
+ case XRAN_CP_SECTIONTYPE_6: // Channel Information, not supported
+ case XRAN_CP_SECTIONTYPE_7: // LAA, not supported
+ default:
+ ret = -XRAN_ERRCODE_INVALIDPARAM;
+ print_err("Non-supported Section Type - %d", apphdr->sectionType);
+ }
+
+#if 0
+ printf("[CP-%s] [%3d:%2d:%2d] section%d[%d] startSym=%d filterIdx=%X IQwidth=%d CompMeth=%d\n",
+ result->dir?"DL":"UL",
+ result->hdr.frameId, result->hdr.subframeId, result->hdr.slotId,
+ result->sectionType, result->numSections,
+ result->hdr.startSymId,
+ result->hdr.filterIdx,
+ result->hdr.iqWidth, result->hdr.compMeth);
+
+ for(i=0; i<result->numSections; i++) {
+ printf(" >> %3d:%04X| rb=%d symInc=%d numSym=%d startPrbc=%02X numPrbc=%d reMask=%03X beamId=%04X freqOffset=%d ef=%d\n",
+ i, result->sections[i].info.id,
+ result->sections[i].info.rb,
+ result->sections[i].info.symInc, result->sections[i].info.numSymbol,
+ result->sections[i].info.startPrbc, result->sections[i].info.numPrbc,
+ result->sections[i].info.reMask,
+ result->sections[i].info.beamId,
+ result->sections[i].info.freqOffset,
+ result->sections[i].info.ef);
+// result->sections[i].info.type
+ }
+#endif
+
+ return(ret);
+}
+