blob: fbb0d7b8c56c2310050aec56c8d02f980948c59b [file] [log] [blame]
/*
* 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 <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "err_codes.h"
#include "options.h"
#include "ipc_api.h"
#include "message_queues.h"
#include "s11.h"
#include "s11_config.h"
#include "s11_structs.h"
#include "../../gtpV2Codec/gtpV2StackWrappers.h"
extern struct GtpV2Stack* gtpStack_gp;
int s11_CS_resp_handler(MsgBuffer* message, GtpV2MessageHeader* hdr);
int s11_MB_resp_handler(MsgBuffer* message, GtpV2MessageHeader* hdr);
int s11_DS_resp_handler(MsgBuffer* message, GtpV2MessageHeader* hdr);
int s11_RB_resp_handler(MsgBuffer* message, GtpV2MessageHeader* hdr);
int s11_DDN_handler(MsgBuffer* message, GtpV2MessageHeader* hdr);
/*
Get count of no of IEs in gtpv2c msg
*/
static int
get_IE_cnt(char *msg, int len)
{
int cnt = 0;
char *tmp = msg+11;
struct s11_IE_header *header = (struct s11_IE_header *)tmp;
for(; (char *)tmp <= msg + len; ++cnt) {
tmp += sizeof(struct s11_IE_header) + ntohs(header->ie_len);
header = (struct s11_IE_header*)tmp;
}
return cnt;
}
void
network_cp_fteid(struct fteid *teid, char *data)
{
unsigned int *tmp;
memcpy(teid, data, sizeof(struct fteid));
teid->header.teid_gre = ntohl(teid->header.teid_gre);
tmp = (unsigned int*)(data+5);
*tmp = ntohl(*tmp);
memcpy(&(teid->ip.ipv4), tmp, sizeof(struct in_addr));
}
int
parse_bearer_ctx(struct bearer_ctx *bearer, char* data, short len)
{
char no_of_ies = 4;
//TODO: count no of IEs
for(int i=0; i < no_of_ies; ++i) {
struct s11_IE_header *header = (struct s11_IE_header*)data;
char *value = data + sizeof(struct s11_IE_header);
switch(header->ie_type){
case S11_IE_CAUSE:
memcpy(&(bearer->cause), value, sizeof(struct gtp_cause));
break;
case S11_IE_FTEID_C:{
#define S1U_SGW_FTEID 1 /*binary 0001*/
if((0x0F & (unsigned char)(*value))
== S1U_SGW_FTEID) {
network_cp_fteid(&bearer->s1u_sgw_teid, value);
}
else { /*s5s8 pgw_U ftied*/
network_cp_fteid(&bearer->s5s8_pgw_u_teid, value);
}
break;
}
case S11_IE_EPS_BEARER_ID:
bearer->eps_bearer_id = (unsigned char)(*value);
break;
default:
log_msg(LOG_ERROR, "Unhandled S11 bearer IE: %d\n", header->ie_type);
}
data += ntohs(header->ie_len) + sizeof(struct s11_IE_header); /*goto next IE*/
}
return SUCCESS;
}
int
parse_gtpv2c_IEs(char *msg, int len, struct s11_proto_IE *proto_ies)
{
proto_ies->no_of_ies = get_IE_cnt(msg, len);
if(0 == proto_ies->no_of_ies) {
log_msg(LOG_INFO, "No IEs recvd in message\n");
return SUCCESS;
}
log_msg(LOG_INFO, "No of IEs - %d\n", proto_ies->no_of_ies);
/*allocated IEs for message*/
proto_ies->s11_ies = (struct s11_IE*)calloc(sizeof(struct s11_IE),
proto_ies->no_of_ies);
msg +=11;
for(int i=0; i < proto_ies->no_of_ies; ++i) {
struct s11_IE *ie = &(proto_ies->s11_ies[i]);
char *data = msg + sizeof(struct s11_IE_header);
memcpy(&(ie->header), msg, sizeof(struct s11_IE_header));
switch(ie->header.ie_type){
case S11_IE_CAUSE:
memcpy(&(ie->data.cause), data, sizeof(struct gtp_cause));
break;
case S11_IE_FTEID_C:{
#define S11_SGW_C_FTEID 11 /*binary 1011*/
if((0x0F & (unsigned char)(*data))
== S11_SGW_C_FTEID) {
network_cp_fteid(&(ie->data.s11_sgw_fteid), data);
}
else { /*s5s8 pgw_c ftied*/
network_cp_fteid(&(ie->data.s5s8_pgw_c_fteid), data);
}
break;
}
case S11_IE_PAA: {
memcpy(&(ie->data.pdn_addr.pdn_type), data,
sizeof(ie->data.pdn_addr.pdn_type));
memcpy(&(ie->data.pdn_addr.ip_type.ipv4), data+1, sizeof(int));
break;
}
case S11_IE_APN_RESTRICTION:
break;
case S11_IE_BEARER_CTX:
parse_bearer_ctx(&(ie->data.bearer), data, ntohs(ie->header.ie_len));
break;
default:
log_msg(LOG_ERROR, "Unhandled S11 IE: %d\n", ie->header.ie_type);
}
msg += (ntohs(((struct s11_IE_header*)msg)->ie_len) + sizeof(struct s11_IE_header)) ; /*goto next IE*/
}
return SUCCESS;
}
void
handle_s11_message(void *message)
{
log_msg(LOG_INFO, "S11 recv msg handler.\n");
MsgBuffer* msgBuf_p = (MsgBuffer*)(message);
GtpV2MessageHeader msgHeader;
bool rc = GtpV2Stack_decodeMessageHeader(gtpStack_gp, &msgHeader, msgBuf_p);
switch(msgHeader.msgType){
case S11_GTP_CREATE_SESSION_RESP:
s11_CS_resp_handler(msgBuf_p, &msgHeader);
break;
case S11_GTP_MODIFY_BEARER_RESP:
s11_MB_resp_handler(msgBuf_p, &msgHeader);
break;
case S11_GTP_DELETE_SESSION_RESP:
s11_DS_resp_handler(msgBuf_p, &msgHeader);
break;
case S11_GTP_RELEASE_BEARER_RESP:
s11_RB_resp_handler(msgBuf_p, &msgHeader);
break;
case S11_GTP_DDN:
s11_DDN_handler(msgBuf_p, &msgHeader);
break;
}
return;
}