S1AP PWS(public warning system) support

S1AP Write Replace Warning Request/Response
S1AP Kill Request/Response
CBC integration (SBc-AP) is required to initiate a PWS procedure.
This commit is contained in:
Jihoon Brandon Lee 2018-09-13 20:38:33 -06:00
parent d004770e17
commit 3dc2d396db
9 changed files with 456 additions and 1 deletions

View file

@ -21,6 +21,7 @@ libmme_la_SOURCES = \
esm_sm.c esm_handler.c esm_build.c \
mme_gtp_path.c mme_s11_build.c mme_s11_handler.c \
mme_sm.c mme_path.c \
sbc_message.h sbc_handler.h sbc_handler.c \
$(NULL)
if USRSCTP

View file

@ -1709,6 +1709,8 @@ status_t s1ap_build_handover_request(
subscription_data = &mme_ue->subscription_data;
d_assert(subscription_data, return CORE_ERROR, "Null param");
d_trace(3, "[MME] Handover request\n");
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage =
@ -2287,7 +2289,7 @@ status_t s1ap_build_s1_reset_ack(
S1AP_ResetAcknowledgeIEs_t *ie = NULL;
d_trace(3, "[MME] ResetAcknowledge\n");
d_trace(3, "[MME] Reset acknowledge\n");
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_successfulOutcome;
@ -2384,3 +2386,226 @@ status_t s1ap_build_s1_reset_ack(
return CORE_OK;
}
status_t s1ap_build_write_replace_warning_request(
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws)
{
status_t rv;
S1AP_S1AP_PDU_t pdu;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_WriteReplaceWarningRequest_t *WriteReplaceWarningRequest = NULL;
S1AP_WriteReplaceWarningRequestIEs_t *ie = NULL;
S1AP_MessageIdentifier_t *MessageIdentifier = NULL;
S1AP_SerialNumber_t *SerialNumber = NULL;
S1AP_RepetitionPeriod_t *RepetitionPeriod = NULL;
S1AP_NumberofBroadcastRequest_t *NumberofBroadcastRequest = NULL;
S1AP_DataCodingScheme_t *DataCodingScheme = NULL;
S1AP_WarningMessageContents_t *WarningMessageContents = NULL;
d_trace(3, "[MME] Write-replace warning request\n");
d_assert(sbc_pws, return CORE_ERROR,);
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage =
core_calloc(1, sizeof(S1AP_InitiatingMessage_t));
initiatingMessage = pdu.choice.initiatingMessage;
initiatingMessage->procedureCode = S1AP_ProcedureCode_id_WriteReplaceWarning;
initiatingMessage->criticality = S1AP_Criticality_reject;
initiatingMessage->value.present =
S1AP_InitiatingMessage__value_PR_WriteReplaceWarningRequest;
WriteReplaceWarningRequest = &initiatingMessage->value.choice.WriteReplaceWarningRequest;
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_MessageIdentifier;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_MessageIdentifier;
MessageIdentifier = &ie->value.choice.MessageIdentifier;
MessageIdentifier->size = (16 / 8);
MessageIdentifier->buf =
core_calloc(MessageIdentifier->size, sizeof(c_uint8_t));
MessageIdentifier->bits_unused = 0;
MessageIdentifier->buf[0] = (sbc_pws->message_id >> 8) & 0xFF;
MessageIdentifier->buf[1] = sbc_pws->message_id & 0xFF;
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_SerialNumber;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_SerialNumber;
SerialNumber = &ie->value.choice.SerialNumber;
SerialNumber->size = (16 / 8);
SerialNumber->buf =
core_calloc(SerialNumber->size, sizeof(c_uint8_t));
SerialNumber->bits_unused = 0;
SerialNumber->buf[0] = (sbc_pws->serial_number >> 8) & 0xFF;
SerialNumber->buf[1] = sbc_pws->serial_number & 0xFF;
/* TODO: optional Warning Area List */
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_RepetitionPeriod;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_RepetitionPeriod;
RepetitionPeriod = &ie->value.choice.RepetitionPeriod;
*RepetitionPeriod = sbc_pws->repetition_period;
/* TODO: optional Extended Repetition Period */
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_NumberofBroadcastRequest;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_NumberofBroadcastRequest;
NumberofBroadcastRequest = &ie->value.choice.NumberofBroadcastRequest;
*NumberofBroadcastRequest = sbc_pws->number_of_broadcast;
/* TODO: optional Warnging Type */
/* TODO: optional Warning Security Information */
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_DataCodingScheme;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_DataCodingScheme;
DataCodingScheme = &ie->value.choice.DataCodingScheme;
DataCodingScheme->size = (8 / 8);
DataCodingScheme->buf =
core_calloc(DataCodingScheme->size, sizeof(c_uint8_t));
DataCodingScheme->bits_unused = 0;
DataCodingScheme->buf[0] = sbc_pws->data_coding_scheme & 0xFF;
ie = core_calloc(1, sizeof(S1AP_WriteReplaceWarningRequestIEs_t));
ASN_SEQUENCE_ADD(&WriteReplaceWarningRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_WarningMessageContents;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_WriteReplaceWarningRequestIEs__value_PR_WarningMessageContents;
WarningMessageContents = &ie->value.choice.WarningMessageContents;
WarningMessageContents->size = sbc_pws->message_length;;
WarningMessageContents->buf =
core_calloc(WarningMessageContents->size, sizeof(c_uint8_t));
memcpy(WarningMessageContents->buf, sbc_pws->message_contents, WarningMessageContents->size);
/* TODO: optional Concurrent Warning Message Indicator */
d_trace(5, " Message[%02x,%02x] Serial[%02x,%02x] Repetition[%d] NumBroadcast[%d]\n",
MessageIdentifier->buf[0], MessageIdentifier->buf[1], SerialNumber->buf[0],
SerialNumber->buf[1], *RepetitionPeriod, *NumberofBroadcastRequest);
rv = s1ap_encode_pdu(s1apbuf, &pdu);
s1ap_free_pdu(&pdu);
if (rv != CORE_OK)
{
d_error("s1ap_encode_pdu() failed");
return CORE_ERROR;
}
return CORE_OK;
}
status_t s1ap_build_kill_request(
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws)
{
status_t rv;
S1AP_S1AP_PDU_t pdu;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_KillRequest_t *KillRequest = NULL;
S1AP_KillRequestIEs_t *ie = NULL;
S1AP_MessageIdentifier_t *MessageIdentifier = NULL;
S1AP_SerialNumber_t *SerialNumber = NULL;
d_trace(3, "[MME] Kill request\n");
d_assert(sbc_pws, return CORE_ERROR,);
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage =
core_calloc(1, sizeof(S1AP_InitiatingMessage_t));
initiatingMessage = pdu.choice.initiatingMessage;
initiatingMessage->procedureCode = S1AP_ProcedureCode_id_Kill;
initiatingMessage->criticality = S1AP_Criticality_reject;
initiatingMessage->value.present =
S1AP_InitiatingMessage__value_PR_KillRequest;
KillRequest = &initiatingMessage->value.choice.KillRequest;
ie = core_calloc(1, sizeof(S1AP_KillRequestIEs_t));
ASN_SEQUENCE_ADD(&KillRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_MessageIdentifier;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_KillRequestIEs__value_PR_MessageIdentifier;
MessageIdentifier = &ie->value.choice.MessageIdentifier;
MessageIdentifier->size = (16 / 8);
MessageIdentifier->buf =
core_calloc(MessageIdentifier->size, sizeof(c_uint8_t));
MessageIdentifier->bits_unused = 0;
MessageIdentifier->buf[0] = (sbc_pws->message_id >> 8) & 0xFF;
MessageIdentifier->buf[1] = sbc_pws->message_id & 0xFF;
ie = core_calloc(1, sizeof(S1AP_KillRequestIEs_t));
ASN_SEQUENCE_ADD(&KillRequest->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_SerialNumber;
ie->criticality = S1AP_Criticality_reject;
ie->value.present = S1AP_KillRequestIEs__value_PR_SerialNumber;
SerialNumber = &ie->value.choice.SerialNumber;
SerialNumber->size = (16 / 8);
SerialNumber->buf =
core_calloc(SerialNumber->size, sizeof(c_uint8_t));
SerialNumber->bits_unused = 0;
SerialNumber->buf[0] = (sbc_pws->serial_number >> 8) & 0xFF;
SerialNumber->buf[1] = sbc_pws->serial_number & 0xFF;
/* TODO: optional Warning Area List */
d_trace(5, " Message[%02x,%02x] Serial[%02x,%02x]\n",
MessageIdentifier->buf[0], MessageIdentifier->buf[1],
SerialNumber->buf[0], SerialNumber->buf[1]);
rv = s1ap_encode_pdu(s1apbuf, &pdu);
s1ap_free_pdu(&pdu);
if (rv != CORE_OK)
{
d_error("s1ap_encode_pdu() failed");
return CORE_ERROR;
}
return CORE_OK;
}

View file

@ -4,6 +4,8 @@
#include "s1ap/s1ap_message.h"
#include "mme_context.h"
#include "sbc_message.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@ -78,6 +80,12 @@ CORE_DECLARE(status_t) s1ap_build_s1_reset_ack(
pkbuf_t **s1apbuf,
S1AP_UE_associatedLogicalS1_ConnectionListRes_t *partOfS1_Interface);
CORE_DECLARE(status_t) s1ap_build_write_replace_warning_request(
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws);
CORE_DECLARE(status_t) s1ap_build_kill_request(
pkbuf_t **s1apbuf, sbc_pws_data_t *sbc_pws);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View file

@ -2106,3 +2106,52 @@ void s1ap_handle_s1_reset(
d_assert(rv == CORE_OK,,);
}
void s1ap_handle_write_replace_warning_response(
mme_enb_t *enb, s1ap_message_t *message)
{
char buf[CORE_ADDRSTRLEN];
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
S1AP_WriteReplaceWarningResponse_t *WriteReplaceWarningResponse = NULL;
d_assert(enb, return,);
d_assert(enb->sock, return,);
d_assert(message, return,);
successfulOutcome = message->choice.successfulOutcome;
d_assert(successfulOutcome, return,);
WriteReplaceWarningResponse =
&successfulOutcome->value.choice.WriteReplaceWarningResponse;
d_assert(WriteReplaceWarningResponse, return,);
d_trace(3, "[MME] Write replace warning response\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
}
void s1ap_handle_kill_response(
mme_enb_t *enb, s1ap_message_t *message)
{
char buf[CORE_ADDRSTRLEN];
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
S1AP_KillResponse_t *KillResponse = NULL;
d_assert(enb, return,);
d_assert(enb->sock, return,);
d_assert(message, return,);
successfulOutcome = message->choice.successfulOutcome;
d_assert(successfulOutcome, return,);
KillResponse =
&successfulOutcome->value.choice.KillResponse;
d_assert(KillResponse, return,);
d_trace(3, "[MME] Kill response\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
}

View file

@ -52,6 +52,11 @@ CORE_DECLARE(void) s1ap_handle_handover_notification(
CORE_DECLARE(void) s1ap_handle_s1_reset(
mme_enb_t *enb, s1ap_message_t *message);
CORE_DECLARE(void) s1ap_handle_write_replace_warning_response(
mme_enb_t *enb, s1ap_message_t *message);
CORE_DECLARE(void) s1ap_handle_kill_response(
mme_enb_t *enb, s1ap_message_t *message);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View file

@ -179,6 +179,16 @@ void s1ap_state_operational(fsm_t *s, event_t *e)
s1ap_handle_handover_request_ack(enb, pdu);
break;
}
case S1AP_ProcedureCode_id_WriteReplaceWarning:
{
s1ap_handle_write_replace_warning_response(enb, pdu);
break;
}
case S1AP_ProcedureCode_id_Kill:
{
s1ap_handle_kill_response(enb, pdu);
break;
}
default:
{
d_warn("Not implemented(choice:%d, proc:%d)",

104
src/mme/sbc_handler.c Normal file
View file

@ -0,0 +1,104 @@
#define TRACE_MODULE _sbc_handler
#include "core_debug.h"
#include "mme_context.h"
#include "s1ap_path.h"
#include "s1ap_build.h"
#include "sbc_handler.h"
void sbc_handle_write_replace_warning_request(sbc_pws_data_t *sbc_pws)
{
pkbuf_t *s1apbuf = NULL;
hash_index_t *hi = NULL;
mme_enb_t *enb = NULL;
int i, j, flag;
status_t rv;
/* Find enB with matched TAI */
for (hi = mme_enb_first(); hi; hi = mme_enb_next(hi))
{
flag = 0;
enb = mme_enb_this(hi);
if (sbc_pws->no_of_tai > 0)
{
for (i = 0, flag = 0; i < enb->num_of_supported_ta_list; i++)
{
for (j = 0; j < sbc_pws->no_of_tai; j++)
{
if (!memcmp(&enb->supported_ta_list[i],
&sbc_pws->tai[j], sizeof(tai_t)))
flag = 1;
if (flag) break;
}
if (flag) break;
}
}
else
flag = 1;
if (flag)
{
s1apbuf = NULL;
/* Buidl S1AP Write Replace Warning Request message */
rv = s1ap_build_write_replace_warning_request(&s1apbuf, sbc_pws);
d_assert(rv == CORE_OK && s1apbuf, return,
"s1ap build error");
/* Send to enb */
d_assert(s1ap_send_to_enb(
enb, s1apbuf, S1AP_NON_UE_SIGNALLING) == CORE_OK,
return, "s1ap send error");
}
}
}
void sbc_handle_stop_warning_request(sbc_pws_data_t *sbc_pws)
{
pkbuf_t *s1apbuf = NULL;
hash_index_t *hi = NULL;
mme_enb_t *enb = NULL;
int i, j, flag;
status_t rv;
/* Find enB with matched TAI */
for (hi = mme_enb_first(); hi; hi = mme_enb_next(hi))
{
flag = 0;
enb = mme_enb_this(hi);
if (sbc_pws->no_of_tai > 0)
{
for (i = 0, flag = 0; i < enb->num_of_supported_ta_list; i++)
{
for (j = 0; j < sbc_pws->no_of_tai; j++)
{
if (!memcmp(&enb->supported_ta_list[i],
&sbc_pws->tai[j], sizeof(tai_t)))
flag = 1;
if (flag) break;
}
if (flag) break;
}
}
else
flag = 1;
if (flag)
{
s1apbuf = NULL;
/* Buidl S1AP Kill request message */
rv = s1ap_build_kill_request(&s1apbuf, sbc_pws);
d_assert(rv == CORE_OK && s1apbuf, return,
"s1ap build error");
/* Send to enb */
d_assert(s1ap_send_to_enb(
enb, s1apbuf, S1AP_NON_UE_SIGNALLING) == CORE_OK,
return, "s1ap send error");
}
}
}

19
src/mme/sbc_handler.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef __SBC_HANDLER_H__
#define __SBC_HANDLER_H__
#include "sbc_message.h"
/* SBc-AP handles */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
CORE_DECLARE(void) sbc_handle_write_replace_warning_request(sbc_pws_data_t *sbc_pws);
CORE_DECLARE(void) sbc_handle_stop_warning_request(sbc_pws_data_t *sbc_pws);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __SBC_HANDLER_H__ */

34
src/mme/sbc_message.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef __SBC_MESSAGE_H__
#define __SBC_MESSAGE_H__
#include "3gpp_types.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* SBc-AP messages:
* After the CBC integration, the encoding/decoding of
* SBc-AP messages will be fully supported.
*/
/* SBc-AP interface data definitions */
/* SBc-AP WriteReplaceWarning data */
typedef struct _sbc_pws_data_t {
c_uint16_t message_id;
c_uint16_t serial_number;
c_uint32_t no_of_tai;
tai_t tai[16]; /* TODO: max 65535 */
c_uint32_t repetition_period;
c_uint32_t number_of_broadcast;
c_uint8_t data_coding_scheme;
c_uint32_t message_length;
c_uint8_t message_contents[1024]; /* TODO: max 9600 */
} sbc_pws_data_t;
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __SBC_MESSAGE_H__ */