new: HSS Cx interface is added

This commit is contained in:
Sukchan Lee 2021-04-05 17:09:39 +09:00
parent 23c1fee516
commit 41c6bb4681
47 changed files with 4742 additions and 1393 deletions

View File

@ -167,6 +167,8 @@ hss:
connect:
- identity: mme.localdomain
addr: 127.0.0.2
- identity: ims.localdomain
addr: 127.0.0.1
pcrf:
freeDiameter:
identity: pcrf.localdomain
@ -184,7 +186,7 @@ pcrf:
connect:
- identity: smf.localdomain
addr: 127.0.0.4
- identity: pcscf.localdomain
- identity: ims.localdomain
addr: 127.0.0.1
#nrf:

View File

@ -97,6 +97,10 @@ static void recalculate_pool_size(void)
#define MAX_CSMAP_POOL 128
self.pool.csmap = MAX_CSMAP_POOL; /* Num of TAI-LAI Mapping Table */
#define MAX_NUM_OF_IMPU 8
self.pool.impi = self.max.ue;
self.pool.impu = self.pool.impi * MAX_NUM_OF_IMPU;
}
static void regenerate_all_timer_duration(void)

View File

@ -126,6 +126,9 @@ typedef struct ogs_app_context_s {
uint64_t gtp_node;
uint64_t pfcp_xact;
uint64_t pfcp_node;
uint64_t impi;
uint64_t impu;
} pool;
struct {

View File

@ -604,7 +604,7 @@ typedef struct ogs_subscription_data_s {
int num_of_slice;
ogs_slice_data_t slice[OGS_MAX_NUM_OF_SLICE];
#define OGS_MAX_NUM_OF_MSISDN 4
#define OGS_MAX_NUM_OF_MSISDN 2
int num_of_msisdn;
struct {
uint8_t buf[OGS_MAX_MSISDN_LEN];

View File

@ -230,3 +230,17 @@ uint64_t ogs_uint64_from_string(char *str)
return x;
}
void ogs_extract_digit_from_string(char *digit, char *string)
{
ogs_assert(string);
ogs_assert(digit);
while(*string) {
if (*string >= '0' && *string <= '9')
*digit++ = *string;
string++;
}
*digit = 0;
}

View File

@ -49,6 +49,8 @@ char *ogs_uint64_to_string(uint64_t x);
ogs_uint24_t ogs_uint24_from_string(char *str);
uint64_t ogs_uint64_from_string(char *str);
void ogs_extract_digit_from_string(char *digit, char *string);
#ifdef __cplusplus
}
#endif

View File

@ -22,8 +22,6 @@
#define CHECK_dict_search( _type, _criteria, _what, _result ) \
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) );
#define OGS_3GPP_VENDOR_ID 10415
struct dict_object *ogs_diam_session_id = NULL;
struct dict_object *ogs_diam_origin_host = NULL;
struct dict_object *ogs_diam_origin_realm = NULL;

View File

@ -28,16 +28,18 @@
extern "C" {
#endif
#define OGS_DIAM_AVP_CODE_FRAME_IP_ADDRESS 8
#define OGS_DIAM_AVP_CODE_FRAME_IPV6_PREFIX 97
#define OGS_3GPP_VENDOR_ID 10415
#define OGS_DIAM_AVP_CODE_FRAME_IP_ADDRESS 8
#define OGS_DIAM_AVP_CODE_FRAME_IPV6_PREFIX 97
/* Result-Code AVP */
#define OGS_DIAM_UNKNOWN_PEER 3010
#define OGS_DIAM_AVP_UNSUPPORTED 5001
#define OGS_DIAM_UNKNOWN_SESSION_ID 5002
#define OGS_DIAM_AUTHORIZATION_REJECTED 5003
#define OGS_DIAM_MISSING_AVP 5004
#define OGS_DIAM_INVALID_AVP_VALUE 5005
#define OGS_DIAM_UNKNOWN_PEER 3010
#define OGS_DIAM_AVP_UNSUPPORTED 5001
#define OGS_DIAM_UNKNOWN_SESSION_ID 5002
#define OGS_DIAM_AUTHORIZATION_REJECTED 5003
#define OGS_DIAM_MISSING_AVP 5004
#define OGS_DIAM_INVALID_AVP_VALUE 5005
extern struct dict_object *ogs_diam_session_id;
extern struct dict_object *ogs_diam_origin_host;

567
lib/diameter/cx/dict.c Normal file
View File

@ -0,0 +1,567 @@
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Thomas Klausner <tk@giga.or.at> *
* *
* Copyright (c) 2013, Thomas Klausner *
* All rights reserved. *
* *
* Written under contract by nfotex IT GmbH, http://nfotex.com/ *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
/*
* Dictionary definitions for objects specified for DCCA by 3GPP.
*
* This extensions contains a lot of AVPs from various 3GPP standards
* documents, and some rules for the grouped AVPs described therein.
*
* This extension does not contain ALL AVPs described by 3GPP, but
* quite a big number of them.
*
* When extending the AVPs, please edit dict_rx.org instead and
* create pastable code with contrib/tools/org_to_fd.pl.
*
* Some points of consideration:
* 1. This dictionary could be split up per document.
*
* + pro: you can only load the AVPs/Rules you're interested in ->
* smaller memory size
*
* - con: the documents use AVPs from each other A LOT, so setting the
* dependencies correctly will be annoying
*
* - con: you need to load all of them as extensions
*
* 2. This dictionary contains ONE AVP in the "3GPP2" vendor space,
* since I found it wasteful to write a separate dictionary just for
* one AVP. Also, it is defined in a 3GPP document.
*
* 3. While there are quite a number of rules here already, many more
* are missing. I've only added rules for those grouped AVPs or
* commands in which I was concretely interested so far; many more
* will need to be added to make this complete.
*
* That being said, I hope this will be useful for you.
*
*/
/*
* Some comments on the 3GPP Standards documents themselves:
*
* 1. It would be good if 29.061 was reviewed to check for each AVP if
* it is Mandatory or not. The data currently in the document does not
* match what was in the previous version of the freeDiameter
* extension (the one that existedbefore I rewrote it) or what I saw
* so far. IIRC, even the table and the document contradict each
* other. The AVP table is also missing an entry for
* "External-Identifier", 28.
*
* 2. 29.140 has conflicting AVP names with other documents:
* - Sequence-Number is also in 32.329
* - Recipient-Address is also in 32.299
* - Status is also in 32.299
*
* 3. 29.229 has name conflict with 29.329 about User-Data (different
* AVP code 702, instead of 606) -- the weird thing is, the latter
* uses some AVPs from the former, but not this one.
*/
#include <freeDiameter/extension.h>
/* The content of this file follows the same structure as dict_base_proto.c */
#define CHECK_dict_new( _type, _data, _parent, _ref ) \
CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict, (_type), (_data), (_parent), (_ref)) );
#define CHECK_dict_search( _type, _criteria, _what, _result ) \
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) );
struct local_rules_definition {
struct dict_avp_request avp_vendor_plus_name;
enum rule_position position;
int min;
int max;
};
#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 )
/* Attention! This version of the macro uses AVP_BY_NAME_AND_VENDOR, in contrast to most other copies! */
#define PARSE_loc_rules( _rulearray, _parent) { \
int __ar; \
for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) { \
struct dict_rule_data __data = { NULL, \
(_rulearray)[__ar].position, \
0, \
(_rulearray)[__ar].min, \
(_rulearray)[__ar].max}; \
__data.rule_order = RULE_ORDER(__data.rule_position); \
CHECK_FCT( fd_dict_search( \
fd_g_config->cnf_dict, \
DICT_AVP, \
AVP_BY_NAME_AND_VENDOR, \
&(_rulearray)[__ar].avp_vendor_plus_name, \
&__data.rule_avp, 0 ) ); \
if ( !__data.rule_avp ) { \
TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_vendor_plus_name.avp_name); \
return ENOENT; \
} \
CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL), \
{ \
TRACE_DEBUG(INFO, "Error on rule with AVP '%s'", \
(_rulearray)[__ar].avp_vendor_plus_name.avp_name); \
return EINVAL; \
} ); \
} \
}
#define enumval_def_u32( _val_, _str_ ) \
{ _str_, { .u32 = _val_ }}
#define enumval_def_os( _len_, _val_, _str_ ) \
{ _str_, { .os = { .data = (unsigned char *)_val_, .len = _len_ }}}
int ogs_dict_cx_entry(char *conffile)
{
/* Applications section */
{
/* Create the vendors */
{
struct dict_object * vendor;
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "3GPP", &vendor, ENOENT));
struct dict_application_data app_data = { 16777216, "Cx" };
CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &app_data, vendor, NULL));
}
}
/* Command section */
{
struct dict_object *cx;
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Cx", &cx, ENOENT));
/* User-Authorization-Request (UAR) Command */
{
struct dict_object* cmd_uar;
struct dict_cmd_data data = {
300, /* Code */
"3GPP/User-Authorization-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Visited-Network-Identifier" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "User-Authorization-Type" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "UAR-Flags" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_uar);
PARSE_loc_rules(rules, cmd_uar);
}
/* User-Authorization-Answer (UAA) Command */
{
struct dict_object* cmd_uaa;
struct dict_cmd_data data = {
300, /* Code */
"3GPP/User-Authorization-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Capabilities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_uaa);
PARSE_loc_rules(rules, cmd_uaa);
}
/* Location-Info-Request (LIR) Command */
{
struct dict_object* cmd_lir;
struct dict_cmd_data data = {
302, /* Code */
"3GPP/Location-Info-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Originating-Request" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "User-Authorization-Type" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Session-Priority" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_lir);
PARSE_loc_rules(rules, cmd_lir);
}
/* Location-Info-Answer (LIA) Command */
{
struct dict_object* cmd_lia;
struct dict_cmd_data data = {
302, /* Code */
"3GPP/Location-Info-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Capabilities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "LIA-Flags" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_lia);
PARSE_loc_rules(rules, cmd_lia);
}
/* Multimedia-Auth-Request (MAR) Command */
{
struct dict_object* cmd_mar;
struct dict_cmd_data data = {
303, /* Code */
"3GPP/Multimedia-Auth-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Number-Auth-Items" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 },
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_mar);
PARSE_loc_rules(rules, cmd_mar);
}
/* Multimedia-Auth-Answer (MAA) Command */
{
struct dict_object* cmd_maa;
struct dict_cmd_data data = {
303, /* Code */
"3GPP/Multimedia-Auth-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Number-Auth-Items" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_maa);
PARSE_loc_rules(rules, cmd_maa);
}
/* Server-Assignment-Request (SAR) Command */
{
struct dict_object* cmd_sar;
struct dict_cmd_data data = {
301, /* Code */
"3GPP/Server-Assignment-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Assignment-Type" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "User-Data-Already-Available" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SCSCF-Restoration-Info" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Multiple-Registration-Indication" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Session-Priority" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_sar);
PARSE_loc_rules(rules, cmd_sar);
}
/* Server-Assignment-Answer (SAA) Command */
{
struct dict_object* cmd_saa;
struct dict_cmd_data data = {
301, /* Code */
"3GPP/Server-Assignment-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "User-Data" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Charging-Information" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Loose-Route-Indication" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SCSCF-Restoration-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Registered-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Priviledged-Sender-Indication" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_saa);
PARSE_loc_rules(rules, cmd_saa);
}
/* Registration-Termination-Request (RTR) Command */
{
struct dict_object* cmd_rtr;
struct dict_cmd_data data = {
304, /* Code */
"3GPP/Registration-Termination-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Deregistration-Reason" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_rtr);
PARSE_loc_rules(rules, cmd_rtr);
}
/* Registration-Termination-Answer (RTA) Command */
{
struct dict_object* cmd_rta;
struct dict_cmd_data data = {
304, /* Code */
"3GPP/Registration-Termination-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Identity-with-Emergency-Registration" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_rta);
PARSE_loc_rules(rules, cmd_rta);
}
/* Push-Profile-Request (PPR) Command */
{
struct dict_object* cmd_ppr;
struct dict_cmd_data data = {
305, /* Code */
"3GPP/Push-Profile-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "User-Data" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Charging-Information" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_ppr);
PARSE_loc_rules(rules, cmd_ppr);
}
/* Push-Profile-Answer (PPA) Command */
{
struct dict_object* cmd_ppa;
struct dict_cmd_data data = {
305, /* Code */
"3GPP/Push-Profile-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, cx, &cmd_ppa);
PARSE_loc_rules(rules, cmd_ppa);
}
}
LOG_D( "Extension 'Dictionary definitions for DCCA 3GPP' initialized");
return 0;
}
#if 0 /* modified by acetcom */
EXTENSION_ENTRY("dict_cx", ogs_dict_cx_entry, "dict_dcca_3gpp");
#endif

View File

@ -0,0 +1,40 @@
# Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
# This file is part of Open5GS.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libdiameter_cx_sources = files('''
ogs-diameter-cx.h
message.h
dict.c
message.c
'''.split())
libdiameter_cx_inc = include_directories('.')
libdiameter_cx = library('ogsdiameter-cx',
sources : libdiameter_cx_sources,
version : libogslib_version,
c_args : libdiameter_common_cc_flags,
include_directories : libdiameter_cx_inc,
dependencies : libdiameter_common_dep,
install : true)
libdiameter_cx_dep = declare_dependency(
link_with : libdiameter_cx,
include_directories : libdiameter_cx_inc,
dependencies : libdiameter_common_dep)

211
lib/diameter/cx/message.c Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-diameter-cx.h"
#define CHECK_dict_search( _type, _criteria, _what, _result ) \
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) );
struct dict_object *ogs_diam_cx_application = NULL;
struct dict_object *ogs_diam_cx_cmd_uar = NULL;
struct dict_object *ogs_diam_cx_cmd_uaa = NULL;
struct dict_object *ogs_diam_cx_cmd_mar = NULL;
struct dict_object *ogs_diam_cx_cmd_maa = NULL;
struct dict_object *ogs_diam_cx_cmd_sar = NULL;
struct dict_object *ogs_diam_cx_cmd_saa = NULL;
struct dict_object *ogs_diam_cx_public_identity = NULL;
struct dict_object *ogs_diam_cx_visited_network_identifier = NULL;
struct dict_object *ogs_diam_cx_server_name = NULL;
struct dict_object *ogs_diam_cx_sip_number_auth_items = NULL;
struct dict_object *ogs_diam_cx_sip_item_number = NULL;
struct dict_object *ogs_diam_cx_sip_auth_data_item = NULL;
struct dict_object *ogs_diam_cx_sip_authentication_scheme = NULL;
struct dict_object *ogs_diam_cx_sip_authenticate = NULL;
struct dict_object *ogs_diam_cx_sip_authorization = NULL;
struct dict_object *ogs_diam_cx_confidentiality_key = NULL;
struct dict_object *ogs_diam_cx_integrity_key = NULL;
struct dict_object *ogs_diam_cx_server_assignment_type = NULL;
struct dict_object *ogs_diam_cx_user_data_already_available = NULL;
struct dict_object *ogs_diam_cx_user_data = NULL;
struct dict_object *ogs_diam_cx_charging_information = NULL;
struct dict_object *ogs_diam_cx_primary_event_charging_function_name = NULL;
struct dict_object *ogs_diam_cx_secondary_event_charging_function_name = NULL;
struct dict_object
*ogs_diam_cx_primary_charging_collection_function_name = NULL;
struct dict_object
*ogs_diam_cx_secondary_charging_collection_function_name = NULL;
const char *ogs_diam_cx_xml_version="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
const char *ogs_diam_cx_xml_ims_subscription_s="<IMSSubscription>";
const char *ogs_diam_cx_xml_ims_subscription_e="</IMSSubscription>";
const char *ogs_diam_cx_xml_private_id_s="<PrivateID>";
const char *ogs_diam_cx_xml_private_id_e="</PrivateID>";
const char *ogs_diam_cx_xml_service_profile_s="<ServiceProfile>";
const char *ogs_diam_cx_xml_service_profile_e="</ServiceProfile>";
const char *ogs_diam_cx_xml_public_id_s="<PublicIdentity>";
const char *ogs_diam_cx_xml_public_id_e="</PublicIdentity>";
const char *ogs_diam_cx_xml_barring_indication_s="<BarringIndication>";
const char *ogs_diam_cx_xml_barring_indication_e="</BarringIndication>";
const char *ogs_diam_cx_xml_identity_s="<Identity>";
const char *ogs_diam_cx_xml_identity_e="</Identity>";
const char *ogs_diam_cx_xml_identity_type_s="<IdentityType>";
const char *ogs_diam_cx_xml_identity_type_e="</IdentityType>";
const char *ogs_diam_cx_xml_wildcarded_psi_s="<WildcardedPSI>";
const char *ogs_diam_cx_xml_wildcarded_psi_e="</WildcardedPSI>";
const char *ogs_diam_cx_xml_display_name_s="<DisplayName>";
const char *ogs_diam_cx_xml_display_name_e="</DisplayName>";
const char *ogs_diam_cx_xml_ifc_s="<InitialFilterCriteria>";
const char *ogs_diam_cx_xml_ifc_e="</InitialFilterCriteria>";
const char *ogs_diam_cx_xml_priority_s="<Priority>";
const char *ogs_diam_cx_xml_priority_e="</Priority>";
const char *ogs_diam_cx_xml_tp_s="<TriggerPoint>";
const char *ogs_diam_cx_xml_tp_e="</TriggerPoint>";
const char *ogs_diam_cx_xml_cnf_s="<ConditionTypeCNF>";
const char *ogs_diam_cx_xml_cnf_e="</ConditionTypeCNF>";
const char *ogs_diam_cx_xml_spt_s="<SPT>";
const char *ogs_diam_cx_xml_spt_e="</SPT>";
const char *ogs_diam_cx_xml_condition_negated_s="<ConditionNegated>";
const char *ogs_diam_cx_xml_condition_negated_e="</ConditionNegated>";
const char *ogs_diam_cx_xml_group_s="<Group>";
const char *ogs_diam_cx_xml_group_e="</Group>";
const char *ogs_diam_cx_xml_req_uri_s="<RequestURI>";
const char *ogs_diam_cx_xml_req_uri_e="</RequestURI>";
const char *ogs_diam_cx_xml_method_s="<Method>";
const char *ogs_diam_cx_xml_method_e="</Method>";
const char *ogs_diam_cx_xml_sip_hdr_s="<SIPHeader>";
const char *ogs_diam_cx_xml_sip_hdr_e="</SIPHeader>";
const char *ogs_diam_cx_xml_session_case_s="<SessionCase>";
const char *ogs_diam_cx_xml_session_case_e="</SessionCase>";
const char *ogs_diam_cx_xml_session_desc_s="<SessionDescription>";
const char *ogs_diam_cx_xml_session_desc_e="</SessionDescription>";
const char *ogs_diam_cx_xml_registration_type_s="<RegistrationType>";
const char *ogs_diam_cx_xml_registration_type_e="</RegistrationType>";
const char *ogs_diam_cx_xml_header_s="<Header>";
const char *ogs_diam_cx_xml_header_e="</Header>";
const char *ogs_diam_cx_xml_content_s="<Content>";
const char *ogs_diam_cx_xml_content_e="</Content>";
const char *ogs_diam_cx_xml_line_s="<Line>";
const char *ogs_diam_cx_xml_line_e="</Line>";
const char *ogs_diam_cx_xml_app_server_s="<ApplicationServer>";
const char *ogs_diam_cx_xml_app_server_e="</ApplicationServer>";
const char *ogs_diam_cx_xml_server_name_s="<ServerName>";
const char *ogs_diam_cx_xml_server_name_e="</ServerName>";
const char *ogs_diam_cx_xml_default_handling_s="<DefaultHandling>";
const char *ogs_diam_cx_xml_default_handling_e="</DefaultHandling>";
const char *ogs_diam_cx_xml_service_info_s="<ServiceInfo>";
const char *ogs_diam_cx_xml_service_info_e="</ServiceInfo>";
const char *ogs_diam_cx_xml_include_register_request="<IncludeRegisterRequest/>";
const char *ogs_diam_cx_xml_include_register_response="<IncludeRegisterResponse/>";
const char *ogs_diam_cx_xml_profile_part_ind_s="<ProfilePartIndicator>";
const char *ogs_diam_cx_xml_profile_part_ind_e="</ProfilePartIndicator>";
const char *ogs_diam_cx_xml_cn_services_auth_s="<CoreNetworkServicesAuthorization>";
const char *ogs_diam_cx_xml_cn_services_auth_e="</CoreNetworkServicesAuthorization>";
const char *ogs_diam_cx_xml_subs_media_profile_id_s="<SubscribedMediaProfileId>";
const char *ogs_diam_cx_xml_subs_media_profile_id_e="</SubscribedMediaProfileId>";
const char *ogs_diam_cx_xml_shared_ifc_set_id_s="<Extension><SharedIFCSetID>";
const char *ogs_diam_cx_xml_shared_ifc_set_id_e="</SharedIFCSetID></Extension>";
const char *ogs_diam_cx_xml_extension_s="<Extension>";
const char *ogs_diam_cx_xml_extension_e="</Extension>";
extern int ogs_dict_cx_entry(char *conffile);
int ogs_diam_cx_init(void)
{
application_id_t id = OGS_DIAM_CX_APPLICATION_ID;
ogs_assert(ogs_dict_cx_entry(NULL) == 0);
CHECK_dict_search(DICT_APPLICATION, APPLICATION_BY_ID,
(void *)&id, &ogs_diam_cx_application);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME,
"3GPP/User-Authorization-Request", &ogs_diam_cx_cmd_uar);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME,
"3GPP/User-Authorization-Answer", &ogs_diam_cx_cmd_uaa);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME,
"3GPP/Multimedia-Auth-Request", &ogs_diam_cx_cmd_mar);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME,
"3GPP/Multimedia-Auth-Answer", &ogs_diam_cx_cmd_maa);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME,
"3GPP/Server-Assignment-Request", &ogs_diam_cx_cmd_sar);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME,
"3GPP/Server-Assignment-Answer", &ogs_diam_cx_cmd_saa);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Public-Identity", &ogs_diam_cx_public_identity);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Visited-Network-Identifier",
&ogs_diam_cx_visited_network_identifier);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Server-Name", &ogs_diam_cx_server_name);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"SIP-Number-Auth-Items", &ogs_diam_cx_sip_number_auth_items);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"SIP-Item-Number", &ogs_diam_cx_sip_item_number);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"SIP-Auth-Data-Item", &ogs_diam_cx_sip_auth_data_item);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"SIP-Authentication-Scheme",
&ogs_diam_cx_sip_authentication_scheme);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"SIP-Authenticate", &ogs_diam_cx_sip_authenticate);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"SIP-Authorization", &ogs_diam_cx_sip_authorization);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Confidentiality-Key", &ogs_diam_cx_confidentiality_key);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Integrity-Key", &ogs_diam_cx_integrity_key);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Server-Assignment-Type", &ogs_diam_cx_server_assignment_type);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"User-Data-Already-Available",
&ogs_diam_cx_user_data_already_available);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"User-Data", &ogs_diam_cx_user_data);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Charging-Information", &ogs_diam_cx_charging_information);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Primary-Event-Charging-Function-Name",
&ogs_diam_cx_primary_event_charging_function_name);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Secondary-Event-Charging-Function-Name",
&ogs_diam_cx_secondary_event_charging_function_name);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Primary-Charging-Collection-Function-Name",
&ogs_diam_cx_primary_charging_collection_function_name);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS,
"Secondary-Charging-Collection-Function-Name",
&ogs_diam_cx_secondary_charging_collection_function_name);
return 0;
}

186
lib/diameter/cx/message.h Normal file
View File

@ -0,0 +1,186 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if !defined(OGS_DIAMETER_INSIDE) && !defined(OGS_DIAMETER_COMPILATION)
#error "This header cannot be included directly."
#endif
#ifndef OGS_DIAM_CX_MESSAGE_H
#define OGS_DIAM_CX_MESSAGE_H
#ifdef __cplusplus
extern "C" {
#endif
#define OGS_DIAM_CX_APPLICATION_ID 16777216
extern struct dict_object *ogs_diam_cx_application;
extern struct dict_object *ogs_diam_cx_cmd_uar;
extern struct dict_object *ogs_diam_cx_cmd_uaa;
extern struct dict_object *ogs_diam_cx_cmd_mar;
extern struct dict_object *ogs_diam_cx_cmd_maa;
extern struct dict_object *ogs_diam_cx_cmd_sar;
extern struct dict_object *ogs_diam_cx_cmd_saa;
extern struct dict_object *ogs_diam_cx_public_identity;
extern struct dict_object *ogs_diam_cx_visited_network_identifier;
extern struct dict_object *ogs_diam_cx_server_name;
extern struct dict_object *ogs_diam_cx_sip_number_auth_items;
extern struct dict_object *ogs_diam_cx_sip_item_number;
extern struct dict_object *ogs_diam_cx_sip_auth_data_item;
#define OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA "Digest-AKAv1-MD5"
#define OGS_DIAM_CX_AUTH_SCHEME_SIP_DIGEST "SIP Digest"
#define OGS_DIAM_CX_AUTH_SCHEME_NASS_BUNDLED "NASS-Bundled"
#define OGS_DIAM_CX_AUTH_SCHEME_GPRS_IMS_BUNDLED "Early-IMS-Security"
#define OGS_DIAM_CX_AUTH_SCHEME_UNKNOWN "Unknown"
extern struct dict_object *ogs_diam_cx_sip_authentication_scheme;
extern struct dict_object *ogs_diam_cx_sip_authenticate;
extern struct dict_object *ogs_diam_cx_sip_authorization;
extern struct dict_object *ogs_diam_cx_confidentiality_key;
extern struct dict_object *ogs_diam_cx_integrity_key;
#define OGS_DIAM_CX_SERVER_NO_ASSIGNMENT 0
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION 1
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_RE_REGISTRATION 2
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_UNREGISTERED_USER 3
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_TIMEOUT_DEREGISTRATION 4
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_USER_DEREGISTRATION 5
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_TIMEOUT_DEREGISTRATION_STORE_SERVER_NAME 6
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_USER_DEREGISTRATION_STORE_SERVER_NAME 7
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_ADMINISTRATIVE_DEREGISTRATION 8
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_AUTHENTICATION_FAILURE 9
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_AUTHENTICATION_TIMEOUT 10
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_DEREGISTRATION_TOO_MUCH_DATA 11
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_AAA_USER_DATA_REQUEST 12
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_PGW_UPDATE 13
#define OGS_DIAM_CX_SERVER_ASSIGNMENT_RESTORATION 14
extern struct dict_object *ogs_diam_cx_server_assignment_type;
#define OGS_DIAM_CX_USER_DATA_NOT_AVAILABLE 0
#define OGS_DIAM_CX_USER_DATA_ALREADY_AVAILABLE 1
extern struct dict_object *ogs_diam_cx_user_data_already_available;
extern struct dict_object *ogs_diam_cx_user_data;
extern struct dict_object *ogs_diam_cx_charging_information;
extern struct dict_object *ogs_diam_cx_primary_event_charging_function_name;
extern struct dict_object *ogs_diam_cx_secondary_event_charging_function_name;
extern struct dict_object
*ogs_diam_cx_primary_charging_collection_function_name;
extern struct dict_object
*ogs_diam_cx_secondary_charging_collection_function_name;
#define OGS_DIAM_CX_FIRST_REGISTRATION 2001
#define OGS_DIAM_CX_SUBSEQUENT_REGISTRATION 2002
#define OGS_DIAM_CX_UNREGISTERED_SERVICE 2003
#define OGS_DIAM_CX_SERVER_NAME_NOT_STORED 2004
#define OGS_DIAM_CX_ERROR_USER_UNKNOWN 5001
#define OGS_DIAM_CX_ERROR_IDENTITIES_DONT_MATCH 5002
#define OGS_DIAM_CX_ERROR_IDENTITY_NOT_REGISTERED 5003
#define OGS_DIAM_CX_ERROR_ROAMING_NOT_ALLOWED 5004
#define OGS_DIAM_CX_ERROR_IDENTITY_ALREADY_REGISTERED 5005
#define OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED 5006
#define OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE 5007
#define OGS_DIAM_CX_ERROR_TOO_MUCH_DATA 5008
#define OGS_DIAM_CX_ERROR_NOT_SUPPORTED_USER_DATA 5009
#define OGS_DIAM_CX_ERROR_FEATURE_UNSUPPORTED 5011
#define OGS_DIAM_CX_ERROR_SERVING_NODE_FEATURE_UNSUPPORTED 5012
int ogs_diam_cx_init(void);
extern const char *ogs_diam_cx_xml_version;
extern const char *ogs_diam_cx_xml_ims_subscription_s;
extern const char *ogs_diam_cx_xml_ims_subscription_e;
extern const char *ogs_diam_cx_xml_private_id_s;
extern const char *ogs_diam_cx_xml_private_id_e;
extern const char *ogs_diam_cx_xml_service_profile_s;
extern const char *ogs_diam_cx_xml_service_profile_e;
extern const char *ogs_diam_cx_xml_public_id_s;
extern const char *ogs_diam_cx_xml_public_id_e;
extern const char *ogs_diam_cx_xml_barring_indication_s;
extern const char *ogs_diam_cx_xml_barring_indication_e;
extern const char *ogs_diam_cx_xml_identity_s;
extern const char *ogs_diam_cx_xml_identity_e;
extern const char *ogs_diam_cx_xml_identity_type_s;
extern const char *ogs_diam_cx_xml_identity_type_e;
extern const char *ogs_diam_cx_xml_wildcarded_psi_s;
extern const char *ogs_diam_cx_xml_wildcarded_psi_e;
extern const char *ogs_diam_cx_xml_display_name_s;
extern const char *ogs_diam_cx_xml_display_name_e;
extern const char *ogs_diam_cx_xml_ifc_s;
extern const char *ogs_diam_cx_xml_ifc_e;
extern const char *ogs_diam_cx_xml_priority_s;
extern const char *ogs_diam_cx_xml_priority_e;
extern const char *ogs_diam_cx_xml_tp_s;
extern const char *ogs_diam_cx_xml_tp_e;
extern const char *ogs_diam_cx_xml_cnf_s;
extern const char *ogs_diam_cx_xml_cnf_e;
extern const char *ogs_diam_cx_xml_spt_s;
extern const char *ogs_diam_cx_xml_spt_e;
extern const char *ogs_diam_cx_xml_condition_negated_s;
extern const char *ogs_diam_cx_xml_condition_negated_e;
extern const char *ogs_diam_cx_xml_group_s;
extern const char *ogs_diam_cx_xml_group_e;
extern const char *ogs_diam_cx_xml_req_uri_s;
extern const char *ogs_diam_cx_xml_req_uri_e;
extern const char *ogs_diam_cx_xml_method_s;
extern const char *ogs_diam_cx_xml_method_e;
extern const char *ogs_diam_cx_xml_sip_hdr_s;
extern const char *ogs_diam_cx_xml_sip_hdr_e;
extern const char *ogs_diam_cx_xml_session_case_s;
extern const char *ogs_diam_cx_xml_session_case_e;
extern const char *ogs_diam_cx_xml_session_desc_s;
extern const char *ogs_diam_cx_xml_session_desc_e;
extern const char *ogs_diam_cx_xml_registration_type_s;
extern const char *ogs_diam_cx_xml_registration_type_e;
extern const char *ogs_diam_cx_xml_header_s;
extern const char *ogs_diam_cx_xml_header_e;
extern const char *ogs_diam_cx_xml_content_s;
extern const char *ogs_diam_cx_xml_content_e;
extern const char *ogs_diam_cx_xml_line_s;
extern const char *ogs_diam_cx_xml_line_e;
extern const char *ogs_diam_cx_xml_app_server_s;
extern const char *ogs_diam_cx_xml_app_server_e;
extern const char *ogs_diam_cx_xml_server_name_s;
extern const char *ogs_diam_cx_xml_server_name_e;
extern const char *ogs_diam_cx_xml_default_handling_s;
extern const char *ogs_diam_cx_xml_default_handling_e;
extern const char *ogs_diam_cx_xml_service_info_s;
extern const char *ogs_diam_cx_xml_service_info_e;
extern const char *ogs_diam_cx_xml_include_register_request;
extern const char *ogs_diam_cx_xml_include_register_response;
extern const char *ogs_diam_cx_xml_profile_part_ind_s;
extern const char *ogs_diam_cx_xml_profile_part_ind_e;
extern const char *ogs_diam_cx_xml_cn_services_auth_s;
extern const char *ogs_diam_cx_xml_cn_services_auth_e;
extern const char *ogs_diam_cx_xml_subs_media_profile_id_s;
extern const char *ogs_diam_cx_xml_subs_media_profile_id_e;
extern const char *ogs_diam_cx_xml_shared_ifc_set_id_s;
extern const char *ogs_diam_cx_xml_shared_ifc_set_id_e;
extern const char *ogs_diam_cx_xml_extension_s;
extern const char *ogs_diam_cx_xml_extension_e;
#ifdef __cplusplus
}
#endif
#endif /* OGS_DIAM_OGS_DIAM_CX_MESSAGE_H */

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef OGS_DIAMETER_CX_H
#define OGS_DIAMETER_CX_H
#include "ogs-diameter-common.h"
#define OGS_DIAMETER_INSIDE
#include "diameter/cx/message.h"
#undef OGS_DIAMETER_INSIDE
#ifdef __cplusplus
extern "C" {
#endif
/* Nothing */
#ifdef __cplusplus
}
#endif
#endif /* OGS_DIAMETER_CX_H */

View File

@ -19,3 +19,4 @@ subdir('common')
subdir('gx')
subdir('rx')
subdir('s6a')
subdir('cx')

View File

@ -148,13 +148,6 @@ int ogs_dict_rx_entry(char *conffile)
{
/* Create the vendors */
{
struct dict_object * vendor;
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "3GPP", &vendor, ENOENT));
struct dict_application_data app_data = { 16777216, "Cx" };
CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &app_data, vendor, NULL));
}
{
struct dict_object * vendor;
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "3GPP", &vendor, ENOENT));
@ -165,404 +158,6 @@ int ogs_dict_rx_entry(char *conffile)
}
/* Command section */
{
struct dict_object* app;
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Cx", &app, ENOENT));
/* User-Authorization-Request (UAR) Command */
{
struct dict_object* cmd_uar;
struct dict_cmd_data data = {
300, /* Code */
"3GPP/User-Authorization-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Visited-Network-Identifier" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "User-Authorization-Type" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "UAR-Flags" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_uar);
PARSE_loc_rules(rules, cmd_uar);
}
/* User-Authorization-Answer (UAA) Command */
{
struct dict_object* cmd_uaa;
struct dict_cmd_data data = {
300, /* Code */
"3GPP/User-Authorization-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Capabilities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_uaa);
PARSE_loc_rules(rules, cmd_uaa);
}
/* Location-Info-Request (LIR) Command */
{
struct dict_object* cmd_lir;
struct dict_cmd_data data = {
302, /* Code */
"3GPP/Location-Info-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Originating-Request" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "User-Authorization-Type" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Session-Priority" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_lir);
PARSE_loc_rules(rules, cmd_lir);
}
/* Location-Info-Answer (LIA) Command */
{
struct dict_object* cmd_lia;
struct dict_cmd_data data = {
302, /* Code */
"3GPP/Location-Info-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Capabilities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "LIA-Flags" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_lia);
PARSE_loc_rules(rules, cmd_lia);
}
/* Multimedia-Auth-Request (MAR) Command */
{
struct dict_object* cmd_mar;
struct dict_cmd_data data = {
303, /* Code */
"3GPP/Multimedia-Auth-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Number-Auth-Items" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 },
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_mar);
PARSE_loc_rules(rules, cmd_mar);
}
/* Multimedia-Auth-Answer (MAA) Command */
{
struct dict_object* cmd_maa;
struct dict_cmd_data data = {
303, /* Code */
"3GPP/Multimedia-Auth-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Number-Auth-Items" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_maa);
PARSE_loc_rules(rules, cmd_maa);
}
/* Server-Assignment-Request (SAR) Command */
{
struct dict_object* cmd_sar;
struct dict_cmd_data data = {
301, /* Code */
"3GPP/Server-Assignment-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Assignment-Type" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "User-Data-Already-Available" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SCSCF-Restoration-Info" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Multiple-Registration-Indication" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Session-Priority" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_sar);
PARSE_loc_rules(rules, cmd_sar);
}
/* Server-Assignment-Answer (SAA) Command */
{
struct dict_object* cmd_saa;
struct dict_cmd_data data = {
301, /* Code */
"3GPP/Server-Assignment-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "User-Data" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Charging-Information" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Loose-Route-Indication" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SCSCF-Restoration-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Registered-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Priviledged-Sender-Indication" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_saa);
PARSE_loc_rules(rules, cmd_saa);
}
/* Registration-Termination-Request (RTR) Command */
{
struct dict_object* cmd_rtr;
struct dict_cmd_data data = {
304, /* Code */
"3GPP/Registration-Termination-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Deregistration-Reason" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_rtr);
PARSE_loc_rules(rules, cmd_rtr);
}
/* Registration-Termination-Answer (RTA) Command */
{
struct dict_object* cmd_rta;
struct dict_cmd_data data = {
304, /* Code */
"3GPP/Registration-Termination-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Associated-Identities" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Identity-with-Emergency-Registration" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_rta);
PARSE_loc_rules(rules, cmd_rta);
}
/* Push-Profile-Request (PPR) Command */
{
struct dict_object* cmd_ppr;
struct dict_cmd_data data = {
305, /* Code */
"3GPP/Push-Profile-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "User-Data" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Charging-Information" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_ppr);
PARSE_loc_rules(rules, cmd_ppr);
}
/* Push-Profile-Answer (PPA) Command */
{
struct dict_object* cmd_ppa;
struct dict_cmd_data data = {
305, /* Code */
"3GPP/Push-Profile-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }
};
CHECK_dict_new(DICT_COMMAND, &data, app, &cmd_ppa);
PARSE_loc_rules(rules, cmd_ppa);
}
}
struct dict_object* rx;
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Rx", &rx, ENOENT));

View File

@ -27,6 +27,21 @@ int __hss_log_domain;
static int context_initialized = 0;
static OGS_POOL(impi_pool, hss_impi_t);
static OGS_POOL(impu_pool, hss_impu_t);
static hss_impi_t *impi_add(char *id);
static void impi_remove(hss_impi_t *impi);
static void impi_remove_all(void);
static hss_impi_t *impi_find_by_id(char *id);
static char *impi_get_server_name(hss_impi_t *impi);
static hss_impu_t *impu_add(hss_impi_t *impi, char *id);
static void impu_remove(hss_impu_t *impu);
static void impu_remove_all(hss_impi_t *impi);
static hss_impu_t *impu_find_by_id(hss_impi_t *impi, char *id);
hss_context_t* hss_self(void)
{
return &self;
@ -47,7 +62,13 @@ void hss_context_init(void)
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", ogs_core()->log.level);
ogs_log_install_domain(&__hss_log_domain, "hss", ogs_core()->log.level);
ogs_pool_init(&impi_pool, ogs_app()->pool.impi);
ogs_pool_init(&impu_pool, ogs_app()->pool.impu);
self.impi_hash = ogs_hash_make();
ogs_thread_mutex_init(&self.db_lock);
ogs_thread_mutex_init(&self.cx_lock);
context_initialized = 1;
}
@ -56,7 +77,16 @@ void hss_context_final(void)
{
ogs_assert(context_initialized == 1);
impi_remove_all();
ogs_assert(self.impi_hash);
ogs_hash_destroy(self.impi_hash);
ogs_pool_final(&impi_pool);
ogs_pool_final(&impu_pool);
ogs_thread_mutex_destroy(&self.db_lock);
ogs_thread_mutex_destroy(&self.cx_lock);
context_initialized = 0;
}
@ -276,8 +306,7 @@ int hss_db_auth_info(char *imsi_bcd, ogs_dbi_auth_info_t *auth_info)
return rv;
}
int hss_db_update_rand_and_sqn(
char *imsi_bcd, uint8_t *rand, uint64_t sqn)
int hss_db_update_sqn(char *imsi_bcd, uint8_t *rand, uint64_t sqn)
{
int rv;
char *supi = NULL;
@ -335,3 +364,236 @@ int hss_db_subscription_data(
return rv;
}
static hss_impi_t *impi_add(char *id)
{
hss_impi_t *impi = NULL;
ogs_assert(id);
ogs_pool_alloc(&impi_pool, &impi);
ogs_assert(impi);
memset(impi, 0, sizeof *impi);
impi->id = ogs_strdup(id);
ogs_assert(impi->id);
ogs_hash_set(self.impi_hash, impi->id, strlen(impi->id), impi);
ogs_list_add(&self.impi_list, impi);
return impi;
}
static void impi_remove(hss_impi_t *impi)
{
ogs_assert(impi);
ogs_list_remove(&self.impi_list, impi);
impu_remove_all(impi);
ogs_assert(impi->id);
ogs_hash_set(self.impi_hash, impi->id, strlen(impi->id), NULL);
ogs_free(impi->id);
ogs_pool_free(&impi_pool, impi);
}
static void impi_remove_all(void)
{
hss_impi_t *impi = NULL, *next = NULL;
ogs_list_for_each_safe(&self.impi_list, next, impi)
impi_remove(impi);
}
static hss_impi_t *impi_find_by_id(char *id)
{
ogs_assert(id);
return (hss_impi_t *)ogs_hash_get(self.impi_hash, id, strlen(id));
}
static char *impi_get_server_name(hss_impi_t *impi)
{
hss_impu_t *impu = NULL;
ogs_assert(impi);
ogs_list_for_each(&impi->impu_list, impu) {
if (impu->server_name)
return impu->server_name;
}
return NULL;
}
static hss_impu_t *impu_add(hss_impi_t *impi, char *id)
{
hss_impu_t *impu = NULL;
ogs_assert(impi);
ogs_assert(id);
ogs_pool_alloc(&impu_pool, &impu);
ogs_assert(impu);
memset(impu, 0, sizeof *impu);
impu->id = ogs_strdup(id);
ogs_assert(impu->id);
impu->impi = impi;
ogs_list_add(&impi->impu_list, impu);
return impu;
}
static void impu_remove(hss_impu_t *impu)
{
hss_impi_t *impi = NULL;
ogs_assert(impu);
impi = impu->impi;
ogs_assert(impi);
ogs_list_remove(&impi->impu_list, impu);
ogs_assert(impu->id);
ogs_free(impu->id);
if (impu->server_name)
ogs_free(impu->server_name);
ogs_pool_free(&impu_pool, impu);
}
static void impu_remove_all(hss_impi_t *impi)
{
hss_impu_t *impu = NULL, *next = NULL;
ogs_list_for_each_safe(&impi->impu_list, next, impu)
impu_remove(impu);
}
static hss_impu_t *impu_find_by_id(hss_impi_t *impi, char *id)
{
hss_impu_t *impu = NULL;
ogs_assert(impi);
ogs_assert(id);
ogs_list_for_each(&impi->impu_list, impu) {
if (!strcmp(impu->id, id))
return impu;
}
return NULL;
}
void hss_cx_associate_identity(char *user_name, char *public_identity)
{
hss_impi_t *impi = NULL;
hss_impu_t *impu = NULL;
ogs_assert(user_name);
ogs_assert(public_identity);
ogs_thread_mutex_lock(&self.cx_lock);
impi = impi_find_by_id(user_name);
if (!impi) {
impi = impi_add(user_name);
ogs_assert(impi);
}
impu = impu_find_by_id(impi, public_identity);
if (!impu) {
impu = impu_add(impi, public_identity);
ogs_assert(impu);
}
ogs_thread_mutex_unlock(&self.cx_lock);
}
bool hss_cx_identity_is_associated(char *user_name, char *public_identity)
{
bool match_result = false;
hss_impi_t *impi = NULL;
hss_impu_t *impu = NULL;
ogs_thread_mutex_lock(&self.cx_lock);
impi = impi_find_by_id(user_name);
if (impi) {
impu = impu_find_by_id(impi, public_identity);
if (impu) {
match_result = true;
}
}
ogs_thread_mutex_unlock(&self.cx_lock);
return match_result;
}
char *hss_cx_get_server_name(char *user_name, char *public_identity)
{
char *server_name = NULL;
hss_impi_t *impi = NULL;
hss_impu_t *impu = NULL;
ogs_thread_mutex_lock(&self.cx_lock);
impi = impi_find_by_id(user_name);
ogs_assert(impi);
impu = impu_find_by_id(impi, public_identity);
ogs_assert(impu);
server_name = impu->server_name;
if (!server_name) {
server_name = impi_get_server_name(impi);
}
ogs_thread_mutex_unlock(&self.cx_lock);
return server_name;
}
void hss_cx_set_server_name(
char *user_name, char *public_identity,
char *server_name, bool overwrite)
{
hss_impi_t *impi = NULL;
hss_impu_t *impu = NULL;
ogs_thread_mutex_lock(&self.cx_lock);
impi = impi_find_by_id(user_name);
ogs_assert(impi);
impu = impu_find_by_id(impi, public_identity);
ogs_assert(impu);
if (!impu->server_name) {
impu->server_name = ogs_strdup(server_name);
ogs_assert(impu->server_name);
} else {
if (strcmp(impu->server_name, server_name) != 0) {
if (overwrite == true) {
ogs_warn("S-CSCF reassignment[%s->%s]",
impu->server_name, server_name);
ogs_free(impu->server_name);
impu->server_name = ogs_strdup(server_name);
ogs_assert(impu->server_name);
} else {
ogs_error("Use Old S-CSCF[%s!=%s]",
server_name, impu->server_name);
}
}
}
ogs_thread_mutex_unlock(&self.cx_lock);
}

View File

@ -21,6 +21,7 @@
#define HSS_CONTEXT_H
#include "ogs-diameter-s6a.h"
#include "ogs-diameter-cx.h"
#include "ogs-dbi.h"
#include "ogs-app.h"
@ -34,12 +35,33 @@ extern int __hss_log_domain;
#define OGS_LOG_DOMAIN __hss_log_domain
typedef struct _hss_context_t {
const char *diam_conf_path; /* HSS Diameter conf path */
ogs_diam_config_t *diam_config; /* HSS Diameter config */
const char *diam_conf_path;/* HSS Diameter conf path */
ogs_diam_config_t *diam_config; /* HSS Diameter config */
ogs_thread_mutex_t db_lock;
ogs_thread_mutex_t cx_lock;
ogs_list_t impi_list;
ogs_hash_t *impi_hash; /* hash table (IMPI) */
} hss_context_t;
typedef struct hss_impi_s {
ogs_lnode_t lnode;
char *id;
ogs_list_t impu_list;
} hss_impi_t;
typedef struct hss_impu_s {
ogs_lnode_t lnode;
char *id;
char *server_name;
hss_impi_t *impi;
} hss_impu_t;
void hss_context_init(void);
void hss_context_final(void);
hss_context_t *hss_self(void);
@ -47,12 +69,20 @@ hss_context_t *hss_self(void);
int hss_context_parse_config(void);
int hss_db_auth_info(char *imsi_bcd, ogs_dbi_auth_info_t *auth_info);
int hss_db_update_rand_and_sqn(char *imsi_bcd, uint8_t *rand, uint64_t sqn);
int hss_db_update_sqn(char *imsi_bcd, uint8_t *rand, uint64_t sqn);
int hss_db_increment_sqn(char *imsi_bcd);
int hss_db_subscription_data(
char *imsi_bcd, ogs_subscription_data_t *subscription_data);
void hss_cx_associate_identity(char *user_name, char *public_identity);
bool hss_cx_identity_is_associated(char *user_name, char *public_identity);
char *hss_cx_get_server_name(char *user_name, char *public_identity);
void hss_cx_set_server_name(
char *user_name, char *public_identity,
char *server_name, bool overwrite);
#ifdef __cplusplus
}
#endif

999
src/hss/hss-cx-path.c Normal file
View File

@ -0,0 +1,999 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-crypt.h"
#include "hss-context.h"
#include "hss-fd-path.h"
/* handler for fallback cb */
static struct disp_hdl *hdl_cx_fb = NULL;
/* handler for User-Authorization-Request cb */
static struct disp_hdl *hdl_cx_uar = NULL;
/* handler for Multimedia-Auth-Request cb */
static struct disp_hdl *hdl_cx_mar = NULL;
/* handler for Server-Assignment-Request cb */
static struct disp_hdl *hdl_cx_sar = NULL;
static char *download_user_data(
char *user_name, ogs_subscription_data_t *subscription_data);
/* Default callback for the application. */
static int hss_ogs_diam_cx_fb_cb(struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
/* This CB should never be called */
ogs_warn("Unexpected message received!");
return ENOTSUP;
}
/* Callback for incoming User-Authorization-Request messages */
static int hss_ogs_diam_cx_uar_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int rv, ret;
uint32_t result_code = 0;
struct msg *ans, *qry;
struct avp_hdr *hdr;
union avp_value val;
char *user_name = NULL;
char *public_identity = NULL;
char *server_name = NULL;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
char msisdn_bcd[OGS_MAX_MSISDN_BCD_LEN+1];
ogs_subscription_data_t subscription_data;
ogs_assert(msg);
ogs_debug("User-Authorization-Request");
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
/* Get User-Name AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
user_name = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(user_name);
ogs_extract_digit_from_string(imsi_bcd, user_name);
/* Get Public-Identity AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
public_identity = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(public_identity);
ogs_extract_digit_from_string(msisdn_bcd, public_identity);
memset(&subscription_data, 0, sizeof(ogs_subscription_data_t));
rv = hss_db_subscription_data(imsi_bcd, &subscription_data);
if (rv != OGS_OK) {
ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN;
goto out;
}
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Associate IMPI(User-Name) + IMPU(Public-Identity) */
hss_cx_associate_identity(user_name, public_identity);
/* Get Server-Name for IMPI(User-Name) + IMPU(Public-Identity) */
server_name = hss_cx_get_server_name(user_name, public_identity);
if (!server_name)
result_code = OGS_DIAM_CX_FIRST_REGISTRATION;
else
result_code = OGS_DIAM_CX_SUBSEQUENT_REGISTRATION;
/* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */
ret = ogs_diam_message_experimental_rescode_set(
ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Server-Name AVP */
if (server_name) {
ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)server_name;
val.os.len = strlen(server_name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
}
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("User-Authorization-Answer");
/* Add this value to the stats */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_subscription_data_free(&subscription_data);
ogs_free(user_name);
ogs_free(public_identity);
return 0;
out:
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_subscription_data_free(&subscription_data);
ogs_free(user_name);
ogs_free(public_identity);
return 0;
}
/* Callback for incoming Multimedia-Auth-Request messages */
static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int rv, ret;
uint32_t result_code = 0;
struct msg *ans, *qry;
struct avp *sip_auth_data_item_avp = NULL;
struct avp *authentication_scheme_avp = NULL;
struct avp *sip_authorization_avp = NULL;
struct avp *avpch = NULL;
struct avp_hdr *hdr;
union avp_value val;
char *user_name = NULL;
char *public_identity = NULL;
char *server_name = NULL;
char *authentication_scheme = NULL;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
char msisdn_bcd[OGS_MAX_MSISDN_BCD_LEN+1];
ogs_dbi_auth_info_t auth_info;
uint8_t zero[OGS_RAND_LEN];
uint8_t authenticate[OGS_KEY_LEN*2];
uint8_t opc[OGS_KEY_LEN];
uint8_t sqn[OGS_SQN_LEN];
uint8_t autn[OGS_AUTN_LEN];
uint8_t ik[OGS_KEY_LEN];
uint8_t ck[OGS_KEY_LEN];
uint8_t ak[OGS_AK_LEN];
uint8_t xres[OGS_MAX_RES_LEN];
size_t xres_len = 8;
uint8_t mac_s[OGS_MAC_S_LEN];
ogs_assert(msg);
ogs_debug("Multimedia-Auth-Request");
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
/* Get User-Name AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
user_name = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(user_name);
ogs_extract_digit_from_string(imsi_bcd, user_name);
/* Get Public-Identity AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
public_identity = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(public_identity);
ogs_extract_digit_from_string(msisdn_bcd, public_identity);
/* Get Server-Name AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_cx_server_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
server_name = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(server_name);
/* Check if IMPI(User-Name) + IMPU(Public-Identity) is associated */
bool matched = hss_cx_identity_is_associated(user_name, public_identity);
if (!matched) {
ogs_error("User-Name[%s] Public-Identity[%s] is not assocated",
user_name, public_identity);
result_code = OGS_DIAM_CX_ERROR_IDENTITIES_DONT_MATCH;
goto out;
}
/* Get the SIP-Auth-Data-Item AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(
qry, ogs_diam_cx_sip_auth_data_item, &sip_auth_data_item_avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(sip_auth_data_item_avp, &hdr);
ogs_assert(ret == 0);
/* Get the Authentication-Scheme AVP */
ret = fd_msg_search_avp(sip_auth_data_item_avp,
ogs_diam_cx_sip_authentication_scheme, &authentication_scheme_avp);
ogs_assert(ret == 0);
if (authentication_scheme_avp) {
ret = fd_msg_avp_hdr(authentication_scheme_avp, &hdr);
ogs_assert(ret == 0);
authentication_scheme = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(authentication_scheme);
}
/* IMS_AKA is only supported */
if (authentication_scheme &&
strcmp(authentication_scheme, OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA) != 0 &&
strcmp(authentication_scheme, OGS_DIAM_CX_AUTH_SCHEME_UNKNOWN) != 0) {
ogs_error("Authentication-Scheme[%s] is not supported",
authentication_scheme);
result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED;
goto out;
}
rv = hss_db_auth_info(imsi_bcd, &auth_info);
if (rv != OGS_OK) {
ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN;
goto out;
}
/* Overwrite Server-Name for IMPI(User-Name) + IMPU(Public-Identity) */
hss_cx_set_server_name(user_name, public_identity, server_name, true);
memset(zero, 0, sizeof(zero));
if (memcmp(auth_info.rand, zero, OGS_RAND_LEN) == 0) {
ogs_random(auth_info.rand, OGS_RAND_LEN);
}
if (auth_info.use_opc)
memcpy(opc, auth_info.opc, sizeof(opc));
else
milenage_opc(auth_info.k, auth_info.op, opc);
/* Get the SIP-Authorization AVP */
ret = fd_msg_search_avp(sip_auth_data_item_avp,
ogs_diam_cx_sip_authorization, &sip_authorization_avp);
ogs_assert(ret == 0);
if (sip_authorization_avp) {
ret = fd_msg_avp_hdr(sip_authorization_avp, &hdr);
ogs_assert(ret == 0);
ogs_auc_sqn(opc, auth_info.k,
hdr->avp_value->os.data,
hdr->avp_value->os.data + OGS_RAND_LEN,
sqn, mac_s);
if (memcmp(mac_s, hdr->avp_value->os.data +
OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) {
ogs_random(auth_info.rand, OGS_RAND_LEN);
auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN);
/* 33.102 C.3.4 Guide : IND + 1 */
auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN;
} else {
ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd);
ogs_log_print(OGS_LOG_ERROR, "MAC_S: ");
ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN);
ogs_log_hexdump(OGS_LOG_ERROR,
(void*)(hdr->avp_value->os.data +
OGS_RAND_LEN + OGS_SQN_LEN),
OGS_MAC_S_LEN);
ogs_log_print(OGS_LOG_ERROR, "SQN: ");
ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN);
result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED;
goto out;
}
}
rv = hss_db_update_sqn(imsi_bcd, auth_info.rand, auth_info.sqn);
if (rv != OGS_OK) {
ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE;
goto out;
}
rv = hss_db_increment_sqn(imsi_bcd);
if (rv != OGS_OK) {
ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE;
goto out;
}
#if 0 /* Test Vector for ipsec_reg.pcapng */
/*
* Ki : 8baf473f2f8fd09487cccbd7097c6862
* OP : 11111111111111111111111111111111
* OPc : 8E27B6AF0E692E750F32667A3B14605D
* open5gs SQN : 44254 (dec)
* Fhoss SQN : 00000000ad25 (hex)
* RAND : a0944c75ff3c4f0853a2f910aa1f104f
* AMF : c6e2f46c8f4280007f3bb9b84b7c3ff6
*
* New SQN : 000017242898 (hex)
*/
auth_info.sqn = 0x17242898;
#define RAND "a0944c75ff3c4f0853a2f910aa1f104f"
OGS_HEX(RAND, strlen(RAND), auth_info.rand);
#endif
milenage_generate(opc, auth_info.amf, auth_info.k,
ogs_uint64_to_buffer(auth_info.sqn, OGS_SQN_LEN, sqn), auth_info.rand,
autn, ik, ck, ak, xres, &xres_len);
memcpy(authenticate, auth_info.rand, OGS_RAND_LEN);
memcpy(authenticate + OGS_RAND_LEN, autn, OGS_AUTN_LEN);
ogs_log_print(OGS_LOG_DEBUG, "K - ");
ogs_log_hexdump(OGS_LOG_DEBUG, auth_info.k, OGS_KEY_LEN);
ogs_log_print(OGS_LOG_DEBUG, "AMF - ");
ogs_log_hexdump(OGS_LOG_DEBUG, auth_info.amf, OGS_AMF_LEN);
ogs_log_print(OGS_LOG_DEBUG, "OPc - ");
ogs_log_hexdump(OGS_LOG_DEBUG, opc, OGS_KEY_LEN);
ogs_log_print(OGS_LOG_DEBUG, "RAND - ");
ogs_log_hexdump(OGS_LOG_DEBUG, auth_info.rand, OGS_RAND_LEN);
ogs_log_print(OGS_LOG_DEBUG, "SQN - ");
ogs_log_hexdump(OGS_LOG_DEBUG, sqn, OGS_SQN_LEN);
ogs_log_print(OGS_LOG_DEBUG, "AUTN - ");
ogs_log_hexdump(OGS_LOG_DEBUG, autn, OGS_KEY_LEN);
ogs_log_print(OGS_LOG_DEBUG, "ck - ");
ogs_log_hexdump(OGS_LOG_DEBUG, ck, OGS_KEY_LEN);
ogs_log_print(OGS_LOG_DEBUG, "ik - ");
ogs_log_hexdump(OGS_LOG_DEBUG, ik, OGS_KEY_LEN);
ogs_log_print(OGS_LOG_DEBUG, "ak - ");
ogs_log_hexdump(OGS_LOG_DEBUG, ak, OGS_KEY_LEN);
ogs_log_print(OGS_LOG_DEBUG, "xles - ");
ogs_log_hexdump(OGS_LOG_DEBUG, xres, xres_len);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)user_name;
val.os.len = strlen(user_name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Public-Identity AVP */
ret = fd_msg_avp_new(ogs_diam_cx_public_identity, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)public_identity;
val.os.len = strlen(public_identity);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the SIP-Number-Auth-Items AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp);
ogs_assert(ret == 0);
val.u32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the SIP-Auth-Data-Item AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp);
ogs_assert(ret == 0);
/* Set the SIP-Item-Number AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_item_number, 0, &avpch);
ogs_assert(ret == 0);
val.u32 = 1;
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
/* Set the SIP-Authentication-Scheme AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA;
val.os.len = strlen(OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA);
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
/* Set the SIP-Authenticatie AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_authenticate, 0, &avpch);
ogs_assert(ret == 0);
val.os.data = authenticate;
val.os.len = OGS_KEY_LEN * 2;
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
/* Set the SIP-Authorization AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch);
ogs_assert(ret == 0);
val.os.data = xres;
val.os.len = xres_len;
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
/* Set the Confidentiality-Key AVP */
ret = fd_msg_avp_new(ogs_diam_cx_confidentiality_key, 0, &avpch);
ogs_assert(ret == 0);
val.os.data = ck;
val.os.len = OGS_KEY_LEN;
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
/* Set the Integirty-Key AVP */
ret = fd_msg_avp_new(ogs_diam_cx_integrity_key, 0, &avpch);
ogs_assert(ret == 0);
val.os.data = ik;
val.os.len = OGS_KEY_LEN;
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("Multimedia-Auth-Answer");
/* Add this value to the stats */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
if (authentication_scheme)
ogs_free(authentication_scheme);
ogs_free(user_name);
ogs_free(public_identity);
ogs_free(server_name);
return 0;
out:
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
if (authentication_scheme)
ogs_free(authentication_scheme);
ogs_free(user_name);
ogs_free(public_identity);
ogs_free(server_name);
return 0;
}
/* Callback for incoming Server-Assignment-Request messages */
static int hss_ogs_diam_cx_sar_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int rv, ret;
uint32_t result_code = 0;
struct msg *ans, *qry;
struct avp *avpch = NULL;
struct avp_hdr *hdr;
union avp_value val;
char *user_name = NULL;
char *public_identity = NULL;
char *server_name = NULL;
char *user_data = NULL;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
char msisdn_bcd[OGS_MAX_MSISDN_BCD_LEN+1];
ogs_subscription_data_t subscription_data;
ogs_assert(msg);
ogs_debug("Server-Assignment-Request");
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
/* Get User-Name AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
user_name = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(user_name);
ogs_extract_digit_from_string(imsi_bcd, user_name);
/* Get Public-Identity AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
public_identity = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(public_identity);
ogs_extract_digit_from_string(msisdn_bcd, public_identity);
memset(&subscription_data, 0, sizeof(ogs_subscription_data_t));
rv = hss_db_subscription_data(imsi_bcd, &subscription_data);
if (rv != OGS_OK) {
ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN;
goto out;
}
/* Get Server-Name AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_cx_server_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
server_name = ogs_strndup(
(char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
ogs_assert(server_name);
/* Check if IMPI(User-Name) + IMPU(Public-Identity) is associated */
bool matched = hss_cx_identity_is_associated(user_name, public_identity);
if (!matched) {
ogs_error("User-Name[%s] Public-Identity[%s] is not assocated",
user_name, public_identity);
result_code = OGS_DIAM_CX_ERROR_IDENTITIES_DONT_MATCH;
goto out;
}
/* Overwrite Server-Name for IMPI(User-Name) + IMPU(Public-Identity) */
hss_cx_set_server_name(user_name, public_identity, server_name, true);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)user_name;
val.os.len = strlen(user_name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Get User-Data-Already-Available AVP (Mandatory has already been checked) */
ret = fd_msg_search_avp(qry, ogs_diam_cx_user_data_already_available, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
if (hdr->avp_value->i32 == OGS_DIAM_CX_USER_DATA_ALREADY_AVAILABLE) {
/* Nothing to do */
} else {
/* Set the User-Data AVP */
user_data = download_user_data(user_name, &subscription_data);
ogs_assert(user_data);
ret = fd_msg_avp_new(ogs_diam_cx_user_data, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)user_data;
val.os.len = strlen(user_data);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Charging-Information AVP */
ret = fd_msg_avp_new(ogs_diam_cx_charging_information, 0, &avp);
ogs_assert(ret == 0);
/* Set the Charging-Information AVP */
ret = fd_msg_avp_new(ogs_diam_cx_charging_information, 0, &avp);
ogs_assert(ret == 0);
/* Set the Primary-Charging-Collection-Function-Name AVP */
ret = fd_msg_avp_new(
ogs_diam_cx_primary_charging_collection_function_name, 0,
&avpch);
ogs_assert(ret == 0);
#define PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME "pcrf"
val.os.data = (uint8_t *)PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME;
val.os.len = strlen(PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME);
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
}
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("Server-Assignment-Answer");
/* Add this value to the stats */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_subscription_data_free(&subscription_data);
if (user_data)
ogs_free(user_data);
ogs_free(user_name);
ogs_free(public_identity);
ogs_free(server_name);
return 0;
out:
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_subscription_data_free(&subscription_data);
if (user_data)
ogs_free(user_data);
ogs_free(user_name);
ogs_free(public_identity);
ogs_free(server_name);
return 0;
}
static char *download_user_data(
char *user_name, ogs_subscription_data_t *subscription_data)
{
char *user_data = NULL;
int i;
ogs_assert(user_name);
ogs_assert(subscription_data);
user_data = ogs_strdup(ogs_diam_cx_xml_version);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_ims_subscription_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s%s%s",
ogs_diam_cx_xml_private_id_s,
user_name,
ogs_diam_cx_xml_private_id_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_service_profile_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_public_id_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s%s%s",
ogs_diam_cx_xml_barring_indication_s,
"1",
ogs_diam_cx_xml_barring_indication_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%ssip:%s%s",
ogs_diam_cx_xml_identity_s,
user_name,
ogs_diam_cx_xml_identity_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_extension_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s%s%s",
ogs_diam_cx_xml_identity_type_s,
"0",
ogs_diam_cx_xml_identity_type_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_extension_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_public_id_e);
ogs_assert(user_data);
for (i = 0; i < subscription_data->num_of_msisdn; i++) {
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_public_id_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%stel:%s%s",
ogs_diam_cx_xml_identity_s,
subscription_data->msisdn[i].bcd,
ogs_diam_cx_xml_identity_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_extension_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s%s%s",
ogs_diam_cx_xml_identity_type_s,
"0",
ogs_diam_cx_xml_identity_type_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_extension_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_public_id_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_public_id_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%ssip:%s%s",
ogs_diam_cx_xml_identity_s,
subscription_data->msisdn[i].bcd,
ogs_diam_cx_xml_identity_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_extension_s);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s%s%s",
ogs_diam_cx_xml_identity_type_s,
"0",
ogs_diam_cx_xml_identity_type_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_extension_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_public_id_e);
ogs_assert(user_data);
}
user_data = ogs_mstrcatf(user_data, "%s",
ogs_diam_cx_xml_service_profile_e);
ogs_assert(user_data);
user_data = ogs_mstrcatf(user_data,
"%s", ogs_diam_cx_xml_ims_subscription_e);
ogs_assert(user_data);
return user_data;
}
int hss_cx_init(void)
{
int ret;
struct disp_when data;
/* Install objects definitions for this application */
ret = ogs_diam_cx_init();
ogs_assert(ret == 0);
memset(&data, 0, sizeof(data));
data.app = ogs_diam_cx_application;
/* Fallback CB if command != unexpected message received */
ret = fd_disp_register(hss_ogs_diam_cx_fb_cb, DISP_HOW_APPID,
&data, NULL, &hdl_cx_fb);
ogs_assert(ret == 0);
/* Specific handler for User-Authorization-Request */
data.command = ogs_diam_cx_cmd_uar;
ret = fd_disp_register(hss_ogs_diam_cx_uar_cb, DISP_HOW_CC, &data, NULL,
&hdl_cx_uar);
ogs_assert(ret == 0);
/* Specific handler for Multimedia-Auth-Request */
data.command = ogs_diam_cx_cmd_mar;
ret = fd_disp_register(hss_ogs_diam_cx_mar_cb, DISP_HOW_CC, &data, NULL,
&hdl_cx_mar);
ogs_assert(ret == 0);
/* Specific handler for Server-Assignment-Request */
data.command = ogs_diam_cx_cmd_sar;
ret = fd_disp_register(hss_ogs_diam_cx_sar_cb, DISP_HOW_CC, &data, NULL,
&hdl_cx_sar);
ogs_assert(ret == 0);
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_cx_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == 0);
return OGS_OK;
}
void hss_cx_final(void)
{
if (hdl_cx_fb)
(void) fd_disp_unregister(&hdl_cx_fb, NULL);
if (hdl_cx_uar)
(void) fd_disp_unregister(&hdl_cx_uar, NULL);
if (hdl_cx_mar)
(void) fd_disp_unregister(&hdl_cx_mar, NULL);
if (hdl_cx_sar)
(void) fd_disp_unregister(&hdl_cx_sar, NULL);
}

View File

@ -22,833 +22,26 @@
#include "hss-context.h"
#include "hss-fd-path.h"
/* handler for fallback cb */
static struct disp_hdl *hdl_s6a_fb = NULL;
/* handler for Authentication-Information-Request cb */
static struct disp_hdl *hdl_s6a_air = NULL;
/* handler for Update-Location-Request cb */
static struct disp_hdl *hdl_s6a_ulr = NULL;
/* Default callback for the application. */
static int hss_ogs_diam_s6a_fb_cb(struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
/* This CB should never be called */
ogs_warn("Unexpected message received!");
return ENOTSUP;
}
/* Callback for incoming Authentication-Information-Request messages */
static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int ret;
struct msg *ans, *qry;
struct avp *avpch;
struct avp *avp_e_utran_vector, *avp_xres, *avp_kasme, *avp_rand, *avp_autn;
struct avp_hdr *hdr;
union avp_value val;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
uint8_t opc[OGS_KEY_LEN];
uint8_t sqn[OGS_SQN_LEN];
uint8_t autn[OGS_AUTN_LEN];
uint8_t ik[OGS_KEY_LEN];
uint8_t ck[OGS_KEY_LEN];
uint8_t ak[OGS_AK_LEN];
uint8_t xres[OGS_MAX_RES_LEN];
uint8_t kasme[OGS_SHA256_DIGEST_SIZE];
size_t xres_len = 8;
uint8_t mac_s[OGS_MAC_S_LEN];
ogs_dbi_auth_info_t auth_info;
uint8_t zero[OGS_RAND_LEN];
int rv;
uint32_t result_code = 0;
ogs_assert(msg);
ogs_debug("[HSS] Authentication-Information-Request\n");
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data,
ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1);
rv = hss_db_auth_info(imsi_bcd, &auth_info);
if (rv != OGS_OK) {
result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN;
goto out;
}
memset(zero, 0, sizeof(zero));
if (memcmp(auth_info.rand, zero, OGS_RAND_LEN) == 0) {
ogs_random(auth_info.rand, OGS_RAND_LEN);
}
if (auth_info.use_opc)
memcpy(opc, auth_info.opc, sizeof(opc));
else
milenage_opc(auth_info.k, auth_info.op, opc);
ret = fd_msg_search_avp(qry, ogs_diam_s6a_req_eutran_auth_info, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_avp_search_avp(
avp, ogs_diam_s6a_re_synchronization_info, &avpch);
ogs_assert(ret == 0);
if (avpch) {
ret = fd_msg_avp_hdr(avpch, &hdr);
ogs_assert(ret == 0);
ogs_auc_sqn(opc, auth_info.k,
hdr->avp_value->os.data,
hdr->avp_value->os.data + OGS_RAND_LEN,
sqn, mac_s);
if (memcmp(mac_s, hdr->avp_value->os.data +
OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) {
ogs_random(auth_info.rand, OGS_RAND_LEN);
auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN);
/* 33.102 C.3.4 Guide : IND + 1 */
auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN;
} else {
ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd);
ogs_log_print(OGS_LOG_ERROR, "MAC_S: ");
ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN);
ogs_log_hexdump(OGS_LOG_ERROR,
(void*)(hdr->avp_value->os.data +
OGS_RAND_LEN + OGS_SQN_LEN),
OGS_MAC_S_LEN);
ogs_log_print(OGS_LOG_ERROR, "SQN: ");
ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN);
result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE;
goto out;
}
}
}
rv = hss_db_update_rand_and_sqn(imsi_bcd, auth_info.rand, auth_info.sqn);
if (rv != OGS_OK) {
ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE;
goto out;
}
rv = hss_db_increment_sqn(imsi_bcd);
if (rv != OGS_OK) {
ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE;
goto out;
}
ret = fd_msg_search_avp(qry, ogs_diam_s6a_visited_plmn_id, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
#if 0 // TODO : check visited_plmn_id
memcpy(visited_plmn_id, hdr->avp_value->os.data, hdr->avp_value->os.len);
#endif
milenage_generate(opc, auth_info.amf, auth_info.k,
ogs_uint64_to_buffer(auth_info.sqn, OGS_SQN_LEN, sqn), auth_info.rand,
autn, ik, ck, ak, xres, &xres_len);
ogs_auc_kasme(ck, ik, hdr->avp_value->os.data, sqn, ak, kasme);
/* Set the Authentication-Info */
ret = fd_msg_avp_new(ogs_diam_s6a_authentication_info, 0, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_e_utran_vector, 0, &avp_e_utran_vector);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_rand, 0, &avp_rand);
ogs_assert(ret == 0);
val.os.data = auth_info.rand;
val.os.len = OGS_KEY_LEN;
ret = fd_msg_avp_setvalue(avp_rand, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_rand);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_xres, 0, &avp_xres);
ogs_assert(ret == 0);
val.os.data = xres;
val.os.len = xres_len;
ret = fd_msg_avp_setvalue(avp_xres, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_xres);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_autn, 0, &avp_autn);
ogs_assert(ret == 0);
val.os.data = autn;
val.os.len = OGS_AUTN_LEN;
ret = fd_msg_avp_setvalue(avp_autn, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_autn);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_kasme, 0, &avp_kasme);
ogs_assert(ret == 0);
val.os.data = kasme;
val.os.len = OGS_SHA256_DIGEST_SIZE;
ret = fd_msg_avp_setvalue(avp_kasme, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_kasme);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_e_utran_vector);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("[HSS] Authentication-Information-Answer\n");
/* Add this value to the stats */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
return 0;
out:
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
return 0;
}
/* Callback for incoming Update-Location-Request messages */
static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int ret;
struct msg *ans, *qry;
struct avp_hdr *hdr;
union avp_value val;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
ogs_s_nssai_t s_nssai;
int rv;
uint32_t result_code = 0;
ogs_subscription_data_t subscription_data;
ogs_slice_data_t *slice_data = NULL;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
ogs_assert(msg);
ogs_debug("[HSS] Update-Location-Request\n");
memset(&subscription_data, 0, sizeof(ogs_subscription_data_t));
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data,
ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1);
rv = hss_db_subscription_data(imsi_bcd, &subscription_data);
if (rv != OGS_OK) {
ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN;
goto out;
}
ret = fd_msg_search_avp(qry, ogs_diam_s6a_visited_plmn_id, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
#if 0 // TODO : check visited_plmn_id
memcpy(visited_plmn_id, hdr->avp_value->os.data, hdr->avp_value->os.len);
#endif
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the ULA Flags */
ret = fd_msg_avp_new(ogs_diam_s6a_ula_flags, 0, &avp);
ogs_assert(ret == 0);
val.i32 = OGS_DIAM_S6A_ULA_FLAGS_MME_REGISTERED_FOR_SMS;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = fd_msg_search_avp(qry, ogs_diam_s6a_ulr_flags, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
if (!(hdr->avp_value->u32 & OGS_DIAM_S6A_ULR_SKIP_SUBSCRIBER_DATA)) {
struct avp *avp_msisdn, *avp_a_msisdn;
struct avp *avp_access_restriction_data;
struct avp *avp_subscriber_status, *avp_network_access_mode;
struct avp *avp_ambr, *avp_max_bandwidth_ul, *avp_max_bandwidth_dl;
struct avp *avp_rau_tau_timer;
/* Set the APN Configuration Profile */
struct avp *apn_configuration_profile;
struct avp *context_identifier;
struct avp *all_apn_configuration_included_indicator;
int i;
/* Set the Subscription Data */
ret = fd_msg_avp_new(ogs_diam_s6a_subscription_data, 0, &avp);
ogs_assert(ret == 0);
/*
* TS29.328
* 6.3.2 MSISDN AVP
*
* The MSISDN AVP is of type OctetString.
* This AVP contains an MSISDN, in international number format
* as described in ITU-T Rec E.164 [8], encoded as a TBCD-string,
* i.e. digits from 0 through 9 are encoded 0000 to 1001;
* 1111 is used as a filler when there is an odd number of digits;
* bits 8 to 5 of octet n encode digit 2n;
* bits 4 to 1 of octet n encode digit 2(n-1)+1.
*/
if (subscription_data.num_of_msisdn >= 1) {
ret = fd_msg_avp_new(ogs_diam_s6a_msisdn, 0, &avp_msisdn);
ogs_assert(ret == 0);
val.os.data = subscription_data.msisdn[0].buf;
val.os.len = subscription_data.msisdn[0].len;
ret = fd_msg_avp_setvalue(avp_msisdn, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_msisdn);
ogs_assert(ret == 0);
}
if (subscription_data.num_of_msisdn >= 2) {
ret = fd_msg_avp_new(ogs_diam_s6a_a_msisdn, 0, &avp_a_msisdn);
ogs_assert(ret == 0);
val.os.data = subscription_data.msisdn[1].buf;
val.os.len = subscription_data.msisdn[1].len;
ret = fd_msg_avp_setvalue(avp_a_msisdn, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_a_msisdn);
ogs_assert(ret == 0);
}
if (subscription_data.access_restriction_data) {
ret = fd_msg_avp_new(ogs_diam_s6a_access_restriction_data, 0,
&avp_access_restriction_data);
ogs_assert(ret == 0);
val.i32 = subscription_data.access_restriction_data;
ret = fd_msg_avp_setvalue( avp_access_restriction_data, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
avp_access_restriction_data);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_new(
ogs_diam_s6a_subscriber_status, 0, &avp_subscriber_status);
ogs_assert(ret == 0);
val.i32 = subscription_data.subscriber_status;
ret = fd_msg_avp_setvalue(avp_subscriber_status, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_subscriber_status);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_network_access_mode, 0,
&avp_network_access_mode);
ogs_assert(ret == 0);
val.i32 = subscription_data.network_access_mode;
ret = fd_msg_avp_setvalue(avp_network_access_mode, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_network_access_mode);
ogs_assert(ret == 0);
/* Set the AMBR */
ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_max_bandwidth_ul, 0, &avp_max_bandwidth_ul);
ogs_assert(ret == 0);
val.u32 = subscription_data.ambr.uplink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(
avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_ul);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_max_bandwidth_dl, 0, &avp_max_bandwidth_dl);
ogs_assert(ret == 0);
val.u32 = subscription_data.ambr.downlink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(
avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_dl);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_ambr);
ogs_assert(ret == 0);
/* Set the Subscribed RAU TAU Timer */
ret = fd_msg_avp_new(
ogs_diam_s6a_subscribed_rau_tau_timer, 0, &avp_rau_tau_timer);
ogs_assert(ret == 0);
val.i32 = subscription_data.subscribed_rau_tau_timer * 60; /* seconds */
ret = fd_msg_avp_setvalue(avp_rau_tau_timer, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_rau_tau_timer);
ogs_assert(ret == 0);
/* For EPC, we'll use SST:1 */
s_nssai.sst = 1;
s_nssai.sd.v = OGS_S_NSSAI_NO_SD_VALUE;
slice_data = ogs_slice_find_by_s_nssai(
subscription_data.slice, subscription_data.num_of_slice,
&s_nssai);
if (!slice_data) {
ogs_error("[%s] Cannot find S-NSSAI", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION;
goto out;
}
if (!slice_data->num_of_session) {
ogs_error("[%s] No PDN", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION;
goto out;
}
ret = fd_msg_avp_new(ogs_diam_s6a_apn_configuration_profile, 0,
&apn_configuration_profile);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0,
&context_identifier);
ogs_assert(ret == 0);
val.i32 = 1; /* Context Identifier : 1 */
ret = fd_msg_avp_setvalue(context_identifier, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration_profile,
MSG_BRW_LAST_CHILD, context_identifier);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_all_apn_configuration_included_indicator, 0,
&all_apn_configuration_included_indicator);
ogs_assert(ret == 0);
val.i32 = 0;
ret = fd_msg_avp_setvalue(
all_apn_configuration_included_indicator, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration_profile, MSG_BRW_LAST_CHILD,
all_apn_configuration_included_indicator);
ogs_assert(ret == 0);
for (i = 0; i < slice_data->num_of_session; i++) {
/* Set the APN Configuration */
struct avp *apn_configuration, *context_identifier, *pdn_type;
struct avp *served_party_ip_address, *service_selection;
struct avp *eps_subscribed_qos_profile, *qos_class_identifier;
struct avp *allocation_retention_priority, *priority_level;
struct avp *pre_emption_capability, *pre_emption_vulnerability;
struct avp *mip6_agent_info, *mip_home_agent_address;
ogs_session_t *session = &slice_data->session[i];
ogs_assert(session);
session->context_identifier = i+1;
ret = fd_msg_avp_new(ogs_diam_s6a_apn_configuration, 0,
&apn_configuration);
ogs_assert(ret == 0);
/* Set Context-Identifier */
ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0,
&context_identifier);
ogs_assert(ret == 0);
val.i32 = session->context_identifier;
ret = fd_msg_avp_setvalue(context_identifier, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, context_identifier);
ogs_assert(ret == 0);
/* Set PDN-Type */
ret = fd_msg_avp_new(ogs_diam_s6a_pdn_type, 0, &pdn_type);
ogs_assert(ret == 0);
val.i32 = OGS_PDU_SESSION_TYPE_TO_DIAMETER(session->session_type);
ret = fd_msg_avp_setvalue(pdn_type, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, pdn_type);
ogs_assert(ret == 0);
/* Set Served-Party-IP-Address */
if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV4 ||
session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) &&
session->ue_ip.ipv4) {
ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address,
0, &served_party_ip_address);
ogs_assert(ret == 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = session->ue_ip.addr;
ret = fd_msg_avp_value_encode(&sin, served_party_ip_address);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD,
served_party_ip_address);
ogs_assert(ret == 0);
}
if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV6 ||
session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) &&
session->ue_ip.ipv6) {
ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address,
0, &served_party_ip_address);
ogs_assert(ret == 0);
sin6.sin6_family = AF_INET6;
memcpy(sin6.sin6_addr.s6_addr,
session->ue_ip.addr6, OGS_IPV6_LEN);
ret = fd_msg_avp_value_encode(&sin6, served_party_ip_address);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD,
served_party_ip_address);
ogs_assert(ret == 0);
}
/* Set Service-Selection */
ret = fd_msg_avp_new(ogs_diam_s6a_service_selection, 0,
&service_selection);
ogs_assert(ret == 0);
ogs_assert(session->name);
val.os.data = (uint8_t *)session->name;
val.os.len = strlen(session->name);
ret = fd_msg_avp_setvalue(service_selection, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, service_selection);
ogs_assert(ret == 0);
/* Set the EPS Subscribed QoS Profile */
ret = fd_msg_avp_new(ogs_diam_s6a_eps_subscribed_qos_profile, 0,
&eps_subscribed_qos_profile);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_qos_class_identifier, 0,
&qos_class_identifier);
ogs_assert(ret == 0);
val.i32 = session->qos.index;
ret = fd_msg_avp_setvalue(qos_class_identifier, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(eps_subscribed_qos_profile,
MSG_BRW_LAST_CHILD, qos_class_identifier);
ogs_assert(ret == 0);
/* Set Allocation retention priority */
ret = fd_msg_avp_new(ogs_diam_s6a_allocation_retention_priority, 0,
&allocation_retention_priority);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_priority_level, 0, &priority_level);
ogs_assert(ret == 0);
val.u32 = session->qos.arp.priority_level;
ret = fd_msg_avp_setvalue(priority_level, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(allocation_retention_priority,
MSG_BRW_LAST_CHILD, priority_level);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_capability, 0,
&pre_emption_capability);
ogs_assert(ret == 0);
val.u32 = OGS_EPC_PRE_EMPTION_DISABLED;
if (session->qos.arp.pre_emption_capability ==
OGS_5GC_PRE_EMPTION_ENABLED)
val.u32 = OGS_EPC_PRE_EMPTION_ENABLED;
ret = fd_msg_avp_setvalue(pre_emption_capability, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(allocation_retention_priority,
MSG_BRW_LAST_CHILD, pre_emption_capability);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_vulnerability, 0,
&pre_emption_vulnerability);
ogs_assert(ret == 0);
val.u32 = OGS_EPC_PRE_EMPTION_DISABLED;
if (session->qos.arp.pre_emption_vulnerability ==
OGS_5GC_PRE_EMPTION_ENABLED)
val.u32 = OGS_EPC_PRE_EMPTION_ENABLED;
ret = fd_msg_avp_setvalue(pre_emption_vulnerability, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(allocation_retention_priority,
MSG_BRW_LAST_CHILD, pre_emption_vulnerability);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(eps_subscribed_qos_profile,
MSG_BRW_LAST_CHILD, allocation_retention_priority);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile);
ogs_assert(ret == 0);
/* Set MIP6-Agent-Info */
if (session->smf_ip.ipv4 || session->smf_ip.ipv6) {
ret = fd_msg_avp_new(ogs_diam_mip6_agent_info, 0,
&mip6_agent_info);
ogs_assert(ret == 0);
if (session->smf_ip.ipv4) {
ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0,
&mip_home_agent_address);
ogs_assert(ret == 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = session->smf_ip.addr;
ret = fd_msg_avp_value_encode (
&sin, mip_home_agent_address );
ogs_assert(ret == 0);
ret = fd_msg_avp_add(mip6_agent_info,
MSG_BRW_LAST_CHILD, mip_home_agent_address);
ogs_assert(ret == 0);
}
if (session->smf_ip.ipv6) {
ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0,
&mip_home_agent_address);
ogs_assert(ret == 0);
sin6.sin6_family = AF_INET6;
memcpy(sin6.sin6_addr.s6_addr, session->smf_ip.addr6,
sizeof session->smf_ip.addr6);
ret = fd_msg_avp_value_encode (
&sin6, mip_home_agent_address );
ogs_assert(ret == 0);
ret = fd_msg_avp_add(mip6_agent_info,
MSG_BRW_LAST_CHILD, mip_home_agent_address);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, mip6_agent_info);
ogs_assert(ret == 0);
}
/* Set AMBR */
if (session->ambr.downlink || session->ambr.uplink) {
ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_ul, 0,
&avp_max_bandwidth_ul);
ogs_assert(ret == 0);
val.u32 = session->ambr.uplink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
avp_max_bandwidth_ul);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_dl, 0,
&avp_max_bandwidth_dl);
ogs_assert(ret == 0);
val.u32 = session->ambr.downlink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
avp_max_bandwidth_dl);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, avp_ambr);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(apn_configuration_profile,
MSG_BRW_LAST_CHILD, apn_configuration);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
apn_configuration_profile);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
}
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("[HSS] Update-Location-Answer\n");
/* Add this value to the stats */
ogs_assert( pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert( pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_subscription_data_free(&subscription_data);
return 0;
out:
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_subscription_data_free(&subscription_data);
return 0;
}
int hss_fd_init(void)
{
int ret;
struct disp_when data;
struct dict_object *s6a_app, *vnd;
struct dict_vendor_data vnd_data;
struct dict_application_data s6a_app_data;
int rv;
ret = ogs_diam_init(FD_MODE_SERVER,
rv = ogs_diam_init(FD_MODE_SERVER,
hss_self()->diam_conf_path, hss_self()->diam_config);
ogs_assert(ret == 0);
ogs_assert(rv == 0);
vnd_data.vendor_id = 10415;
vnd_data.vendor_name = (char *) "3GPP";
ret = fd_dict_new(fd_g_config->cnf_dict,
DICT_VENDOR, &vnd_data, NULL, &vnd);
ogs_assert(ret == 0);
s6a_app_data.application_id = 16777251;
s6a_app_data.application_name = (char *) "S6A";
ret = fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION,
&s6a_app_data, NULL, &s6a_app);
ogs_assert(ret == 0);
ret = fd_disp_app_support(s6a_app, vnd, 1, 0);
ogs_assert(ret == 0);
/* Install objects definitions for this application */
ret = ogs_diam_s6a_init();
ogs_assert(ret == 0);
memset(&data, 0, sizeof(data));
data.app = ogs_diam_s6a_application;
/* Fallback CB if command != unexpected message received */
ret = fd_disp_register(hss_ogs_diam_s6a_fb_cb, DISP_HOW_APPID, &data, NULL,
&hdl_s6a_fb);
ogs_assert(ret == 0);
/* Specific handler for Authentication-Information-Request */
data.command = ogs_diam_s6a_cmd_air;
ret = fd_disp_register(hss_ogs_diam_s6a_air_cb, DISP_HOW_CC, &data, NULL,
&hdl_s6a_air);
ogs_assert(ret == 0);
/* Specific handler for Location-Update-Request */
data.command = ogs_diam_s6a_cmd_ulr;
ret = fd_disp_register(hss_ogs_diam_s6a_ulr_cb, DISP_HOW_CC, &data, NULL,
&hdl_s6a_ulr);
ogs_assert(ret == 0);
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_s6a_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == 0);
rv = hss_s6a_init();
ogs_assert(rv == OGS_OK);
rv = hss_cx_init();
ogs_assert(rv == OGS_OK);
return OGS_OK;
}
void hss_fd_final(void)
{
if (hdl_s6a_fb)
(void) fd_disp_unregister(&hdl_s6a_fb, NULL);
if (hdl_s6a_air)
(void) fd_disp_unregister(&hdl_s6a_air, NULL);
if (hdl_s6a_ulr)
(void) fd_disp_unregister(&hdl_s6a_ulr, NULL);
hss_s6a_final();
hss_cx_final();
ogs_diam_final();
}

View File

@ -27,6 +27,11 @@ extern "C" {
int hss_fd_init(void);
void hss_fd_final(void);
int hss_s6a_init(void);
void hss_s6a_final(void);
int hss_cx_init(void);
void hss_cx_final(void);
#ifdef __cplusplus
}
#endif

828
src/hss/hss-s6a-path.c Normal file
View File

@ -0,0 +1,828 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-crypt.h"
#include "hss-context.h"
#include "hss-fd-path.h"
/* handler for fallback cb */
static struct disp_hdl *hdl_s6a_fb = NULL;
/* handler for Authentication-Information-Request cb */
static struct disp_hdl *hdl_s6a_air = NULL;
/* handler for Update-Location-Request cb */
static struct disp_hdl *hdl_s6a_ulr = NULL;
/* Default callback for the application. */
static int hss_ogs_diam_s6a_fb_cb(struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
/* This CB should never be called */
ogs_warn("Unexpected message received!");
return ENOTSUP;
}
/* Callback for incoming Authentication-Information-Request messages */
static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int ret;
struct msg *ans, *qry;
struct avp *avpch;
struct avp *avp_e_utran_vector, *avp_xres, *avp_kasme, *avp_rand, *avp_autn;
struct avp_hdr *hdr;
union avp_value val;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
uint8_t opc[OGS_KEY_LEN];
uint8_t sqn[OGS_SQN_LEN];
uint8_t autn[OGS_AUTN_LEN];
uint8_t ik[OGS_KEY_LEN];
uint8_t ck[OGS_KEY_LEN];
uint8_t ak[OGS_AK_LEN];
uint8_t xres[OGS_MAX_RES_LEN];
uint8_t kasme[OGS_SHA256_DIGEST_SIZE];
size_t xres_len = 8;
uint8_t mac_s[OGS_MAC_S_LEN];
ogs_dbi_auth_info_t auth_info;
uint8_t zero[OGS_RAND_LEN];
int rv;
uint32_t result_code = 0;
ogs_assert(msg);
ogs_debug("Authentication-Information-Request");
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data,
ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1);
rv = hss_db_auth_info(imsi_bcd, &auth_info);
if (rv != OGS_OK) {
result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN;
goto out;
}
memset(zero, 0, sizeof(zero));
if (memcmp(auth_info.rand, zero, OGS_RAND_LEN) == 0) {
ogs_random(auth_info.rand, OGS_RAND_LEN);
}
if (auth_info.use_opc)
memcpy(opc, auth_info.opc, sizeof(opc));
else
milenage_opc(auth_info.k, auth_info.op, opc);
ret = fd_msg_search_avp(qry, ogs_diam_s6a_req_eutran_auth_info, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_avp_search_avp(
avp, ogs_diam_s6a_re_synchronization_info, &avpch);
ogs_assert(ret == 0);
if (avpch) {
ret = fd_msg_avp_hdr(avpch, &hdr);
ogs_assert(ret == 0);
ogs_auc_sqn(opc, auth_info.k,
hdr->avp_value->os.data,
hdr->avp_value->os.data + OGS_RAND_LEN,
sqn, mac_s);
if (memcmp(mac_s, hdr->avp_value->os.data +
OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) {
ogs_random(auth_info.rand, OGS_RAND_LEN);
auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN);
/* 33.102 C.3.4 Guide : IND + 1 */
auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN;
} else {
ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd);
ogs_log_print(OGS_LOG_ERROR, "MAC_S: ");
ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN);
ogs_log_hexdump(OGS_LOG_ERROR,
(void*)(hdr->avp_value->os.data +
OGS_RAND_LEN + OGS_SQN_LEN),
OGS_MAC_S_LEN);
ogs_log_print(OGS_LOG_ERROR, "SQN: ");
ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN);
result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE;
goto out;
}
}
}
rv = hss_db_update_sqn(imsi_bcd, auth_info.rand, auth_info.sqn);
if (rv != OGS_OK) {
ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE;
goto out;
}
rv = hss_db_increment_sqn(imsi_bcd);
if (rv != OGS_OK) {
ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE;
goto out;
}
ret = fd_msg_search_avp(qry, ogs_diam_s6a_visited_plmn_id, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
#if 0 // TODO : check visited_plmn_id
memcpy(visited_plmn_id, hdr->avp_value->os.data, hdr->avp_value->os.len);
#endif
milenage_generate(opc, auth_info.amf, auth_info.k,
ogs_uint64_to_buffer(auth_info.sqn, OGS_SQN_LEN, sqn), auth_info.rand,
autn, ik, ck, ak, xres, &xres_len);
ogs_auc_kasme(ck, ik, hdr->avp_value->os.data, sqn, ak, kasme);
/* Set the Authentication-Info */
ret = fd_msg_avp_new(ogs_diam_s6a_authentication_info, 0, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_e_utran_vector, 0, &avp_e_utran_vector);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_rand, 0, &avp_rand);
ogs_assert(ret == 0);
val.os.data = auth_info.rand;
val.os.len = OGS_KEY_LEN;
ret = fd_msg_avp_setvalue(avp_rand, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_rand);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_xres, 0, &avp_xres);
ogs_assert(ret == 0);
val.os.data = xres;
val.os.len = xres_len;
ret = fd_msg_avp_setvalue(avp_xres, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_xres);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_autn, 0, &avp_autn);
ogs_assert(ret == 0);
val.os.data = autn;
val.os.len = OGS_AUTN_LEN;
ret = fd_msg_avp_setvalue(avp_autn, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_autn);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_kasme, 0, &avp_kasme);
ogs_assert(ret == 0);
val.os.data = kasme;
val.os.len = OGS_SHA256_DIGEST_SIZE;
ret = fd_msg_avp_setvalue(avp_kasme, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_kasme);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_e_utran_vector);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("Authentication-Information-Answer");
/* Add this value to the stats */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
return 0;
out:
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
return 0;
}
/* Callback for incoming Update-Location-Request messages */
static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int ret;
struct msg *ans, *qry;
struct avp_hdr *hdr;
union avp_value val;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
ogs_s_nssai_t s_nssai;
int rv;
uint32_t result_code = 0;
ogs_subscription_data_t subscription_data;
ogs_slice_data_t *slice_data = NULL;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
ogs_assert(msg);
ogs_debug("Update-Location-Request");
memset(&subscription_data, 0, sizeof(ogs_subscription_data_t));
/* Create answer header */
qry = *msg;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data,
ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1);
rv = hss_db_subscription_data(imsi_bcd, &subscription_data);
if (rv != OGS_OK) {
ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN;
goto out;
}
ret = fd_msg_search_avp(qry, ogs_diam_s6a_visited_plmn_id, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
#if 0 // TODO : check visited_plmn_id
memcpy(visited_plmn_id, hdr->avp_value->os.data, hdr->avp_value->os.len);
#endif
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the ULA Flags */
ret = fd_msg_avp_new(ogs_diam_s6a_ula_flags, 0, &avp);
ogs_assert(ret == 0);
val.i32 = OGS_DIAM_S6A_ULA_FLAGS_MME_REGISTERED_FOR_SMS;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = fd_msg_search_avp(qry, ogs_diam_s6a_ulr_flags, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
if (!(hdr->avp_value->u32 & OGS_DIAM_S6A_ULR_SKIP_SUBSCRIBER_DATA)) {
struct avp *avp_msisdn, *avp_a_msisdn;
struct avp *avp_access_restriction_data;
struct avp *avp_subscriber_status, *avp_network_access_mode;
struct avp *avp_ambr, *avp_max_bandwidth_ul, *avp_max_bandwidth_dl;
struct avp *avp_rau_tau_timer;
/* Set the APN Configuration Profile */
struct avp *apn_configuration_profile;
struct avp *context_identifier;
struct avp *all_apn_configuration_included_indicator;
int i;
/* Set the Subscription Data */
ret = fd_msg_avp_new(ogs_diam_s6a_subscription_data, 0, &avp);
ogs_assert(ret == 0);
/*
* TS29.328
* 6.3.2 MSISDN AVP
*
* The MSISDN AVP is of type OctetString.
* This AVP contains an MSISDN, in international number format
* as described in ITU-T Rec E.164 [8], encoded as a TBCD-string,
* i.e. digits from 0 through 9 are encoded 0000 to 1001;
* 1111 is used as a filler when there is an odd number of digits;
* bits 8 to 5 of octet n encode digit 2n;
* bits 4 to 1 of octet n encode digit 2(n-1)+1.
*/
if (subscription_data.num_of_msisdn >= 1) {
ret = fd_msg_avp_new(ogs_diam_s6a_msisdn, 0, &avp_msisdn);
ogs_assert(ret == 0);
val.os.data = subscription_data.msisdn[0].buf;
val.os.len = subscription_data.msisdn[0].len;
ret = fd_msg_avp_setvalue(avp_msisdn, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_msisdn);
ogs_assert(ret == 0);
}
if (subscription_data.num_of_msisdn >= 2) {
ret = fd_msg_avp_new(ogs_diam_s6a_a_msisdn, 0, &avp_a_msisdn);
ogs_assert(ret == 0);
val.os.data = subscription_data.msisdn[1].buf;
val.os.len = subscription_data.msisdn[1].len;
ret = fd_msg_avp_setvalue(avp_a_msisdn, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_a_msisdn);
ogs_assert(ret == 0);
}
if (subscription_data.access_restriction_data) {
ret = fd_msg_avp_new(ogs_diam_s6a_access_restriction_data, 0,
&avp_access_restriction_data);
ogs_assert(ret == 0);
val.i32 = subscription_data.access_restriction_data;
ret = fd_msg_avp_setvalue( avp_access_restriction_data, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
avp_access_restriction_data);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_new(
ogs_diam_s6a_subscriber_status, 0, &avp_subscriber_status);
ogs_assert(ret == 0);
val.i32 = subscription_data.subscriber_status;
ret = fd_msg_avp_setvalue(avp_subscriber_status, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_subscriber_status);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_network_access_mode, 0,
&avp_network_access_mode);
ogs_assert(ret == 0);
val.i32 = subscription_data.network_access_mode;
ret = fd_msg_avp_setvalue(avp_network_access_mode, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_network_access_mode);
ogs_assert(ret == 0);
/* Set the AMBR */
ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_max_bandwidth_ul, 0, &avp_max_bandwidth_ul);
ogs_assert(ret == 0);
val.u32 = subscription_data.ambr.uplink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(
avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_ul);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_max_bandwidth_dl, 0, &avp_max_bandwidth_dl);
ogs_assert(ret == 0);
val.u32 = subscription_data.ambr.downlink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(
avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_dl);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_ambr);
ogs_assert(ret == 0);
/* Set the Subscribed RAU TAU Timer */
ret = fd_msg_avp_new(
ogs_diam_s6a_subscribed_rau_tau_timer, 0, &avp_rau_tau_timer);
ogs_assert(ret == 0);
val.i32 = subscription_data.subscribed_rau_tau_timer * 60; /* seconds */
ret = fd_msg_avp_setvalue(avp_rau_tau_timer, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_rau_tau_timer);
ogs_assert(ret == 0);
/* For EPC, we'll use SST:1 */
s_nssai.sst = 1;
s_nssai.sd.v = OGS_S_NSSAI_NO_SD_VALUE;
slice_data = ogs_slice_find_by_s_nssai(
subscription_data.slice, subscription_data.num_of_slice,
&s_nssai);
if (!slice_data) {
ogs_error("[%s] Cannot find S-NSSAI", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION;
goto out;
}
if (!slice_data->num_of_session) {
ogs_error("[%s] No PDN", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION;
goto out;
}
ret = fd_msg_avp_new(ogs_diam_s6a_apn_configuration_profile, 0,
&apn_configuration_profile);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0,
&context_identifier);
ogs_assert(ret == 0);
val.i32 = 1; /* Context Identifier : 1 */
ret = fd_msg_avp_setvalue(context_identifier, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration_profile,
MSG_BRW_LAST_CHILD, context_identifier);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_all_apn_configuration_included_indicator, 0,
&all_apn_configuration_included_indicator);
ogs_assert(ret == 0);
val.i32 = 0;
ret = fd_msg_avp_setvalue(
all_apn_configuration_included_indicator, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration_profile, MSG_BRW_LAST_CHILD,
all_apn_configuration_included_indicator);
ogs_assert(ret == 0);
for (i = 0; i < slice_data->num_of_session; i++) {
/* Set the APN Configuration */
struct avp *apn_configuration, *context_identifier, *pdn_type;
struct avp *served_party_ip_address, *service_selection;
struct avp *eps_subscribed_qos_profile, *qos_class_identifier;
struct avp *allocation_retention_priority, *priority_level;
struct avp *pre_emption_capability, *pre_emption_vulnerability;
struct avp *mip6_agent_info, *mip_home_agent_address;
ogs_session_t *session = &slice_data->session[i];
ogs_assert(session);
session->context_identifier = i+1;
ret = fd_msg_avp_new(ogs_diam_s6a_apn_configuration, 0,
&apn_configuration);
ogs_assert(ret == 0);
/* Set Context-Identifier */
ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0,
&context_identifier);
ogs_assert(ret == 0);
val.i32 = session->context_identifier;
ret = fd_msg_avp_setvalue(context_identifier, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, context_identifier);
ogs_assert(ret == 0);
/* Set PDN-Type */
ret = fd_msg_avp_new(ogs_diam_s6a_pdn_type, 0, &pdn_type);
ogs_assert(ret == 0);
val.i32 = OGS_PDU_SESSION_TYPE_TO_DIAMETER(session->session_type);
ret = fd_msg_avp_setvalue(pdn_type, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, pdn_type);
ogs_assert(ret == 0);
/* Set Served-Party-IP-Address */
if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV4 ||
session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) &&
session->ue_ip.ipv4) {
ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address,
0, &served_party_ip_address);
ogs_assert(ret == 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = session->ue_ip.addr;
ret = fd_msg_avp_value_encode(&sin, served_party_ip_address);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD,
served_party_ip_address);
ogs_assert(ret == 0);
}
if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV6 ||
session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) &&
session->ue_ip.ipv6) {
ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address,
0, &served_party_ip_address);
ogs_assert(ret == 0);
sin6.sin6_family = AF_INET6;
memcpy(sin6.sin6_addr.s6_addr,
session->ue_ip.addr6, OGS_IPV6_LEN);
ret = fd_msg_avp_value_encode(&sin6, served_party_ip_address);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD,
served_party_ip_address);
ogs_assert(ret == 0);
}
/* Set Service-Selection */
ret = fd_msg_avp_new(ogs_diam_s6a_service_selection, 0,
&service_selection);
ogs_assert(ret == 0);
ogs_assert(session->name);
val.os.data = (uint8_t *)session->name;
val.os.len = strlen(session->name);
ret = fd_msg_avp_setvalue(service_selection, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, service_selection);
ogs_assert(ret == 0);
/* Set the EPS Subscribed QoS Profile */
ret = fd_msg_avp_new(ogs_diam_s6a_eps_subscribed_qos_profile, 0,
&eps_subscribed_qos_profile);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_qos_class_identifier, 0,
&qos_class_identifier);
ogs_assert(ret == 0);
val.i32 = session->qos.index;
ret = fd_msg_avp_setvalue(qos_class_identifier, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(eps_subscribed_qos_profile,
MSG_BRW_LAST_CHILD, qos_class_identifier);
ogs_assert(ret == 0);
/* Set Allocation retention priority */
ret = fd_msg_avp_new(ogs_diam_s6a_allocation_retention_priority, 0,
&allocation_retention_priority);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(
ogs_diam_s6a_priority_level, 0, &priority_level);
ogs_assert(ret == 0);
val.u32 = session->qos.arp.priority_level;
ret = fd_msg_avp_setvalue(priority_level, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(allocation_retention_priority,
MSG_BRW_LAST_CHILD, priority_level);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_capability, 0,
&pre_emption_capability);
ogs_assert(ret == 0);
val.u32 = OGS_EPC_PRE_EMPTION_DISABLED;
if (session->qos.arp.pre_emption_capability ==
OGS_5GC_PRE_EMPTION_ENABLED)
val.u32 = OGS_EPC_PRE_EMPTION_ENABLED;
ret = fd_msg_avp_setvalue(pre_emption_capability, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(allocation_retention_priority,
MSG_BRW_LAST_CHILD, pre_emption_capability);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_vulnerability, 0,
&pre_emption_vulnerability);
ogs_assert(ret == 0);
val.u32 = OGS_EPC_PRE_EMPTION_DISABLED;
if (session->qos.arp.pre_emption_vulnerability ==
OGS_5GC_PRE_EMPTION_ENABLED)
val.u32 = OGS_EPC_PRE_EMPTION_ENABLED;
ret = fd_msg_avp_setvalue(pre_emption_vulnerability, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(allocation_retention_priority,
MSG_BRW_LAST_CHILD, pre_emption_vulnerability);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(eps_subscribed_qos_profile,
MSG_BRW_LAST_CHILD, allocation_retention_priority);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile);
ogs_assert(ret == 0);
/* Set MIP6-Agent-Info */
if (session->smf_ip.ipv4 || session->smf_ip.ipv6) {
ret = fd_msg_avp_new(ogs_diam_mip6_agent_info, 0,
&mip6_agent_info);
ogs_assert(ret == 0);
if (session->smf_ip.ipv4) {
ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0,
&mip_home_agent_address);
ogs_assert(ret == 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = session->smf_ip.addr;
ret = fd_msg_avp_value_encode (
&sin, mip_home_agent_address );
ogs_assert(ret == 0);
ret = fd_msg_avp_add(mip6_agent_info,
MSG_BRW_LAST_CHILD, mip_home_agent_address);
ogs_assert(ret == 0);
}
if (session->smf_ip.ipv6) {
ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0,
&mip_home_agent_address);
ogs_assert(ret == 0);
sin6.sin6_family = AF_INET6;
memcpy(sin6.sin6_addr.s6_addr, session->smf_ip.addr6,
sizeof session->smf_ip.addr6);
ret = fd_msg_avp_value_encode (
&sin6, mip_home_agent_address );
ogs_assert(ret == 0);
ret = fd_msg_avp_add(mip6_agent_info,
MSG_BRW_LAST_CHILD, mip_home_agent_address);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, mip6_agent_info);
ogs_assert(ret == 0);
}
/* Set AMBR */
if (session->ambr.downlink || session->ambr.uplink) {
ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_ul, 0,
&avp_max_bandwidth_ul);
ogs_assert(ret == 0);
val.u32 = session->ambr.uplink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
avp_max_bandwidth_ul);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_dl, 0,
&avp_max_bandwidth_dl);
ogs_assert(ret == 0);
val.u32 = session->ambr.downlink;
ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
avp_max_bandwidth_dl);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(apn_configuration,
MSG_BRW_LAST_CHILD, avp_ambr);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(apn_configuration_profile,
MSG_BRW_LAST_CHILD, apn_configuration);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
apn_configuration_profile);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
}
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("Update-Location-Answer");
/* Add this value to the stats */
ogs_assert( pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert( pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_subscription_data_free(&subscription_data);
return 0;
out:
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_subscription_data_free(&subscription_data);
return 0;
}
int hss_s6a_init(void)
{
int ret;
struct disp_when data;
/* Install objects definitions for this application */
ret = ogs_diam_s6a_init();
ogs_assert(ret == 0);
memset(&data, 0, sizeof(data));
data.app = ogs_diam_s6a_application;
/* Fallback CB if command != unexpected message received */
ret = fd_disp_register(hss_ogs_diam_s6a_fb_cb, DISP_HOW_APPID, &data, NULL,
&hdl_s6a_fb);
ogs_assert(ret == 0);
/* Specific handler for Authentication-Information-Request */
data.command = ogs_diam_s6a_cmd_air;
ret = fd_disp_register(hss_ogs_diam_s6a_air_cb, DISP_HOW_CC, &data, NULL,
&hdl_s6a_air);
ogs_assert(ret == 0);
/* Specific handler for Location-Update-Request */
data.command = ogs_diam_s6a_cmd_ulr;
ret = fd_disp_register(hss_ogs_diam_s6a_ulr_cb, DISP_HOW_CC, &data, NULL,
&hdl_s6a_ulr);
ogs_assert(ret == 0);
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_s6a_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == 0);
return OGS_OK;
}
void hss_s6a_final(void)
{
if (hdl_s6a_fb)
(void) fd_disp_unregister(&hdl_s6a_fb, NULL);
if (hdl_s6a_air)
(void) fd_disp_unregister(&hdl_s6a_air, NULL);
if (hdl_s6a_ulr)
(void) fd_disp_unregister(&hdl_s6a_ulr, NULL);
}

View File

@ -18,19 +18,24 @@
libhss_sources = files('''
hss-context.h
hss-fd-path.h
hss-init.c
hss-context.c
hss-s6a-path.c
hss-cx-path.c
hss-fd-path.c
'''.split())
libhss = static_library('hss',
sources : libhss_sources,
dependencies : [libapp_dep, libcrypt_dep, libdbi_dep, libdiameter_s6a_dep],
dependencies : [libapp_dep, libcrypt_dep, libdbi_dep,
libdiameter_s6a_dep, libdiameter_cx_dep],
install : false)
libhss_dep = declare_dependency(
link_with : libhss,
dependencies : [libapp_dep, libcrypt_dep, libdbi_dep, libdiameter_s6a_dep])
dependencies : [libapp_dep, libcrypt_dep, libdbi_dep,
libdiameter_s6a_dep, libdiameter_cx_dep])
hss_sources = files('''
app-init.c

View File

@ -58,17 +58,17 @@ void mme_s6a_send_air(mme_ue_t *mme_ue,
/* Clear Security Context */
CLEAR_SECURITY_CONTEXT(mme_ue);
/* Create the random value to store with the session */
sess_data = ogs_calloc(1, sizeof (*sess_data));
ogs_assert(sess_data);
sess_data->mme_ue = mme_ue;
/* Create the request */
ret = fd_msg_new(ogs_diam_s6a_cmd_air, MSGFL_ALLOC_ETEID, &req);
ogs_assert(ret == 0);
/* Create a new session */
#define OGS_DIAM_S6A_APP_SID_OPT "app_s6a"
ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_S6A_APP_SID_OPT,
@ -89,7 +89,7 @@ void mme_s6a_send_air(mme_ue_t *mme_ue,
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
@ -99,12 +99,12 @@ void mme_s6a_send_air(mme_ue_t *mme_ue,
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)mme_ue->imsi_bcd;
val.os.len = strlen(mme_ue->imsi_bcd);
val.os.len = strlen(mme_ue->imsi_bcd);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
@ -163,16 +163,16 @@ void mme_s6a_send_air(mme_ue_t *mme_ue,
ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts);
ogs_assert(ret == 0);
/* Keep a pointer to the session data for debug purpose,
/* Keep a pointer to the session data for debug purpose,
* in real life we would not need it */
svg = sess_data;
/* Store this value in the session */
ret = fd_sess_state_store(mme_s6a_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == 0);
/* Send the request */
ret = fd_msg_send(&req, mme_s6a_aia_cb, svg);
ogs_assert(ret == 0);
@ -455,15 +455,16 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue)
ogs_assert(mme_ue);
ogs_debug("[MME] Update-Location-Request");
/* Create the random value to store with the session */
sess_data = ogs_calloc(1, sizeof(*sess_data));
ogs_assert(sess_data);
sess_data->mme_ue = mme_ue;
/* Create the request */
ret = fd_msg_new(ogs_diam_s6a_cmd_ulr, MSGFL_ALLOC_ETEID, &req);
ogs_assert(ret == 0);
/* Create a new session */
#define OGS_DIAM_S6A_APP_SID_OPT "app_s6a"
ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_S6A_APP_SID_OPT,
@ -484,7 +485,7 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue)
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
@ -494,7 +495,7 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue)
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
@ -576,16 +577,16 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue)
ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts);
ogs_assert(ret == 0);
/* Keep a pointer to the session data for debug purpose,
/* Keep a pointer to the session data for debug purpose,
* in real life we would not need it */
svg = sess_data;
/* Store this value in the session */
ret = fd_sess_state_store(mme_s6a_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == 0);
/* Send the request */
ret = fd_msg_send(&req, mme_s6a_ula_cb, svg);
ogs_assert(ret == 0);
@ -1113,12 +1114,12 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
/* Free the message */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_logger_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg *
ogs_diam_logger_self()->stats.nb_recv + dur) /
ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg *
ogs_diam_logger_self()->stats.nb_recv + dur) /
(ogs_diam_logger_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_logger_self()->stats.shortest)
@ -1136,17 +1137,17 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
ogs_diam_logger_self()->stats.nb_recv++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
@ -1159,29 +1160,9 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
int mme_fd_init(void)
{
int ret;
struct dict_object *s6a_app, *vnd;
struct dict_vendor_data vnd_data;
struct dict_application_data s6a_app_data;
ret = ogs_diam_init(FD_MODE_CLIENT,
mme_self()->diam_conf_path, mme_self()->diam_config);
ogs_assert(ret == OGS_OK);
vnd_data.vendor_id = 10415;
vnd_data.vendor_name = (char *) "3GPP";
ret = fd_dict_new(fd_g_config->cnf_dict,
DICT_VENDOR, &vnd_data, NULL, &vnd);
ogs_assert(ret == 0);
s6a_app_data.application_id = 16777251;
s6a_app_data.application_name = (char *) "S6A";
ret = fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION,
&s6a_app_data, NULL, &s6a_app);
ogs_assert(ret == 0);
ret = fd_disp_app_support(s6a_app, vnd, 1, 0);
ogs_assert(ret == 0);
/* Install objects definitions for this application */
@ -1189,13 +1170,12 @@ int mme_fd_init(void)
ogs_assert(ret == OGS_OK);
/* Create handler for sessions */
ret = fd_sess_handler_create(&mme_s6a_reg, &state_cleanup,
NULL, NULL);
ogs_assert(ret == OGS_OK);
ret = fd_sess_handler_create(&mme_s6a_reg, &state_cleanup, NULL, NULL);
ogs_assert(ret == 0);
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_s6a_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == OGS_OK);
ogs_assert(ret == 0);
return 0;
}

View File

@ -289,7 +289,7 @@ int pcrf_db_qos_data(
return rv;
}
int pcrf_sess_set_ipv4(const void *key, uint8_t *sid)
void pcrf_sess_set_ipv4(const void *key, uint8_t *sid)
{
ogs_assert(self.ip_hash);
@ -298,10 +298,8 @@ int pcrf_sess_set_ipv4(const void *key, uint8_t *sid)
ogs_hash_set(self.ip_hash, key, OGS_IPV4_LEN, sid);
ogs_thread_mutex_unlock(&self.hash_lock);
return OGS_OK;
}
int pcrf_sess_set_ipv6(const void *key, uint8_t *sid)
void pcrf_sess_set_ipv6(const void *key, uint8_t *sid)
{
ogs_assert(self.ip_hash);
@ -310,8 +308,6 @@ int pcrf_sess_set_ipv6(const void *key, uint8_t *sid)
ogs_hash_set(self.ip_hash, key, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, sid);
ogs_thread_mutex_unlock(&self.hash_lock);
return OGS_OK;
}
uint8_t *pcrf_sess_find_by_ipv4(const void *key)

View File

@ -41,10 +41,10 @@ typedef struct pcrf_context_s {
const char *diam_conf_path; /* PCRF Diameter conf path */
ogs_diam_config_t *diam_config; /* PCRF Diameter config */
ogs_thread_mutex_t db_lock;
ogs_thread_mutex_t db_lock;
ogs_hash_t *ip_hash; /* hash table for Gx Frame IPv4/IPv6 */
ogs_thread_mutex_t hash_lock;
ogs_hash_t *ip_hash; /* hash table for Gx Frame IPv4/IPv6 */
ogs_thread_mutex_t hash_lock;
} pcrf_context_t;
void pcrf_context_init(void);
@ -56,8 +56,8 @@ int pcrf_context_parse_config(void);
int pcrf_db_qos_data(char *imsi_bcd, char *apn,
ogs_session_data_t *session_data);
int pcrf_sess_set_ipv4(const void *key, uint8_t *sid);
int pcrf_sess_set_ipv6(const void *key, uint8_t *sid);
void pcrf_sess_set_ipv4(const void *key, uint8_t *sid);
void pcrf_sess_set_ipv6(const void *key, uint8_t *sid);
uint8_t *pcrf_sess_find_by_ipv4(const void *key);
uint8_t *pcrf_sess_find_by_ipv6(const void *key);

View File

@ -22,39 +22,11 @@
int pcrf_fd_init(void)
{
int rv, ret;
struct dict_object *gx_app, *rx_app, *vnd;
struct dict_vendor_data vnd_data;
struct dict_application_data gx_app_data, rx_app_data;
int rv;
ret = ogs_diam_init(FD_MODE_CLIENT|FD_MODE_SERVER,
rv = ogs_diam_init(FD_MODE_CLIENT|FD_MODE_SERVER,
pcrf_self()->diam_conf_path, pcrf_self()->diam_config);
ogs_assert(ret == 0);
vnd_data.vendor_id = 10415;
vnd_data.vendor_name = (char *) "3GPP";
ret = fd_dict_new(fd_g_config->cnf_dict,
DICT_VENDOR, &vnd_data, NULL, &vnd);
ogs_assert(ret == 0);
gx_app_data.application_id = 16777238;
gx_app_data.application_name = (char *) "Gx";
rx_app_data.application_id = 16777236;
rx_app_data.application_name = (char *) "Rx";
ret = fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION,
&gx_app_data, NULL, &gx_app);
ogs_assert(ret == 0);
ret = fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION,
&rx_app_data, NULL, &rx_app);
ogs_assert(ret == 0);
ret = fd_disp_app_support(gx_app, vnd, 1, 0);
ogs_assert(ret == 0);
ret = fd_disp_app_support(rx_app, vnd, 1, 0);
ogs_assert(ret == 0);
ogs_assert(rv == 0);
rv = pcrf_gx_init();
ogs_assert(rv == OGS_OK);

View File

@ -931,16 +931,6 @@ int pcrf_gx_send_rar(
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
@ -952,6 +942,16 @@ int pcrf_gx_send_rar(
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Auth-Application-Id AVP */
ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp);
ogs_assert(ret == 0);

View File

@ -501,16 +501,6 @@ int pcrf_rx_send_asr(uint8_t *rx_sid, uint32_t abort_cause)
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
@ -522,6 +512,16 @@ int pcrf_rx_send_asr(uint8_t *rx_sid, uint32_t abort_cause)
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Auth-Application-Id AVP */
ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp);
ogs_assert(ret == 0);

View File

@ -1056,9 +1056,6 @@ int smf_fd_init(void)
{
int ret;
struct disp_when data;
struct dict_object *gx_app, *vnd;
struct dict_vendor_data vnd_data;
struct dict_application_data gx_app_data;
if (smf_self()->diam_conf_path == NULL &&
(smf_self()->diam_config->cnf_diamid == NULL ||
@ -1075,23 +1072,6 @@ int smf_fd_init(void)
smf_self()->diam_conf_path, smf_self()->diam_config);
ogs_assert(ret == 0);
vnd_data.vendor_id = 10415;
vnd_data.vendor_name = (char *) "3GPP";
ret = fd_dict_new(fd_g_config->cnf_dict,
DICT_VENDOR, &vnd_data, NULL, &vnd);
ogs_assert(ret == 0);
gx_app_data.application_id = 16777238;
gx_app_data.application_name = (char *) "Gx";
ret = fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION,
&gx_app_data, NULL, &gx_app);
ogs_assert(ret == 0);
ret = fd_disp_app_support(gx_app, vnd, 1, 0);
ogs_assert(ret == 0);
/* Install objects definitions for this application */
ret = ogs_diam_gx_init();
ogs_assert(ret == 0);
@ -1114,6 +1094,7 @@ int smf_fd_init(void)
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_gx_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == 0);
return OGS_OK;
}

View File

@ -1535,6 +1535,10 @@ bson_t *test_db_new_ims(test_ue_t *test_ue)
doc = BCON_NEW(
"imsi", BCON_UTF8(test_ue->imsi),
"msisdn", "[",
BCON_UTF8(TEST_MSISDN),
BCON_UTF8(TEST_ADDITIONAL_MSISDN),
"]",
"ambr", "{",
"downlink", "{",
"value", BCON_INT32(1),

View File

@ -40,6 +40,9 @@ extern "C" {
#define MAX_NUM_OF_SERVED_GUAMI 8
#define TEST_MSISDN "491725670014"
#define TEST_ADDITIONAL_MSISDN "491725670015"
typedef struct test_context_s {
uint16_t ngap_port; /* Default NGAP Port */
ogs_list_t ngap_list; /* AMF NGAP IPv4 Server List */

View File

@ -67,7 +67,8 @@ libtestcommon = static_library('testcomon',
libngap_dep,
libnas_eps_dep,
libnas_5gs_dep,
libdiameter_rx_dep],
libdiameter_rx_dep,
libdiameter_cx_dep],
install : false)
libtestcommon_dep = declare_dependency(
@ -83,4 +84,5 @@ libtestcommon_dep = declare_dependency(
libngap_dep,
libnas_eps_dep,
libnas_5gs_dep,
libdiameter_rx_dep])
libdiameter_rx_dep,
libdiameter_cx_dep])

View File

@ -25,6 +25,7 @@ abts_suite *test_bearer(abts_suite *suite);
abts_suite *test_session(abts_suite *suite);
abts_suite *test_rx(abts_suite *suite);
abts_suite *test_video(abts_suite *suite);
abts_suite *test_cx(abts_suite *suite);
const struct testlist {
abts_suite *(*func)(abts_suite *suite);
@ -33,6 +34,7 @@ const struct testlist {
{test_session},
{test_rx},
{test_video},
{test_cx},
{NULL},
};

350
tests/volte/cx-test.c Normal file
View File

@ -0,0 +1,350 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-common.h"
#include "pcscf-fd-path.h"
static void test1_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *s1ap;
ogs_socknode_t *gtpu;
ogs_pkbuf_t *emmbuf;
ogs_pkbuf_t *esmbuf;
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_s1ap_message_t message;
uint8_t *rx_sid = NULL;
ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci;
test_ue_t *test_ue = NULL;
test_sess_t *sess = NULL;
test_bearer_t *bearer = NULL;
uint32_t enb_ue_s1ap_id;
uint64_t mme_ue_s1ap_id;
bson_t *doc = NULL;
/* Setup Test UE & Session Context */
memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci));
mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI;
mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI;
mobile_identity_suci.routing_indicator1 = 0;
mobile_identity_suci.routing_indicator2 = 0xf;
mobile_identity_suci.routing_indicator3 = 0xf;
mobile_identity_suci.routing_indicator4 = 0xf;
mobile_identity_suci.protection_scheme_id = OGS_NAS_5GS_NULL_SCHEME;
mobile_identity_suci.home_network_pki_value = 0;
mobile_identity_suci.scheme_output[0] = 0x10;
mobile_identity_suci.scheme_output[1] = 0x32;
mobile_identity_suci.scheme_output[2] = 0x54;
mobile_identity_suci.scheme_output[3] = 0x86;
mobile_identity_suci.scheme_output[4] = 0x91;
test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13);
ogs_assert(test_ue);
test_ue->e_cgi.cell_id = 0x1079baf;
test_ue->nas.ksi = 0;
test_ue->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH;
#if 0 /* ipsec_reg.pcapng */
test_ue->k_string = "8baf473f2f8fd09487cccbd7097c6862";
test_ue->opc_string = "8E27B6AF0E692E750F32667A3B14605D";
#else
test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca";
#endif
sess = test_sess_add_by_apn(test_ue, "internet");
ogs_assert(sess);
/* eNB connects to MME */
s1ap = tests1ap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, s1ap);
/* eNB connects to SGW */
gtpu = test_gtpu_server(1, AF_INET);
ABTS_PTR_NOTNULL(tc, gtpu);
/* Send S1-Setup Reqeust */
sendbuf = test_s1ap_build_s1_setup_request(
S1AP_ENB_ID_PR_macroENB_ID, 0x54f64);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive S1-Setup Response */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(NULL, recvbuf);
/********** Insert Subscriber in Database */
doc = test_db_new_ims(test_ue);
ABTS_PTR_NOTNULL(tc, doc);
ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc));
/* Send Attach Request */
memset(&sess->pdn_connectivity_param,
0, sizeof(sess->pdn_connectivity_param));
sess->pdn_connectivity_param.eit = 1;
esmbuf = testesm_build_pdn_connectivity_request(sess);
ABTS_PTR_NOTNULL(tc, esmbuf);
memset(&test_ue->attach_request_param,
0, sizeof(test_ue->attach_request_param));
test_ue->attach_request_param.integrity_protected = 1;
test_ue->attach_request_param.drx_parameter = 1;
test_ue->attach_request_param.ms_network_capability = 1;
test_ue->attach_request_param.tmsi_status = 1;
test_ue->attach_request_param.mobile_station_classmark_2 = 1;
test_ue->attach_request_param.ue_usage_setting = 1;
emmbuf = testemm_build_attach_request(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, emmbuf);
memset(&test_ue->initial_ue_param, 0, sizeof(test_ue->initial_ue_param));
sendbuf = test_s1ap_build_initial_ue_message(
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Signalling, false);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Authentication Request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send Authentication response */
emmbuf = testemm_build_authentication_response(test_ue);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Security mode Command */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send Security mode complete */
test_ue->mobile_identity_imeisv_presence = true;
emmbuf = testemm_build_security_mode_complete(test_ue);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive ESM Information Request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send ESM Information Response */
sess->esm_information_param.pco = 1;
esmbuf = testesm_build_esm_information_response(sess);
ABTS_PTR_NOTNULL(tc, esmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Initial Context Setup Request +
* Attach Accept +
* Activate Default Bearer Context Request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send UE Capability Info Indication */
sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Initial Context Setup Response */
sendbuf = test_s1ap_build_initial_context_setup_response(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Attach Complete + Activate default EPS bearer cotext accept */
test_ue->nr_cgi.cell_id = 0x1234502;
bearer = test_bearer_find_by_ue_ebi(test_ue, 5);
ogs_assert(bearer);
esmbuf = testesm_build_activate_default_eps_bearer_context_accept(
bearer, false);
ABTS_PTR_NOTNULL(tc, esmbuf);
emmbuf = testemm_build_attach_complete(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive EMM information */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send PDN Connectivity Request */
sess = test_sess_add_by_apn(test_ue, "ims");
ogs_assert(sess);
sess->pti = 5;
sess->pdn_connectivity_param.integrity_protected = 1;
sess->pdn_connectivity_param.ciphered = 1;
sess->pdn_connectivity_param.apn = 1;
sess->pdn_connectivity_param.pco = 1;
esmbuf = testesm_build_pdn_connectivity_request(sess);
ABTS_PTR_NOTNULL(tc, esmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive E-RAB Setup Request +
* Activate default EPS bearer context request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send E-RAB Setup Response */
bearer = test_bearer_find_by_ue_ebi(test_ue, 6);
ogs_assert(bearer);
sendbuf = test_s1ap_build_e_rab_setup_response(bearer);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Activate default EPS bearer context accept */
esmbuf = testesm_build_activate_default_eps_bearer_context_accept(
bearer, true);
ABTS_PTR_NOTNULL(tc, esmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send AA-Request */
pcscf_rx_send_aar_audio(&rx_sid, sess,
OGS_DIAM_RX_SUBSCRIPTION_ID_TYPE_END_USER_IMSI, 1, 1);
/* Receive E-RAB Setup Request +
* Activate dedicated EPS bearer context request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send E-RAB Setup Response */
bearer = test_bearer_find_by_ue_ebi(test_ue, 7);
ogs_assert(bearer);
sendbuf = test_s1ap_build_e_rab_setup_response(bearer);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Activate dedicated EPS bearer context accept */
esmbuf = testesm_build_activate_dedicated_eps_bearer_context_accept(bearer);
ABTS_PTR_NOTNULL(tc, esmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* DELAY is needed in dedicated EPS bearer */
ogs_msleep(100);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send User-Authorization-Request */
test_cx_send_uar(test_ue, 0);
/* DELAY for setup IMS */
ogs_msleep(100);
/* Send UEContextReleaseRequest */
sendbuf = test_s1ap_build_ue_context_release_request(test_ue,
S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive UEContextReleaseCommand */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send UEContextReleaseComplete */
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_msleep(300);
/********** Remove Subscriber in Database */
ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue));
/* eNB disonncect from MME */
testenb_s1ap_close(s1ap);
/* eNB disonncect from SGW */
test_gtpu_close(gtpu);
test_ue_remove(test_ue);
}
abts_suite *test_cx(abts_suite *suite)
{
suite = ADD_SUITE(suite)
abts_run_test(suite, test1_func, NULL);
return suite;
}

View File

@ -0,0 +1,926 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-diameter-cx.h"
#include "test-common.h"
#include "pcscf-fd-path.h"
static struct session_handler *test_cx_reg = NULL;
struct sess_state {
test_ue_t *test_ue;
char *user_name;
char *public_identity;
bool resync;
struct timespec ts; /* Time of sending the message */
};
static struct disp_hdl *hdl_cx_fb = NULL;
static void test_cx_uaa_cb(void *data, struct msg **msg);
static void test_cx_send_mar(struct sess_state *sess_data);
static void test_cx_maa_cb(void *data, struct msg **msg);
static void test_cx_send_sar(struct sess_state *sess_data);
static void test_cx_saa_cb(void *data, struct msg **msg);
static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque)
{
if (sess_data->user_name)
ogs_free(sess_data->user_name);
if (sess_data->public_identity)
ogs_free(sess_data->public_identity);
ogs_free(sess_data);
}
static int test_cx_fb_cb(struct msg **msg, struct avp *avp,
struct session *sess, void *opaque, enum disp_action *act)
{
/* This CB should never be called */
ogs_warn("Unexpected message received!");
return ENOTSUP;
}
void test_cx_send_uar(test_ue_t *test_ue, int id_type)
{
int ret;
struct msg *req = NULL;
struct msg_hdr *msg_header = NULL;
struct session *session = NULL;
struct sess_state *sess_data = NULL, *svg;
struct avp *avp = NULL;
union avp_value val;
ogs_assert(test_ue);
ogs_debug("User-Authroization-Request");
/* Create the random value to store with the session */
sess_data = ogs_calloc(1, sizeof (*sess_data));
ogs_assert(sess_data);
sess_data->test_ue = test_ue;
/* Create the request */
ret = fd_msg_new(ogs_diam_cx_cmd_uar, MSGFL_ALLOC_ETEID, &req);
ogs_assert(ret == 0);
ret = fd_msg_hdr(req, &msg_header);
ogs_assert(ret == 0);
msg_header->msg_appl = OGS_DIAM_CX_APPLICATION_ID;
#define OGS_DIAM_CX_APP_SID_OPT "app_cx"
ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_CX_APP_SID_OPT,
CONSTSTRLEN(OGS_DIAM_CX_APP_SID_OPT));
ogs_assert(ret == 0);
ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
req, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_HSS_IDENTITY;
val.os.len = strlen(TEST_HSS_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
if (sess_data->user_name)
ogs_free(sess_data->user_name);
sess_data->user_name =
ogs_msprintf("%s@%s", test_ue->imsi, fd_g_config->cnf_diamrlm);
ogs_assert(sess_data->user_name);
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess_data->user_name;
val.os.len = strlen(sess_data->user_name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Public-Identity AVP */
if (sess_data->public_identity)
ogs_free(sess_data->public_identity);
sess_data->public_identity = ogs_msprintf("sip:%s@%s",
test_ue->imsi, fd_g_config->cnf_diamrlm);
ogs_assert(sess_data->public_identity);
ret = fd_msg_avp_new(ogs_diam_cx_public_identity, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess_data->public_identity;
val.os.len = strlen(sess_data->public_identity);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Visited-Network-Identifier AVP */
ret = fd_msg_avp_new(ogs_diam_cx_visited_network_identifier, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts);
ogs_assert(ret == 0);
/* Keep a pointer to the session data for debug purpose,
* in real life we would not need it */
svg = sess_data;
/* Store this value in the session */
ret = fd_sess_state_store(test_cx_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == 0);
/* Send the request */
ret = fd_msg_send(&req, test_cx_uaa_cb, svg);
ogs_assert(ret == 0);
/* Increment the counter */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_sent++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
}
/* Callback for incoming User-Authorization-Answer messages */
static void test_cx_uaa_cb(void *data, struct msg **msg)
{
int ret, new;
struct avp *avp, *avpch;
struct avp_hdr *hdr;
unsigned long dur;
int error = 0;
struct sess_state *sess_data = NULL;
struct timespec ts;
struct session *session;
test_ue_t *test_ue = NULL;
uint32_t result_code;
uint32_t *err = NULL, *exp_err = NULL;
ogs_debug("User-Authroization-Answer");
ret = clock_gettime(CLOCK_REALTIME, &ts);
ogs_assert(ret == 0);
/* Search the session, retrieve its data */
ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new);
ogs_expect_or_return(ret == 0);
ogs_expect_or_return(new == 0);
ret = fd_sess_state_retrieve(test_cx_reg, session, &sess_data);
ogs_expect_or_return(ret == 0);
ogs_expect_or_return(sess_data);
ogs_expect_or_return((void *)sess_data == data);
test_ue = sess_data->test_ue;
ogs_assert(test_ue);
/* Value of Result Code */
ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
result_code = hdr->avp_value->i32;
err = &result_code;
ogs_debug(" Result Code: %d", hdr->avp_value->i32);
} else {
ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_avp_search_avp(avp,
ogs_diam_experimental_result_code, &avpch);
ogs_assert(ret == 0);
if (avpch) {
ret = fd_msg_avp_hdr(avpch, &hdr);
ogs_assert(ret == 0);
result_code = hdr->avp_value->i32;
exp_err = &result_code;
ogs_debug(" Experimental Result Code: %d", result_code);
}
} else {
ogs_error("no Result-Code");
error++;
}
}
ogs_assert(!err && exp_err &&
result_code == OGS_DIAM_CX_FIRST_REGISTRATION);
/* Free the message */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_logger_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg *
ogs_diam_logger_self()->stats.nb_recv + dur) /
(ogs_diam_logger_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_logger_self()->stats.shortest)
ogs_diam_logger_self()->stats.shortest = dur;
if (dur > ogs_diam_logger_self()->stats.longest)
ogs_diam_logger_self()->stats.longest = dur;
} else {
ogs_diam_logger_self()->stats.shortest = dur;
ogs_diam_logger_self()->stats.longest = dur;
ogs_diam_logger_self()->stats.avg = dur;
}
if (error)
ogs_diam_logger_self()->stats.nb_errs++;
else
ogs_diam_logger_self()->stats.nb_recv++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
test_cx_send_mar(sess_data);
return;
}
static void test_cx_send_mar(struct sess_state *sess_data)
{
int ret;
struct msg *req = NULL;
struct msg_hdr *msg_header = NULL;
struct session *session = NULL;
struct sess_state *svg;
struct avp *avp = NULL, *avpch = NULL;
union avp_value val;
test_ue_t *test_ue = NULL;
uint8_t resync[OGS_AUTS_LEN + OGS_RAND_LEN];
ogs_assert(sess_data);
test_ue = sess_data->test_ue;
ogs_assert(test_ue);
ogs_debug("Multimedia-Auth-Request");
/* Create the request */
ret = fd_msg_new(ogs_diam_cx_cmd_mar, MSGFL_ALLOC_ETEID, &req);
ogs_assert(ret == 0);
ret = fd_msg_hdr(req, &msg_header);
ogs_assert(ret == 0);
msg_header->msg_appl = OGS_DIAM_CX_APPLICATION_ID;
#define OGS_DIAM_CX_APP_SID_OPT "app_cx"
ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_CX_APP_SID_OPT,
CONSTSTRLEN(OGS_DIAM_CX_APP_SID_OPT));
ogs_assert(ret == 0);
ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
req, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_HSS_IDENTITY;
val.os.len = strlen(TEST_HSS_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess_data->user_name;
val.os.len = strlen(sess_data->user_name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Public-Identity AVP */
ret = fd_msg_avp_new(ogs_diam_cx_public_identity, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess_data->public_identity;
val.os.len = strlen(sess_data->public_identity);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the SIP-Auth-Data-Item AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp);
ogs_assert(ret == 0);
if (sess_data->resync == true) {
uint8_t ak[OGS_AK_LEN];
uint8_t sqn[OGS_SQN_LEN];
uint8_t mac_s[OGS_MAC_S_LEN];
uint8_t amf[2] = { 0, 0 };
uint8_t auts[OGS_AUTS_LEN];
uint64_t sqn_ms;
int i;
OGS_HEX(test_ue->k_string, strlen(test_ue->k_string), test_ue->k);
OGS_HEX(test_ue->opc_string, strlen(test_ue->opc_string), test_ue->opc);
milenage_f2345(test_ue->opc, test_ue->k, test_ue->rand,
NULL, NULL, NULL, NULL, ak);
sqn_ms = 0x11223344;
ogs_uint64_to_buffer(sqn_ms, 6, sqn);
milenage_f1(test_ue->opc, test_ue->k, test_ue->rand,
sqn, amf, NULL, auts + OGS_SQN_LEN);
for (i = 0; i < OGS_SQN_LEN; i++)
auts[i] = sqn[i] ^ ak[i];
memset(resync, 0, sizeof resync);
memcpy(resync, test_ue->rand, OGS_RAND_LEN);
memcpy(resync+OGS_RAND_LEN, auts, OGS_AUTS_LEN);
ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch);
ogs_assert(ret == 0);
val.os.len = OGS_RAND_LEN+OGS_AUTS_LEN;
val.os.data = resync;
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
} else {
ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)OGS_DIAM_CX_AUTH_SCHEME_UNKNOWN;
val.os.len = strlen(OGS_DIAM_CX_AUTH_SCHEME_UNKNOWN);
ret = fd_msg_avp_setvalue(avpch, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch);
ogs_assert(ret == 0);
}
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the SIP-Number-Auth-Items AVP */
ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Server-Name AVP */
ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (os0_t)fd_g_config->cnf_diamid;
val.os.len = fd_g_config->cnf_diamid_len;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts);
ogs_assert(ret == 0);
/* Keep a pointer to the session data for debug purpose,
* in real life we would not need it */
svg = sess_data;
/* Store this value in the session */
ret = fd_sess_state_store(test_cx_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == 0);
/* Send the request */
ret = fd_msg_send(&req, test_cx_maa_cb, svg);
ogs_assert(ret == 0);
/* Increment the counter */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_sent++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
}
/* Callback for incoming Multimedia-Auth-Answer messages */
static void test_cx_maa_cb(void *data, struct msg **msg)
{
int ret, new;
struct avp *avp, *avpch;
struct avp_hdr *hdr;
unsigned long dur;
int error = 0;
struct sess_state *sess_data = NULL;
struct timespec ts;
struct session *session;
test_ue_t *test_ue = NULL;
uint32_t result_code;
uint32_t *err = NULL, *exp_err = NULL;
ogs_debug("Multimedia-Auth-Answer");
ret = clock_gettime(CLOCK_REALTIME, &ts);
ogs_assert(ret == 0);
/* Search the session, retrieve its data */
ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new);
ogs_expect_or_return(ret == 0);
ogs_expect_or_return(new == 0);
ret = fd_sess_state_retrieve(test_cx_reg, session, &sess_data);
ogs_expect_or_return(ret == 0);
ogs_expect_or_return(sess_data);
ogs_expect_or_return((void *)sess_data == data);
test_ue = sess_data->test_ue;
ogs_assert(test_ue);
/* Value of Result Code */
ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
result_code = hdr->avp_value->i32;
err = &result_code;
ogs_debug(" Result Code: %d", hdr->avp_value->i32);
} else {
ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_avp_search_avp(avp,
ogs_diam_experimental_result_code, &avpch);
ogs_assert(ret == 0);
if (avpch) {
ret = fd_msg_avp_hdr(avpch, &hdr);
ogs_assert(ret == 0);
result_code = hdr->avp_value->i32;
exp_err = &result_code;
ogs_debug(" Experimental Result Code: %d", result_code);
}
} else {
ogs_error("no Result-Code");
error++;
}
}
ogs_assert(err && !exp_err && result_code == ER_DIAMETER_SUCCESS);
/* Free the message */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_logger_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg *
ogs_diam_logger_self()->stats.nb_recv + dur) /
(ogs_diam_logger_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_logger_self()->stats.shortest)
ogs_diam_logger_self()->stats.shortest = dur;
if (dur > ogs_diam_logger_self()->stats.longest)
ogs_diam_logger_self()->stats.longest = dur;
} else {
ogs_diam_logger_self()->stats.shortest = dur;
ogs_diam_logger_self()->stats.longest = dur;
ogs_diam_logger_self()->stats.avg = dur;
}
if (error)
ogs_diam_logger_self()->stats.nb_errs++;
else
ogs_diam_logger_self()->stats.nb_recv++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
if (sess_data->resync == true) {
test_cx_send_sar(sess_data);
} else {
sess_data->resync = true;
test_cx_send_mar(sess_data);
}
return;
}
static void test_cx_send_sar(struct sess_state *sess_data)
{
int ret;
struct msg *req = NULL;
struct msg_hdr *msg_header = NULL;
struct session *session = NULL;
struct sess_state *svg;
struct avp *avp = NULL, *avpch = NULL;
union avp_value val;
test_ue_t *test_ue = NULL;
ogs_assert(sess_data);
test_ue = sess_data->test_ue;
ogs_assert(test_ue);
ogs_debug("Server-Assignment-Request");
/* Create the request */
ret = fd_msg_new(ogs_diam_cx_cmd_sar, MSGFL_ALLOC_ETEID, &req);
ogs_assert(ret == 0);
ret = fd_msg_hdr(req, &msg_header);
ogs_assert(ret == 0);
msg_header->msg_appl = OGS_DIAM_CX_APPLICATION_ID;
#define OGS_DIAM_CX_APP_SID_OPT "app_cx"
ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_CX_APP_SID_OPT,
CONSTSTRLEN(OGS_DIAM_CX_APP_SID_OPT));
ogs_assert(ret == 0);
ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL);
ogs_assert(ret == 0);
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
req, OGS_DIAM_CX_APPLICATION_ID);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = 1;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set Origin-Host & Origin-Realm */
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_HSS_IDENTITY;
val.os.len = strlen(TEST_HSS_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the User-Name AVP */
ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess_data->user_name;
val.os.len = strlen(sess_data->user_name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Public-Identity AVP */
ret = fd_msg_avp_new(ogs_diam_cx_public_identity, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess_data->public_identity;
val.os.len = strlen(sess_data->public_identity);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Server-Name AVP */
ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (os0_t)fd_g_config->cnf_diamid;
val.os.len = fd_g_config->cnf_diamid_len;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Server-Assignment-Type AVP */
ret = fd_msg_avp_new(ogs_diam_cx_server_assignment_type, 0, &avp);
ogs_assert(ret == 0);
val.i32 = OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the User-Data-Already-Avaiable AVP */
ret = fd_msg_avp_new(ogs_diam_cx_user_data_already_available, 0, &avp);
ogs_assert(ret == 0);
val.i32 = OGS_DIAM_CX_USER_DATA_NOT_AVAILABLE;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts);
ogs_assert(ret == 0);
/* Keep a pointer to the session data for debug purpose,
* in real life we would not need it */
svg = sess_data;
/* Store this value in the session */
ret = fd_sess_state_store(test_cx_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == 0);
/* Send the request */
ret = fd_msg_send(&req, test_cx_saa_cb, svg);
ogs_assert(ret == 0);
/* Increment the counter */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_sent++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
}
/* Callback for incoming Server-Assignment-Answer messages */
static void test_cx_saa_cb(void *data, struct msg **msg)
{
int ret, new;
struct avp *avp, *avpch;
struct avp_hdr *hdr;
unsigned long dur;
int error = 0;
struct sess_state *sess_data = NULL;
struct timespec ts;
struct session *session;
test_ue_t *test_ue = NULL;
uint32_t result_code;
uint32_t *err = NULL, *exp_err = NULL;
ogs_debug("Server-Assignment-Answer");
ret = clock_gettime(CLOCK_REALTIME, &ts);
ogs_assert(ret == 0);
/* Search the session, retrieve its data */
ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new);
ogs_expect_or_return(ret == 0);
ogs_expect_or_return(new == 0);
ret = fd_sess_state_retrieve(test_cx_reg, session, &sess_data);
ogs_expect_or_return(ret == 0);
ogs_expect_or_return(sess_data);
ogs_expect_or_return((void *)sess_data == data);
test_ue = sess_data->test_ue;
ogs_assert(test_ue);
/* Value of Result Code */
ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
result_code = hdr->avp_value->i32;
err = &result_code;
ogs_debug(" Result Code: %d", hdr->avp_value->i32);
} else {
ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_avp_search_avp(avp,
ogs_diam_experimental_result_code, &avpch);
ogs_assert(ret == 0);
if (avpch) {
ret = fd_msg_avp_hdr(avpch, &hdr);
ogs_assert(ret == 0);
result_code = hdr->avp_value->i32;
exp_err = &result_code;
ogs_debug(" Experimental Result Code: %d", result_code);
}
} else {
ogs_error("no Result-Code");
error++;
}
}
ogs_assert(err && !exp_err && result_code == ER_DIAMETER_SUCCESS);
/* Free the message */
ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_logger_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg *
ogs_diam_logger_self()->stats.nb_recv + dur) /
(ogs_diam_logger_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_logger_self()->stats.shortest)
ogs_diam_logger_self()->stats.shortest = dur;
if (dur > ogs_diam_logger_self()->stats.longest)
ogs_diam_logger_self()->stats.longest = dur;
} else {
ogs_diam_logger_self()->stats.shortest = dur;
ogs_diam_logger_self()->stats.longest = dur;
ogs_diam_logger_self()->stats.avg = dur;
}
if (error)
ogs_diam_logger_self()->stats.nb_errs++;
else
ogs_diam_logger_self()->stats.nb_recv++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
state_cleanup(sess_data, NULL, NULL);
return;
}
int test_cx_init(void)
{
int ret;
struct disp_when data;
/* Install objects definitions for this application */
ret = ogs_diam_cx_init();
ogs_assert(ret == 0);
/* Create handler for sessions */
ret = fd_sess_handler_create(&test_cx_reg, &state_cleanup, NULL, NULL);
ogs_assert(ret == 0);
/* Fallback CB if command != unexpected message received */
memset(&data, 0, sizeof(data));
data.app = ogs_diam_cx_application;
ret = fd_disp_register(test_cx_fb_cb, DISP_HOW_APPID, &data, NULL,
&hdl_cx_fb);
ogs_assert(ret == 0);
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_cx_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == 0);
return 0;
}
void test_cx_final(void)
{
int ret;
ret = fd_sess_handler_destroy(&test_cx_reg, NULL);
ogs_assert(ret == OGS_OK);
if (hdl_cx_fb)
(void) fd_disp_unregister(&hdl_cx_fb, NULL);
}

View File

@ -18,12 +18,14 @@
testapp_volte_sources = files('''
pcscf-fd-path.h
pcscf-fd-path.c
diameter-cx-path.c
abts-main.c
bearer-test.c
session-test.c
rx-test.c
video-test.c
cx-test.c
'''.split())
testapp_volte_exe = executable('volte',

View File

@ -58,7 +58,7 @@ static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque)
ogs_free(sess_data);
}
static int pcscf_rx_fb_cb(struct msg **msg, struct avp *avp,
static int pcscf_rx_fb_cb(struct msg **msg, struct avp *avp,
struct session *sess, void *opaque, enum disp_action *act)
{
/* This CB should never be called */
@ -156,6 +156,16 @@ void pcscf_rx_send_aar_audio(uint8_t **rx_sid,
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_PCRF_IDENTITY;
val.os.len = strlen(TEST_PCRF_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
@ -643,6 +653,16 @@ void pcscf_rx_send_aar_video(uint8_t **rx_sid, test_sess_t *sess, int id_type)
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_PCRF_IDENTITY;
val.os.len = strlen(TEST_PCRF_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
@ -1311,6 +1331,16 @@ void pcscf_rx_send_aar_ctrl(uint8_t **rx_sid, test_sess_t *sess, int id_type)
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_PCRF_IDENTITY;
val.os.len = strlen(TEST_PCRF_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
@ -1881,6 +1911,16 @@ void pcscf_rx_send_str(uint8_t *rx_sid)
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = TEST_PCRF_IDENTITY;
val.os.len = strlen(TEST_PCRF_IDENTITY);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
@ -2063,7 +2103,7 @@ void pcscf_diam_config(void)
{
memset(&diam_config, 0, sizeof(ogs_diam_config_t));
diam_config.cnf_diamid = "pcscf.localdomain";
diam_config.cnf_diamid = "ims.localdomain";
diam_config.cnf_diamrlm = "localdomain";
diam_config.cnf_port = DIAMETER_PORT;
diam_config.cnf_port_tls = DIAMETER_SECURE_PORT;
@ -2093,7 +2133,10 @@ void pcscf_diam_config(void)
FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_dcca_3gpp.fdx";
diam_config.num_of_ext++;
diam_config.conn[diam_config.num_of_conn].identity = "pcrf.localdomain";
diam_config.conn[diam_config.num_of_conn].identity = TEST_HSS_IDENTITY;
diam_config.conn[diam_config.num_of_conn].addr = "127.0.0.8";
diam_config.num_of_conn++;
diam_config.conn[diam_config.num_of_conn].identity = TEST_PCRF_IDENTITY;
diam_config.conn[diam_config.num_of_conn].addr = "127.0.0.9";
diam_config.num_of_conn++;
}
@ -2108,6 +2151,8 @@ int pcscf_fd_init(void)
ret = ogs_diam_init(FD_MODE_CLIENT, NULL, &diam_config);
ogs_assert(ret == 0);
test_cx_init();
/* Install objects definitions for this application */
ret = ogs_diam_rx_init();
ogs_assert(ret == 0);
@ -2148,5 +2193,7 @@ void pcscf_fd_final(void)
if (hdl_rx_asr)
(void) fd_disp_unregister(&hdl_rx_asr, NULL);
test_cx_final();
ogs_diam_final();
}

View File

@ -26,15 +26,23 @@ extern "C" {
#include "ogs-diameter-rx.h"
#define TEST_HSS_IDENTITY "hss.localdomain"
#define TEST_PCRF_IDENTITY "pcrf.localdomain"
int pcscf_fd_init(void);
void pcscf_fd_final(void);
int test_cx_init(void);
void test_cx_final(void);
void pcscf_rx_send_aar_audio(uint8_t **rx_sid,
test_sess_t *sess, int id_type, int qos_type, int flow_type);
void pcscf_rx_send_aar_video(uint8_t **rx_sid, test_sess_t *sess, int id_type);
void pcscf_rx_send_aar_ctrl(uint8_t **rx_sid, test_sess_t *sess, int id_type);
void pcscf_rx_send_str(uint8_t *rx_sid);
void test_cx_send_uar(test_ue_t *test_ue, int id_type);
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,6 @@
{
"name": "open5gs",
"version": "2.2.1",
"version": "2.2.6",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

@ -1,6 +1,6 @@
{
"name": "open5gs",
"version": "2.2.1",
"version": "2.2.6",
"description": "Open5gs",
"main": "index.js",
"repository": "https://github.com/open5gs/open5gs/webui",

View File

@ -11,6 +11,8 @@ const Profile = new Schema({
title: { $type: String, required: true },
msisdn: [ String ],
security: {
k: String,
op: String,

View File

@ -11,6 +11,8 @@ const Subscriber = new Schema({
imsi: { $type: String, unique: true, required: true },
msisdn: [ String ],
security: {
k: String,
op: String,

View File

@ -9,11 +9,29 @@ const schema = {
"type": "object",
"properties": {
"title": {
"type": "string",
"type": "string",
"title": "Title*",
"required": true,
"maxLength": 24
},
"msisdn": {
"type": "array",
"title": "",
"maxItems": 2,
"messages": {
"maxItems": "2 MSISDN are supported"
},
"items": {
"type": "string",
"title": "MSISDN",
"maxLength": 15,
"required": true,
"pattern": "^\\d+$",
"messages": {
"pattern": "Only digits are allowed"
}
}
},
"security": {
"title": "",
"type": "object",
@ -440,7 +458,11 @@ const uiSchema = {
"title" : {
classNames: "col-xs-12",
},
"msisdn" : {
classNames: "col-xs-7",
},
"security" : {
classNames: "col-xs-12",
"k" : {
classNames: "col-xs-7",
},
@ -455,6 +477,7 @@ const uiSchema = {
},
},
"ambr" : {
classNames: "col-xs-12",
"downlink": {
classNames: "col-xs-6",
"value": {
@ -475,6 +498,7 @@ const uiSchema = {
}
},
"slice": {
classNames: "col-xs-12",
"items": {
"sst": {
classNames: "col-xs-3",
@ -621,12 +645,12 @@ const uiSchema = {
class Edit extends Component {
static propTypes = {
visible: PropTypes.bool,
action: PropTypes.string,
visible: PropTypes.bool,
action: PropTypes.string,
formData: PropTypes.object,
isLoading: PropTypes.bool,
validate: PropTypes.func,
onHide: PropTypes.func,
validate: PropTypes.func,
onHide: PropTypes.func,
onSubmit: PropTypes.func,
onError: PropTypes.func
}

View File

@ -8,6 +8,7 @@ import EditIcon from 'react-icons/lib/md/edit';
import DeleteIcon from 'react-icons/lib/md/delete';
import CloseIcon from 'react-icons/lib/md/close';
import PhoneIcon from 'react-icons/lib/md/phone';
import SecurityIcon from 'react-icons/lib/md/security';
import PdnIcon from 'react-icons/lib/md/cast';
import KeyboardControlIcon from 'react-icons/lib/md/keyboard-control';
@ -161,6 +162,7 @@ const Pdn = styled.div`
const View = ({ visible, disableOnClickOutside, profile, onEdit, onDelete, onHide }) => {
const _id = (profile || {})._id;
const title = (profile || {}).title;
const msisdn_list = ((profile || {}).msisdn || []);
const security = ((profile || {}).security || {});
const ambr = ((profile || {}).ambr || {});
const slice_list = ((profile || {}).slice || []);
@ -191,6 +193,21 @@ const View = ({ visible, disableOnClickOutside, profile, onEdit, onDelete, onHid
<div className="header">
Profile Configuration
</div>
{msisdn_list.length !== 0 &&
<div className="body">
<div className="left">
<PhoneIcon/>
</div>
<div className="right">
{msisdn_list.map((msisdn, index) =>
<div key={index} className="data">
{msisdn}
<span style={{color:oc.gray[5]}}><KeyboardControlIcon/>MSISDN</span>
</div>
)}
</div>
</div>
}
<div className="body">
<div className="left">
<SecurityIcon/>

View File

@ -69,7 +69,10 @@ const fields = {
};
function Label(props) {
const { label, required, id } = props;
// modified by acetcom
// const { label, required, id } = props;
const { label, id } = props;
const required = 0;
if (!label) {
// See #312: Ensure compatibility with old versions of React.
return <div />;
@ -304,4 +307,4 @@ class Form extends Component {
}
}
export default Form;
export default Form;

View File

@ -11,7 +11,7 @@ const schema = {
"type": "object",
"properties": {
"imsi": {
"type": "string",
"type": "string",
"title": "IMSI*",
"required": true,
"pattern": "^\\d+$",
@ -20,6 +20,24 @@ const schema = {
"pattern": "Only digits are allowed"
}
},
"msisdn": {
"type": "array",
"title": "",
"maxItems": 2,
"messages": {
"maxItems": "2 MSISDN are supported"
},
"items": {
"type": "string",
"title": "MSISDN",
"maxLength": 15,
"required": true,
"pattern": "^\\d+$",
"messages": {
"pattern": "Only digits are allowed"
}
}
},
"security": {
"title": "",
"type": "object",
@ -446,7 +464,11 @@ const uiSchema = {
"imsi" : {
classNames: "col-xs-12",
},
"msisdn" : {
classNames: "col-xs-7",
},
"security" : {
classNames: "col-xs-12",
"k" : {
classNames: "col-xs-7",
},
@ -461,6 +483,7 @@ const uiSchema = {
},
},
"ambr" : {
classNames: "col-xs-12",
"downlink": {
classNames: "col-xs-6",
"value": {
@ -628,12 +651,12 @@ const uiSchema = {
class Edit extends Component {
static propTypes = {
visible: PropTypes.bool,
action: PropTypes.string,
visible: PropTypes.bool,
action: PropTypes.string,
formData: PropTypes.object,
isLoading: PropTypes.bool,
validate: PropTypes.func,
onHide: PropTypes.func,
validate: PropTypes.func,
onHide: PropTypes.func,
onSubmit: PropTypes.func,
onError: PropTypes.func
}
@ -679,7 +702,7 @@ class Edit extends Component {
...schema,
"properties": {
profile: {
type: "string",
type: "string",
title: "Profile*",
enum: profiles.map(profile => profile._id),
enumNames: profiles.map(profile => profile.title),

View File

@ -8,6 +8,7 @@ import EditIcon from 'react-icons/lib/md/edit';
import DeleteIcon from 'react-icons/lib/md/delete';
import CloseIcon from 'react-icons/lib/md/close';
import PhoneIcon from 'react-icons/lib/md/phone';
import SecurityIcon from 'react-icons/lib/md/security';
import PdnIcon from 'react-icons/lib/md/cast';
import KeyboardControlIcon from 'react-icons/lib/md/keyboard-control';
@ -160,6 +161,7 @@ const Pdn = styled.div`
`
const View = ({ visible, disableOnClickOutside, subscriber, onEdit, onDelete, onHide }) => {
const imsi = (subscriber || {}).imsi;
const msisdn_list = ((subscriber || {}).msisdn || []);
const security = ((subscriber || {}).security || {});
const ambr = ((subscriber || {}).ambr || {});
const slice_list = ((subscriber || {}).slice || []);
@ -190,6 +192,21 @@ const View = ({ visible, disableOnClickOutside, subscriber, onEdit, onDelete, on
<div className="header">
Subscriber Configuration
</div>
{msisdn_list.length !== 0 &&
<div className="body">
<div className="left">
<PhoneIcon/>
</div>
<div className="right">
{msisdn_list.map((msisdn, index) =>
<div key={index} className="data">
{msisdn}
<span style={{color:oc.gray[5]}}><KeyboardControlIcon/>MSISDN</span>
</div>
)}
</div>
</div>
}
<div className="body">
<div className="left">
<SecurityIcon/>