blob: 8948c3596a6ecbc00d324755c916c886f8f63714 [file] [log] [blame]
anjana_sreekumar@infosys.com991c2062020-01-08 11:42:57 +05301/*
2 * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
3 * Copyright (c) 2017 Intel Corporation
4 * Copyright (c) 2019, Infosys Ltd.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <string.h>
24#include <pthread.h>
25#include <arpa/inet.h>
26#include <errno.h>
27
28#include "options.h"
29#include "ipc_api.h"
30#include "main.h"
31#include "s1ap.h"
32#include "s1ap_config.h"
33#include "sctp_conn.h"
34#include "s1ap_structs.h"
35#include "message_queues.h"
36#include "thread_pool.h"
37#include "tpool_queue.h"
38#include "snow_3g.h"
39#include "f9.h"
40#include "err_codes.h"
41#include <sys/ioctl.h>
42#include <sys/types.h>
43
44/*Global and externs **/
45extern s1ap_config g_s1ap_cfg;
46pthread_t s1ap_iam_t;
47
48int g_enb_fd = 0;
49int g_sctp_fd = 0;
50struct thread_pool *g_tpool;
51struct thread_pool *g_tpool_tipc_reader;
52
53ipc_handle ipc_S1ap_Hndl;
54
55ipc_handle ipc_tipc_reader;
56
57ipc_handle ipcHndl_sctpsend_reader;
58ipc_handle ipcHndl_sctpsend_writer;
59
60pthread_t tipcReader_t;
61pthread_t acceptSctp_t;
62
63struct time_stat g_attach_stats[65535];
64/**End: global and externs**/
65
66extern char processName[255];
67extern int pid;
68
69extern void
70handle_mmeapp_message(void * data);
71
72#define MAX_ENB 10
73#define BUFFER_LEN 1024
74
75/**
76 * @brief Decode int value from the byte array received in the s1ap incoming
77 * packet.
78 * @param[in] bytes - Array of bytes in packet
79 * @param[in] len - Length of the bytes array from which to extract the int
80 * @return Integer value extracted out of bytes array. 0 if failed.
81 */
82char *msg_to_hex_str(const char *msg, int len, char **buffer) {
83
84 char chars[]= "0123456789abcdef";
85 char *local;
86
87 if (!len)
88 return NULL;
89
90 if (!((*buffer) = (char *)malloc(2 * len + 1)))
91 return NULL;
92
93 local = *buffer;
94 for (int i = 0; i < len; i++) {
95 local[2 * i] = chars[(msg[i] >> 4) & 0x0F];
96 local[2 * i + 1] = chars[(msg[i]) & 0x0F];
97 }
98 local[2 * len] = '\0';
99
100 return local;
101}
102
103unsigned short get_length(char **msg) {
104 /* get length and consume msg bytes accordingly */
105
106 unsigned short ie_len = 0;
107
108 unsigned char val = ((*msg)[0] & 0xc0) >> 6;
109 if(val == 2) {
110 //log_msg(LOG_INFO, "length more than 128\n");
111 unsigned short higher = (unsigned char)(*msg)[0] & 0x3f;
112 (*msg)++;
113 unsigned short lower = (unsigned char)(*msg)[0];
114 ie_len = (higher << 8) | lower;
115 } else {
116 //log_msg(LOG_INFO, "length less than 128\n");
117 ie_len = (unsigned short)(*msg)[0];
118 }
119 (*msg)++;
120 return ie_len;
121}
122
123int
124decode_int_val(unsigned char *bytes, short len)
125{
126 switch(len) {
127 case 1:
128 case 2:
129 return (bytes[1] & 0xff);
130
131 case 3:
132 return (bytes[2] & 0xff) |
133 (0xff00 & ((unsigned short)(bytes[1] << 8)));
134
135 case 4:
136 return (((((unsigned int)(bytes[1]) << 16) & 0xffff00) |
137 ((unsigned int)(bytes[2]) << 8)) & 0xffff00) |
138 ((unsigned int)(bytes[3]) & 0xff);
139 };
140 return 0;
141}
142
143/**
144 * @brief Pack short number value in to the buffer
145 * @param[out] buffer to fill the value
146 * @param[in] value to fill
147 * @return number of bytes filled in to the buffer
148 */
149int
150copyU16(unsigned char *buffer, uint32_t val)
151{
152 if (val < 255) {
153 buffer[0] = (val >> 8) & 0xFF;
154 buffer[1] = val & 0xFF;
155 return 2;
156 } else if (val < 65535) {
157 buffer[0] = 0x40;
158 buffer[1] = (val >> 8) & 0xFF;
159 buffer[2] = val & 0xFF;
160 return 3;
161 } else {
162 buffer[0] = 0x80;
163 buffer[1] = (val >> 16) & 0xFF;
164 buffer[2] = (val >> 8) & 0xFF;
165 buffer[3] = val & 0xFF;
166 return 4;
167 }
168}
169
170void
171calculate_mac(uint8_t *int_key, uint32_t seq_no, uint8_t direction,
172 uint8_t bearer, uint8_t *data, uint16_t data_len,
173 uint8_t *mac)
174{
175 uint8_t *out;
176
177 out = f9(int_key, seq_no, bearer, direction, data, data_len * 8);
178
179 memcpy(mac, out, MAC_SIZE);
180
181 return;
182}
183
184int
185init_s1ap_workers()
186{
187 pthread_attr_t attr;
188
189 pthread_attr_init(&attr);
190 /* set the thread detach state */
191 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
192
193 pthread_attr_destroy(&attr);
194 return 0;
195}
196
197/**
198 * @brief Thread to read and distribute sctp request received. Messages will
199 * be passed to s1ap handler function for further processing.
200 * @param[in] thread data
201 * @return thread return data
202 */
203void *
204accept_sctp(void *data)
205{
206 log_msg(LOG_INFO, "accept connection on sctp sock\n");
207 int new_socket = 0;
208 int activity = 0;
209 int i = 0;
210 int valread = 0;
211 int sd = 0;
212 int max_sd = 0;
213 int enb_socket[MAX_ENB] = {0};
214 unsigned char buffer[BUFFER_LEN] = {0};
215
216 while(1) {
217 log_msg(LOG_INFO, "WHILE LOOP\n");
218
219 fd_set readfds;
220 memset (buffer, 0, BUFFER_LEN);
221 valread = 0;
222
223 FD_ZERO(&readfds);
224 FD_SET(g_sctp_fd, &readfds);
225 max_sd = g_sctp_fd;
226
227 for (i = 0; i < MAX_ENB; i++) {
228 sd = enb_socket[i];
229
230 if (sd > 0) {
231 FD_SET(sd, &readfds);
232 }
233
234 if (sd > max_sd) {
235 max_sd = sd;
236 }
237 }
238
239 activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
240
241 if ((activity < 0) && (errno != EINTR)) {
242 log_msg(LOG_ERROR, "select error.\n");
243 }
244
245 if (FD_ISSET(g_sctp_fd, &readfds)) {
246
247 if ((new_socket = accept_sctp_socket(g_sctp_fd)) == -1) {
248 log_msg(LOG_ERROR, "Error in accept on sctp socket.\n");
249 }
250
251 log_msg(LOG_INFO, "New Connection Established\n.");
252
253 for (i = 0; i < MAX_ENB; i++) {
254
255 if( enb_socket[i] == 0 ) {
256
257 enb_socket[i] = new_socket;
258 g_enb_fd = new_socket;
259 log_msg(LOG_INFO, "Adding to list of sockets at %d value %d\n" , i, new_socket);
260
261 break;
262 }
263 }
264 }
265
266 for (i = 0; i < MAX_ENB; i++) {
267
268 sd = enb_socket[i];
269
270 if (FD_ISSET(sd, &readfds)) {
271
272 if ((valread = recv_sctp_msg(sd, buffer, SCTP_BUF_SIZE)) == 0) {
273
274 log_msg(LOG_INFO, "Host Disconnected\n");
275 close(sd);
276 enb_socket[i] = 0;
277
278 } else {
279
280 unsigned char *tmpBuf = (unsigned char *)
281 malloc(sizeof(char) * valread + (2*sizeof(int)) );
282 memcpy(tmpBuf, &sd, sizeof(sd));
283 memcpy(tmpBuf + sizeof(int), &valread, sizeof(int));
284 memcpy(tmpBuf + (2*sizeof(int)), buffer, valread);
285 //tmpBuf[len] = '\0';
286 log_msg(LOG_INFO, "SCTP Received msg len : %d on fd %d\n",
287 valread, sd);
288 insert_job(g_tpool, handle_s1ap_message, tmpBuf);
289
290 }
291 }
292 }
293
294 }/* while */
295
296 return NULL;
297}
298
299void * tipc_msg_handler()
300{
301 int bytesRead = 0;
302 while (1)
303 {
304 unsigned char buffer[BUFFER_LEN] = {0};
305 if ((bytesRead = read_tipc_msg(ipc_tipc_reader, buffer,BUFFER_LEN)) > 0)
306 {
307 unsigned char *tmpBuf = (unsigned char *) malloc(sizeof(char) * bytesRead);
308 memcpy(tmpBuf, buffer, bytesRead);
309 log_msg(LOG_INFO, "S1AP message received from mme-app");
310 insert_job(g_tpool_tipc_reader, handle_mmeapp_message, tmpBuf);
311 }
312 }
313}
314
315/**
316 * @brief Initialize sctp socket connection for eNB
317 * @return Error code SUCCESS or FAIL
318*/
319int
320init_sctp()
321{
322 log_msg(LOG_INFO, "Create sctp sock, ip:%d, port:%d\n",
323 g_s1ap_cfg.s1ap_local_ip, g_s1ap_cfg.sctp_port);
324 /*Create MME sctp listned socket*/
325 g_sctp_fd = create_sctp_socket(g_s1ap_cfg.s1ap_local_ip,
326 g_s1ap_cfg.sctp_port);
327
328 if (g_sctp_fd == -1) {
329 log_msg(LOG_ERROR, "Error in creating sctp socket. \n");
330 return -E_FAIL;
331 }
332
333 pthread_attr_t attr;
334
335 pthread_attr_init(&attr);
336 /* set the thread detach state */
337 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
338
339 int ret = pthread_create(&acceptSctp_t, &attr,&accept_sctp, NULL);
340 if(ret < 0) {
341 log_msg(LOG_ERROR,"SCTP ACCEPTS THREAD FAILED\n");
342 return -E_FAIL;
343 }
344
345 pthread_attr_destroy(&attr);
346 return SUCCESS;
347}
348
349
350/**
351 * @brief Init all writer IPC channels for s1ap program
352 * @return Success/fail error code
353 */
354int
355init_writer_ipc()
356{
357 if ((ipc_S1ap_Hndl = create_tipc_socket()) <= 0)
358 return -E_FAIL;
359
360 log_msg(LOG_INFO, "Writer IPCs initialized\n");
361
362 return SUCCESS;
363}
364
365/**
366 * @brief Init handlers to process messages coming from mme-app
367 * @return error code.
368 */
369int
370start_mme_resp_handlers()
371{
372 if ((ipc_tipc_reader = create_tipc_socket()) <= 0)
373 {
374 log_msg(LOG_ERROR, "Failed to create IPC Reader tipc socket \n");
375 return -E_FAIL;
376 }
377 if ( bind_tipc_socket(ipc_tipc_reader, s1apAppInstanceNum_c) != 1)
378 {
379 log_msg(LOG_ERROR, "Failed to bind IPC Reader tipc socket \n");
380 return -E_FAIL;
381 }
382
383 /* Initialize thread pool for mme-app messages */
384 g_tpool_tipc_reader = thread_pool_new(5);
385
386 if (g_tpool_tipc_reader == NULL) {
387 log_msg(LOG_ERROR, "Error in creating thread pool. \n");
388 return -E_FAIL_INIT;
389 }
390
391 log_msg(LOG_INFO, "S1AP Listener theadpool initalized.\n");
392
393 // thread to read incoming ipc messages from tipc socket
394 pthread_attr_t attr;
395 pthread_attr_init(&attr);
396 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
397 pthread_create(&tipcReader_t, &attr, &tipc_msg_handler, NULL);
398 pthread_attr_destroy(&attr);
399
400
401 return SUCCESS;
402}
403
404/**
405 *@Thread to handle send messages to sctp thread
406 * NOT user currently.
407 */
408void *
409sctp_write(void *args)
410{
411 while(1) {
412
413 sleep(10);
414
415 }
416}
417
418int
419start_sctp_threads()
420{
421 pthread_t sctp_writer;
422 pthread_attr_t attr;
423 int res = SUCCESS;
424
425 res = pthread_attr_init(&attr);
426 if (res != 0)
427 return -E_FAIL;
428
429 res = pthread_attr_setdetachstate(&attr,
430 PTHREAD_CREATE_DETACHED);
431 if (res != 0)
432 return -E_FAIL;
433
434 res = pthread_create(&sctp_writer, &attr,
435 sctp_write, NULL);
436 if (res != 0) {
437 log_msg(LOG_ERROR, "Error in creating sctp writer thread.\n");
438 pthread_attr_destroy(&attr);
439 return -E_FAIL;
440 }
441
442 pthread_attr_destroy(&attr);
443
444 return SUCCESS;
445}
446
447/**
448 * @brief - main entry point for s1ap application. Read json config,
449 * start all the handlers. Connect with configured enb
450 */
451int
452main(int argc, char **argv)
453{
454 memcpy (processName, argv[0], strlen(argv[0]));
455 pid = getpid();
456
457 parse_args(argc, argv);
458
459 init_parser("conf/s1ap.json");
460 parse_s1ap_conf();
461
462 if (init_writer_ipc() != SUCCESS) {
463 log_msg(LOG_ERROR, "Error in initializing writer ipc.\n");
464 return -E_FAIL_INIT;
465 }
466
467 if (start_mme_resp_handlers() != SUCCESS) {
468 log_msg(LOG_ERROR, "Error in starting mme response handlers.\n");
469 return -E_FAIL_INIT;
470 }
471
472 /* Initialize thread pool for sctp request parsers */
473 g_tpool = thread_pool_new(THREADPOOL_SIZE);
474
475 if (g_tpool == NULL) {
476 log_msg(LOG_ERROR, "Error in creating thread pool. \n");
477 return -E_FAIL_INIT;
478 }
479 log_msg(LOG_INFO, "S1AP Listener theadpool initalized.\n");
480
481
482 if (init_sctp() != SUCCESS) {
483 log_msg(LOG_ERROR, "Error in initializing sctp server.\n");
484 return -E_FAIL_INIT;
485 }
486
487 log_msg(LOG_INFO, "Connection accespted from enb \n");
488
489 if (start_sctp_threads() != SUCCESS) {
490 log_msg(LOG_ERROR, "Error in creating sctp reader/writer thread.\n");
491 return -E_FAIL_INIT;
492 }
493
494 log_msg(LOG_INFO, "sctp reader/writer thread started.\n");
495
496
497 while (1) {
498 sleep(10);
499 }
500
501 return SUCCESS;
502}