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;
+}