MME2 changes - Propped commits from openmme/paging branch. Added scripts
for code gen
Change-Id: Ie55032217232214ac8544ca76ea34335205329e4
diff --git a/src/s1ap/main.c b/src/s1ap/main.c
new file mode 100644
index 0000000..8948c35
--- /dev/null
+++ b/src/s1ap/main.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "options.h"
+#include "ipc_api.h"
+#include "main.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "sctp_conn.h"
+#include "s1ap_structs.h"
+#include "message_queues.h"
+#include "thread_pool.h"
+#include "tpool_queue.h"
+#include "snow_3g.h"
+#include "f9.h"
+#include "err_codes.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+/*Global and externs **/
+extern s1ap_config g_s1ap_cfg;
+pthread_t s1ap_iam_t;
+
+int g_enb_fd = 0;
+int g_sctp_fd = 0;
+struct thread_pool *g_tpool;
+struct thread_pool *g_tpool_tipc_reader;
+
+ipc_handle ipc_S1ap_Hndl;
+
+ipc_handle ipc_tipc_reader;
+
+ipc_handle ipcHndl_sctpsend_reader;
+ipc_handle ipcHndl_sctpsend_writer;
+
+pthread_t tipcReader_t;
+pthread_t acceptSctp_t;
+
+struct time_stat g_attach_stats[65535];
+/**End: global and externs**/
+
+extern char processName[255];
+extern int pid;
+
+extern void
+handle_mmeapp_message(void * data);
+
+#define MAX_ENB 10
+#define BUFFER_LEN 1024
+
+/**
+ * @brief Decode int value from the byte array received in the s1ap incoming
+ * packet.
+ * @param[in] bytes - Array of bytes in packet
+ * @param[in] len - Length of the bytes array from which to extract the int
+ * @return Integer value extracted out of bytes array. 0 if failed.
+ */
+char *msg_to_hex_str(const char *msg, int len, char **buffer) {
+
+ char chars[]= "0123456789abcdef";
+ char *local;
+
+ if (!len)
+ return NULL;
+
+ if (!((*buffer) = (char *)malloc(2 * len + 1)))
+ return NULL;
+
+ local = *buffer;
+ for (int i = 0; i < len; i++) {
+ local[2 * i] = chars[(msg[i] >> 4) & 0x0F];
+ local[2 * i + 1] = chars[(msg[i]) & 0x0F];
+ }
+ local[2 * len] = '\0';
+
+ return local;
+}
+
+unsigned short get_length(char **msg) {
+ /* get length and consume msg bytes accordingly */
+
+ unsigned short ie_len = 0;
+
+ unsigned char val = ((*msg)[0] & 0xc0) >> 6;
+ if(val == 2) {
+ //log_msg(LOG_INFO, "length more than 128\n");
+ unsigned short higher = (unsigned char)(*msg)[0] & 0x3f;
+ (*msg)++;
+ unsigned short lower = (unsigned char)(*msg)[0];
+ ie_len = (higher << 8) | lower;
+ } else {
+ //log_msg(LOG_INFO, "length less than 128\n");
+ ie_len = (unsigned short)(*msg)[0];
+ }
+ (*msg)++;
+ return ie_len;
+}
+
+int
+decode_int_val(unsigned char *bytes, short len)
+{
+ switch(len) {
+ case 1:
+ case 2:
+ return (bytes[1] & 0xff);
+
+ case 3:
+ return (bytes[2] & 0xff) |
+ (0xff00 & ((unsigned short)(bytes[1] << 8)));
+
+ case 4:
+ return (((((unsigned int)(bytes[1]) << 16) & 0xffff00) |
+ ((unsigned int)(bytes[2]) << 8)) & 0xffff00) |
+ ((unsigned int)(bytes[3]) & 0xff);
+ };
+ return 0;
+}
+
+/**
+ * @brief Pack short number value in to the buffer
+ * @param[out] buffer to fill the value
+ * @param[in] value to fill
+ * @return number of bytes filled in to the buffer
+ */
+int
+copyU16(unsigned char *buffer, uint32_t val)
+{
+ if (val < 255) {
+ buffer[0] = (val >> 8) & 0xFF;
+ buffer[1] = val & 0xFF;
+ return 2;
+ } else if (val < 65535) {
+ buffer[0] = 0x40;
+ buffer[1] = (val >> 8) & 0xFF;
+ buffer[2] = val & 0xFF;
+ return 3;
+ } else {
+ buffer[0] = 0x80;
+ buffer[1] = (val >> 16) & 0xFF;
+ buffer[2] = (val >> 8) & 0xFF;
+ buffer[3] = val & 0xFF;
+ return 4;
+ }
+}
+
+void
+calculate_mac(uint8_t *int_key, uint32_t seq_no, uint8_t direction,
+ uint8_t bearer, uint8_t *data, uint16_t data_len,
+ uint8_t *mac)
+{
+ uint8_t *out;
+
+ out = f9(int_key, seq_no, bearer, direction, data, data_len * 8);
+
+ memcpy(mac, out, MAC_SIZE);
+
+ return;
+}
+
+int
+init_s1ap_workers()
+{
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ /* set the thread detach state */
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ pthread_attr_destroy(&attr);
+ return 0;
+}
+
+/**
+ * @brief Thread to read and distribute sctp request received. Messages will
+ * be passed to s1ap handler function for further processing.
+ * @param[in] thread data
+ * @return thread return data
+ */
+void *
+accept_sctp(void *data)
+{
+ log_msg(LOG_INFO, "accept connection on sctp sock\n");
+ int new_socket = 0;
+ int activity = 0;
+ int i = 0;
+ int valread = 0;
+ int sd = 0;
+ int max_sd = 0;
+ int enb_socket[MAX_ENB] = {0};
+ unsigned char buffer[BUFFER_LEN] = {0};
+
+ while(1) {
+ log_msg(LOG_INFO, "WHILE LOOP\n");
+
+ fd_set readfds;
+ memset (buffer, 0, BUFFER_LEN);
+ valread = 0;
+
+ FD_ZERO(&readfds);
+ FD_SET(g_sctp_fd, &readfds);
+ max_sd = g_sctp_fd;
+
+ for (i = 0; i < MAX_ENB; i++) {
+ sd = enb_socket[i];
+
+ if (sd > 0) {
+ FD_SET(sd, &readfds);
+ }
+
+ if (sd > max_sd) {
+ max_sd = sd;
+ }
+ }
+
+ activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
+
+ if ((activity < 0) && (errno != EINTR)) {
+ log_msg(LOG_ERROR, "select error.\n");
+ }
+
+ if (FD_ISSET(g_sctp_fd, &readfds)) {
+
+ if ((new_socket = accept_sctp_socket(g_sctp_fd)) == -1) {
+ log_msg(LOG_ERROR, "Error in accept on sctp socket.\n");
+ }
+
+ log_msg(LOG_INFO, "New Connection Established\n.");
+
+ for (i = 0; i < MAX_ENB; i++) {
+
+ if( enb_socket[i] == 0 ) {
+
+ enb_socket[i] = new_socket;
+ g_enb_fd = new_socket;
+ log_msg(LOG_INFO, "Adding to list of sockets at %d value %d\n" , i, new_socket);
+
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_ENB; i++) {
+
+ sd = enb_socket[i];
+
+ if (FD_ISSET(sd, &readfds)) {
+
+ if ((valread = recv_sctp_msg(sd, buffer, SCTP_BUF_SIZE)) == 0) {
+
+ log_msg(LOG_INFO, "Host Disconnected\n");
+ close(sd);
+ enb_socket[i] = 0;
+
+ } else {
+
+ unsigned char *tmpBuf = (unsigned char *)
+ malloc(sizeof(char) * valread + (2*sizeof(int)) );
+ memcpy(tmpBuf, &sd, sizeof(sd));
+ memcpy(tmpBuf + sizeof(int), &valread, sizeof(int));
+ memcpy(tmpBuf + (2*sizeof(int)), buffer, valread);
+ //tmpBuf[len] = '\0';
+ log_msg(LOG_INFO, "SCTP Received msg len : %d on fd %d\n",
+ valread, sd);
+ insert_job(g_tpool, handle_s1ap_message, tmpBuf);
+
+ }
+ }
+ }
+
+ }/* while */
+
+ return NULL;
+}
+
+void * tipc_msg_handler()
+{
+ int bytesRead = 0;
+ while (1)
+ {
+ unsigned char buffer[BUFFER_LEN] = {0};
+ if ((bytesRead = read_tipc_msg(ipc_tipc_reader, buffer,BUFFER_LEN)) > 0)
+ {
+ unsigned char *tmpBuf = (unsigned char *) malloc(sizeof(char) * bytesRead);
+ memcpy(tmpBuf, buffer, bytesRead);
+ log_msg(LOG_INFO, "S1AP message received from mme-app");
+ insert_job(g_tpool_tipc_reader, handle_mmeapp_message, tmpBuf);
+ }
+ }
+}
+
+/**
+ * @brief Initialize sctp socket connection for eNB
+ * @return Error code SUCCESS or FAIL
+*/
+int
+init_sctp()
+{
+ log_msg(LOG_INFO, "Create sctp sock, ip:%d, port:%d\n",
+ g_s1ap_cfg.s1ap_local_ip, g_s1ap_cfg.sctp_port);
+ /*Create MME sctp listned socket*/
+ g_sctp_fd = create_sctp_socket(g_s1ap_cfg.s1ap_local_ip,
+ g_s1ap_cfg.sctp_port);
+
+ if (g_sctp_fd == -1) {
+ log_msg(LOG_ERROR, "Error in creating sctp socket. \n");
+ return -E_FAIL;
+ }
+
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ /* set the thread detach state */
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ int ret = pthread_create(&acceptSctp_t, &attr,&accept_sctp, NULL);
+ if(ret < 0) {
+ log_msg(LOG_ERROR,"SCTP ACCEPTS THREAD FAILED\n");
+ return -E_FAIL;
+ }
+
+ pthread_attr_destroy(&attr);
+ return SUCCESS;
+}
+
+
+/**
+ * @brief Init all writer IPC channels for s1ap program
+ * @return Success/fail error code
+ */
+int
+init_writer_ipc()
+{
+ if ((ipc_S1ap_Hndl = create_tipc_socket()) <= 0)
+ return -E_FAIL;
+
+ log_msg(LOG_INFO, "Writer IPCs initialized\n");
+
+ return SUCCESS;
+}
+
+/**
+ * @brief Init handlers to process messages coming from mme-app
+ * @return error code.
+ */
+int
+start_mme_resp_handlers()
+{
+ if ((ipc_tipc_reader = create_tipc_socket()) <= 0)
+ {
+ log_msg(LOG_ERROR, "Failed to create IPC Reader tipc socket \n");
+ return -E_FAIL;
+ }
+ if ( bind_tipc_socket(ipc_tipc_reader, s1apAppInstanceNum_c) != 1)
+ {
+ log_msg(LOG_ERROR, "Failed to bind IPC Reader tipc socket \n");
+ return -E_FAIL;
+ }
+
+ /* Initialize thread pool for mme-app messages */
+ g_tpool_tipc_reader = thread_pool_new(5);
+
+ if (g_tpool_tipc_reader == NULL) {
+ log_msg(LOG_ERROR, "Error in creating thread pool. \n");
+ return -E_FAIL_INIT;
+ }
+
+ log_msg(LOG_INFO, "S1AP Listener theadpool initalized.\n");
+
+ // thread to read incoming ipc messages from tipc socket
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&tipcReader_t, &attr, &tipc_msg_handler, NULL);
+ pthread_attr_destroy(&attr);
+
+
+ return SUCCESS;
+}
+
+/**
+ *@Thread to handle send messages to sctp thread
+ * NOT user currently.
+ */
+void *
+sctp_write(void *args)
+{
+ while(1) {
+
+ sleep(10);
+
+ }
+}
+
+int
+start_sctp_threads()
+{
+ pthread_t sctp_writer;
+ pthread_attr_t attr;
+ int res = SUCCESS;
+
+ res = pthread_attr_init(&attr);
+ if (res != 0)
+ return -E_FAIL;
+
+ res = pthread_attr_setdetachstate(&attr,
+ PTHREAD_CREATE_DETACHED);
+ if (res != 0)
+ return -E_FAIL;
+
+ res = pthread_create(&sctp_writer, &attr,
+ sctp_write, NULL);
+ if (res != 0) {
+ log_msg(LOG_ERROR, "Error in creating sctp writer thread.\n");
+ pthread_attr_destroy(&attr);
+ return -E_FAIL;
+ }
+
+ pthread_attr_destroy(&attr);
+
+ return SUCCESS;
+}
+
+/**
+ * @brief - main entry point for s1ap application. Read json config,
+ * start all the handlers. Connect with configured enb
+ */
+int
+main(int argc, char **argv)
+{
+ memcpy (processName, argv[0], strlen(argv[0]));
+ pid = getpid();
+
+ parse_args(argc, argv);
+
+ init_parser("conf/s1ap.json");
+ parse_s1ap_conf();
+
+ if (init_writer_ipc() != SUCCESS) {
+ log_msg(LOG_ERROR, "Error in initializing writer ipc.\n");
+ return -E_FAIL_INIT;
+ }
+
+ if (start_mme_resp_handlers() != SUCCESS) {
+ log_msg(LOG_ERROR, "Error in starting mme response handlers.\n");
+ return -E_FAIL_INIT;
+ }
+
+ /* Initialize thread pool for sctp request parsers */
+ g_tpool = thread_pool_new(THREADPOOL_SIZE);
+
+ if (g_tpool == NULL) {
+ log_msg(LOG_ERROR, "Error in creating thread pool. \n");
+ return -E_FAIL_INIT;
+ }
+ log_msg(LOG_INFO, "S1AP Listener theadpool initalized.\n");
+
+
+ if (init_sctp() != SUCCESS) {
+ log_msg(LOG_ERROR, "Error in initializing sctp server.\n");
+ return -E_FAIL_INIT;
+ }
+
+ log_msg(LOG_INFO, "Connection accespted from enb \n");
+
+ if (start_sctp_threads() != SUCCESS) {
+ log_msg(LOG_ERROR, "Error in creating sctp reader/writer thread.\n");
+ return -E_FAIL_INIT;
+ }
+
+ log_msg(LOG_INFO, "sctp reader/writer thread started.\n");
+
+
+ while (1) {
+ sleep(10);
+ }
+
+ return SUCCESS;
+}