Commit 692c1bb0 authored by Tien Thinh NGUYEN's avatar Tien Thinh NGUYEN

Update Authentication Failure

parent e8c98233
...@@ -110,6 +110,8 @@ constexpr uint8_t kIeiAuthenticationResponseParameter = 0x2D; ...@@ -110,6 +110,8 @@ constexpr uint8_t kIeiAuthenticationResponseParameter = 0x2D;
constexpr uint8_t kIeiUeSecurityCapability = 0x2e; constexpr uint8_t kIeiUeSecurityCapability = 0x2e;
constexpr uint8_t kIeiUeNetworkCapability = 0x17; constexpr uint8_t kIeiUeNetworkCapability = 0x17;
constexpr uint8_t kIeiAuthenticationFailureParameter = 0x30;
constexpr uint8_t kIeiAdditional5gSecurityInformation = 0x36; constexpr uint8_t kIeiAdditional5gSecurityInformation = 0x36;
constexpr uint8_t kIeiAbba = 0x38; constexpr uint8_t kIeiAbba = 0x38;
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
#include "UESecurityCapability.hpp" #include "UESecurityCapability.hpp"
#include "UeRadioCapabilityId.hpp" #include "UeRadioCapabilityId.hpp"
#include "UplinkDataStatus.hpp" #include "UplinkDataStatus.hpp"
#include "_5GMM_Cause.hpp" #include "_5gmmCause.hpp"
#include "_5GSDeregistrationType.hpp" #include "_5GSDeregistrationType.hpp"
#include "_5GSTrackingAreaIdList.hpp" #include "_5GSTrackingAreaIdList.hpp"
#include "_5GS_DRX_Parameters.hpp" #include "_5GS_DRX_Parameters.hpp"
......
...@@ -19,93 +19,112 @@ ...@@ -19,93 +19,112 @@
* contact@openairinterface.org * contact@openairinterface.org
*/ */
/*! \file
\brief
\author Keliang DU, BUPT
\date 2020
\email: contact@openairinterface.org
*/
#include "Authentication_Failure_Parameter.hpp" #include "Authentication_Failure_Parameter.hpp"
#include "logger.hpp" #include "logger.hpp"
using namespace nas; using namespace nas;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Authentication_Failure_Parameter::Authentication_Failure_Parameter( Authentication_Failure_Parameter::Authentication_Failure_Parameter()
uint8_t iei) { : Type4NasIe(kIeiAuthenticationFailureParameter), value_() {
_iei = iei; SetLengthIndicator(kAuthenticationFailureParameterContentLength);
length = 0; SetIeName(kAuthenticationFailureParameterIeName);
value = 0;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Authentication_Failure_Parameter::Authentication_Failure_Parameter( Authentication_Failure_Parameter::Authentication_Failure_Parameter(
const uint8_t iei, bstring auts) { const bstring& value) {
_iei = iei; value_ = bstrcpy(value);
value = bstrcpy(auts); SetLengthIndicator(kAuthenticationFailureParameterContentLength);
length = blength(auts) + 2; SetIeName(kAuthenticationFailureParameterIeName);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Authentication_Failure_Parameter::Authentication_Failure_Parameter() Authentication_Failure_Parameter::~Authentication_Failure_Parameter() {}
: _iei(), length(), value() {}
/*
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Authentication_Failure_Parameter::~Authentication_Failure_Parameter() {} void Authentication_Failure_Parameter::SetValue(const uint8_t
(&value)[kAuthenticationFailureParameterContentLength]) { for (int i = 0; i <
kAuthenticationFailureParameterContentLength; i++) { this->value_[i] = value[i];
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Authentication_Failure_Parameter::getValue(bstring& auts) { void Authentication_Failure_Parameter::GetValue(uint8_t
auts = bstrcpy(value); (&value)[kAuthenticationFailureParameterContentLength]) const{ for (int i = 0; i
< kAuthenticationFailureParameterContentLength; i++) { value[i] =
this->value_[i];
}
}
*/
//------------------------------------------------------------------------------
void Authentication_Failure_Parameter::SetValue(const bstring& value) {
value_ = bstrcpy(value);
SetLengthIndicator(blength(value));
}
//------------------------------------------------------------------------------
void Authentication_Failure_Parameter::GetValue(bstring& value) const {
value = bstrcpy(value_);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int Authentication_Failure_Parameter::Encode(uint8_t* buf, int len) { int Authentication_Failure_Parameter::Encode(uint8_t* buf, int len) {
Logger::nas_mm().debug( Logger::nas_mm().debug("Encoding %s", GetIeName().c_str());
"encoding Authentication_Failure_Parameter iei(0x%x)", _iei); int ie_len = GetIeLength();
if (len < length) {
Logger::nas_mm().error("len is less than %x", length); if (len < ie_len) {
return 0; Logger::nas_mm().error("Len is less than %d", ie_len);
return KEncodeDecodeError;
} }
int encoded_size = 0; int encoded_size = 0;
if (_iei) { // IEI and Length
*(buf + encoded_size) = _iei; int encoded_header_size = Type4NasIe::Encode(buf + encoded_size, len);
encoded_size++; if (encoded_header_size == KEncodeDecodeError) return KEncodeDecodeError;
*(buf + encoded_size) = length - 2; encoded_size += encoded_header_size;
encoded_size++;
int size = encode_bstring(value, (buf + encoded_size), len - encoded_size); // Value
encoded_size += size; /* for (int i = 0; i < kAuthenticationFailureParameterContentLength; i++) {
return encoded_size; ENCODE_U8(buf + encoded_size, value_[i], encoded_size);
} else {
// *(buf + encoded_size) = length - 1; encoded_size++;
// *(buf + encoded_size) = _value; encoded_size++; encoded_size++;
} }
*/
int size = encode_bstring(value_, (buf + encoded_size), len - encoded_size);
encoded_size += size;
Logger::nas_mm().debug( Logger::nas_mm().debug(
"Encoded Authentication_Failure_Parameter len (%d)", encoded_size); "Encoded %s, len (%d)", GetIeName().c_str(), encoded_size);
return encoded_size; return encoded_size;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int Authentication_Failure_Parameter::Decode( int Authentication_Failure_Parameter::Decode(
uint8_t* buf, int len, bool is_option) { uint8_t* buf, int len, bool is_iei) {
Logger::nas_mm().debug( uint8_t decoded_size = 0;
"Decoding Authentication_Failure_Parameter iei (0x%x)", *buf); uint8_t octet = 0;
int decoded_size = 0; Logger::nas_mm().debug("Decoding %s", GetIeName().c_str());
if (is_option) {
decoded_size++; // IEI and Length
} int decoded_header_size = Type4NasIe::Decode(buf + decoded_size, len, is_iei);
length = *(buf + decoded_size); if (decoded_header_size == KEncodeDecodeError) return KEncodeDecodeError;
decoded_size++; decoded_size += decoded_header_size;
Logger::nas_mm().debug(
"Decoded IE Authentication_Failure_Parameter length (%d)", length); if (GetLengthIndicator() != kAuthenticationFailureParameterContentLength)
decode_bstring(&value, length, (buf + decoded_size), len - decoded_size); return KEncodeDecodeError;
decoded_size += length;
for (int i = 0; i < length; i++) { // Value
Logger::nas_mm().debug( uint8_t ie_len = GetLengthIndicator();
"Decoded Authentication_Failure_Parameter value (0x%x)", decode_bstring(&value_, ie_len, (buf + decoded_size), len - decoded_size);
(uint8_t) value->data[i]); decoded_size += ie_len;
for (int i = 0; i < ie_len; i++) {
Logger::nas_mm().debug("Decoded value 0x%x", (uint8_t) value_->data[i]);
} }
Logger::nas_mm().debug( Logger::nas_mm().debug(
"Decoded Authentication_Failure_Parameter len (%d)", decoded_size); "Decoded %s, len (%d)", GetIeName().c_str(), decoded_size);
return decoded_size; return decoded_size;
} }
...@@ -19,41 +19,47 @@ ...@@ -19,41 +19,47 @@
* contact@openairinterface.org * contact@openairinterface.org
*/ */
/*! \file #ifndef _AUTHENTICATION_FAILURE_PARAMETER_H_
\brief #define _AUTHENTICATION_FAILURE_PARAMETER_H_
\author Keliang DU, BUPT
\date 2020 #include "Type4NasIe.hpp"
\email: contact@openairinterface.org
*/
#ifndef __Authentication_Failure_Parameter_H_
#define __Authentication_Failure_Parameter_H_
#include <stdint.h> #include <stdint.h>
#include <iostream>
extern "C" { extern "C" {
#include "TLVDecoder.h" #include "TLVDecoder.h"
#include "TLVEncoder.h" #include "TLVEncoder.h"
#include "bstrlib.h" #include "bstrlib.h"
} }
constexpr uint8_t kAuthenticationFailureParameterLength = 16;
constexpr uint8_t kAuthenticationFailureParameterContentLength =
kAuthenticationFailureParameterLength - 2;
constexpr auto kAuthenticationFailureParameterIeName = "5GMM Capability";
namespace nas { namespace nas {
class Authentication_Failure_Parameter { class Authentication_Failure_Parameter : public Type4NasIe {
public: public:
Authentication_Failure_Parameter(); Authentication_Failure_Parameter();
Authentication_Failure_Parameter(uint8_t iei); Authentication_Failure_Parameter(
Authentication_Failure_Parameter(const uint8_t iei, bstring auts); const uint8_t (&value)[kAuthenticationFailureParameterContentLength]);
Authentication_Failure_Parameter(const bstring& value);
~Authentication_Failure_Parameter(); ~Authentication_Failure_Parameter();
// void setValue(uint8_t iei, uint8_t value);
int Encode(uint8_t* buf, int len); int Encode(uint8_t* buf, int len);
int Decode(uint8_t* buf, int len, bool is_option); int Decode(uint8_t* buf, int len, bool is_iei);
void getValue(bstring& auts);
// void SetValue(const uint8_t
// (&value)[kAuthenticationFailureParameterContentLength]); void
// GetValue(uint8_t (&value)[kAuthenticationFailureParameterContentLength])
// const;
void SetValue(const bstring& value);
void GetValue(bstring& value) const;
private: private:
uint8_t _iei; // uint8_t value_[kAuthenticationFailureParameterContentLength];
uint8_t length; bstring value_;
bstring value;
}; };
} // namespace nas } // namespace nas
......
...@@ -104,6 +104,6 @@ int Authentication_Parameter_AUTN::Decode(uint8_t* buf, int len, bool is_iei) { ...@@ -104,6 +104,6 @@ int Authentication_Parameter_AUTN::Decode(uint8_t* buf, int len, bool is_iei) {
"Decoded Authentication_Parameter_AUTN value (0x%2x)", _value[j]); "Decoded Authentication_Parameter_AUTN value (0x%2x)", _value[j]);
} }
Logger::nas_mm().debug( Logger::nas_mm().debug(
"Decoded Authentication_Parameter_AUTN len (%d)", decoded_size); "Decoded %s, len (%d)", GetIeName().c_str(), decoded_size);
return decoded_size; return decoded_size;
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* For more information about the OpenAirInterface (OAI) Software Alliance: * For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org * contact@openairinterface.org
*/ */
#include "_5GMM_Cause.hpp" #include "_5gmmCause.hpp"
#include "3gpp_24.501.hpp" #include "3gpp_24.501.hpp"
#include "common_defs.h" #include "common_defs.h"
...@@ -26,44 +26,44 @@ ...@@ -26,44 +26,44 @@
using namespace nas; using namespace nas;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
_5GMM_Cause::_5GMM_Cause(uint8_t iei) : Type3NasIe(iei) { _5gmmCause::_5gmmCause(uint8_t iei) : Type3NasIe(iei) {
value_ = 0; value_ = 0;
SetIeName(k5gmmCauseIeName); SetIeName(k5gmmCauseIeName);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
_5GMM_Cause::_5GMM_Cause() : Type3NasIe() { _5gmmCause::_5gmmCause() : Type3NasIe() {
value_ = 0; value_ = 0;
SetIeName(k5gmmCauseIeName); SetIeName(k5gmmCauseIeName);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
_5GMM_Cause::_5GMM_Cause(uint8_t iei, uint8_t value) : Type3NasIe(iei) { _5gmmCause::_5gmmCause(uint8_t iei, uint8_t value) : Type3NasIe(iei) {
value_ = value; value_ = value;
SetIeName(k5gmmCauseIeName); SetIeName(k5gmmCauseIeName);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
_5GMM_Cause::~_5GMM_Cause(){}; _5gmmCause::~_5gmmCause(){};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void _5GMM_Cause::SetValue(uint8_t value) { void _5gmmCause::SetValue(uint8_t value) {
value_ = value; value_ = value;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
uint8_t _5GMM_Cause::GetValue() const { uint8_t _5gmmCause::GetValue() const {
return value_; return value_;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void _5GMM_Cause::Set(uint8_t iei, uint8_t value) { void _5gmmCause::Set(uint8_t iei, uint8_t value) {
SetIei(iei); SetIei(iei);
value_ = value; value_ = value;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int _5GMM_Cause::Encode(uint8_t* buf, int len) { int _5gmmCause::Encode(uint8_t* buf, int len) {
Logger::nas_mm().debug("Encoding %s", GetIeName().c_str()); Logger::nas_mm().debug("Encoding %s", GetIeName().c_str());
if (len < k5gmmCauseMaximumLength) { if (len < k5gmmCauseMaximumLength) {
...@@ -85,7 +85,7 @@ int _5GMM_Cause::Encode(uint8_t* buf, int len) { ...@@ -85,7 +85,7 @@ int _5GMM_Cause::Encode(uint8_t* buf, int len) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int _5GMM_Cause::Decode(uint8_t* buf, int len, bool is_iei) { int _5gmmCause::Decode(uint8_t* buf, int len, bool is_iei) {
Logger::nas_mm().debug("Decoding %s", GetIeName().c_str()); Logger::nas_mm().debug("Decoding %s", GetIeName().c_str());
if (len < k5gmmCauseMinimumLength) { if (len < k5gmmCauseMinimumLength) {
......
...@@ -74,12 +74,12 @@ constexpr auto k5gmmCauseIeName = "5GMM Cause"; ...@@ -74,12 +74,12 @@ constexpr auto k5gmmCauseIeName = "5GMM Cause";
namespace nas { namespace nas {
class _5GMM_Cause : public Type3NasIe { class _5gmmCause : public Type3NasIe {
public: public:
_5GMM_Cause(); _5gmmCause();
_5GMM_Cause(uint8_t iei); _5gmmCause(uint8_t iei);
_5GMM_Cause(uint8_t _iei, uint8_t value); _5gmmCause(uint8_t _iei, uint8_t value);
~_5GMM_Cause(); ~_5gmmCause();
int Encode(uint8_t* buf, int len); int Encode(uint8_t* buf, int len);
int Decode(uint8_t* buf, int len, bool is_iei); int Decode(uint8_t* buf, int len, bool is_iei);
......
...@@ -50,15 +50,34 @@ uint8_t AuthenticationFailure::get5GMmCause() { ...@@ -50,15 +50,34 @@ uint8_t AuthenticationFailure::get5GMmCause() {
return ie_5gmm_cause.GetValue(); return ie_5gmm_cause.GetValue();
} }
/*
//------------------------------------------------------------------------------
void AuthenticationFailure::setAuthentication_Failure_Parameter(
const uint8_t (&value)[kAuthenticationFailureParameterContentLength]) {
ie_authentication_failure_parameter =
std::make_optional<Authentication_Failure_Parameter>(value);
}
bool AuthenticationFailure::getAutsInAuthFailPara(uint8_t
(&value)[kAuthenticationFailureParameterContentLength]) const{ if
(ie_authentication_failure_parameter.has_value()) {
ie_authentication_failure_parameter.value().GetValue(value);
return true;
} else {
return false;
}
}
*/
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void AuthenticationFailure::setAuthentication_Failure_Parameter( void AuthenticationFailure::setAuthentication_Failure_Parameter(
const bstring& auts) { const bstring& value) {
ie_authentication_failure_parameter = ie_authentication_failure_parameter =
std::make_optional<Authentication_Failure_Parameter>(0x30, auts); std::make_optional<Authentication_Failure_Parameter>(value);
} }
bool AuthenticationFailure::getAutsInAuthFailPara(bstring& auts) {
bool AuthenticationFailure::getAutsInAuthFailPara(bstring& value) const {
if (ie_authentication_failure_parameter.has_value()) { if (ie_authentication_failure_parameter.has_value()) {
ie_authentication_failure_parameter.value().getValue(auts); ie_authentication_failure_parameter.value().GetValue(value);
return true; return true;
} else { } else {
return false; return false;
......
...@@ -39,11 +39,16 @@ class AuthenticationFailure : public NasMmPlainHeader { ...@@ -39,11 +39,16 @@ class AuthenticationFailure : public NasMmPlainHeader {
void Set5gmmCause(uint8_t value); void Set5gmmCause(uint8_t value);
uint8_t get5GMmCause(); uint8_t get5GMmCause();
void setAuthentication_Failure_Parameter(const bstring& auts); // void setAuthentication_Failure_Parameter(const uint8_t
bool getAutsInAuthFailPara(bstring& auts); // (&value)[kAuthenticationFailureParameterContentLength]); bool
// getAutsInAuthFailPara(uint8_t
// (&value)[kAuthenticationFailureParameterContentLength]) const;
void setAuthentication_Failure_Parameter(const bstring& value);
bool getAutsInAuthFailPara(bstring& value) const;
public: public:
_5GMM_Cause ie_5gmm_cause; // Mandatory _5gmmCause ie_5gmm_cause; // Mandatory
std::optional<Authentication_Failure_Parameter> std::optional<Authentication_Failure_Parameter>
ie_authentication_failure_parameter; // Optional ie_authentication_failure_parameter; // Optional
}; };
......
...@@ -74,7 +74,7 @@ void DLNASTransport::SetAdditionalInformation(const bstring& value) { ...@@ -74,7 +74,7 @@ void DLNASTransport::SetAdditionalInformation(const bstring& value) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void DLNASTransport::Set5gmmCause(uint8_t value) { void DLNASTransport::Set5gmmCause(uint8_t value) {
ie_5gmm_cause = std::make_optional<_5GMM_Cause>(0x58, value); ie_5gmm_cause = std::make_optional<_5gmmCause>(0x58, value);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
...@@ -238,13 +238,13 @@ int DLNASTransport::Decode(uint8_t* buf, int len) { ...@@ -238,13 +238,13 @@ int DLNASTransport::Decode(uint8_t* buf, int len) {
} break; } break;
case kIei5gmmCause: { case kIei5gmmCause: {
Logger::nas_mm().debug("Decoding IEI (0x58)"); Logger::nas_mm().debug("Decoding IEI (0x58)");
_5GMM_Cause ie_5gmm_cause_tmp = {}; _5gmmCause ie_5gmm_cause_tmp = {};
if ((decoded_result = ie_5gmm_cause_tmp.Decode( if ((decoded_result = ie_5gmm_cause_tmp.Decode(
buf + decoded_size, len - decoded_size, true)) == buf + decoded_size, len - decoded_size, true)) ==
KEncodeDecodeError) KEncodeDecodeError)
return decoded_result; return decoded_result;
decoded_size += decoded_result; decoded_size += decoded_result;
ie_5gmm_cause = std::optional<_5GMM_Cause>(ie_5gmm_cause_tmp); ie_5gmm_cause = std::optional<_5gmmCause>(ie_5gmm_cause_tmp);
octet = *(buf + decoded_size); octet = *(buf + decoded_size);
Logger::nas_mm().debug("Next IEI (0x%x)", octet); Logger::nas_mm().debug("Next IEI (0x%x)", octet);
} break; } break;
......
...@@ -58,7 +58,7 @@ class DLNASTransport : public NasMmPlainHeader { ...@@ -58,7 +58,7 @@ class DLNASTransport : public NasMmPlainHeader {
Payload_Container ie_payload_container; // Mandatory Payload_Container ie_payload_container; // Mandatory
std::optional<PduSessionIdentity2> ie_pdu_session_identity_2; // Optional std::optional<PduSessionIdentity2> ie_pdu_session_identity_2; // Optional
std::optional<AdditionalInformation> ie_additional_information; // Optional std::optional<AdditionalInformation> ie_additional_information; // Optional
std::optional<_5GMM_Cause> ie_5gmm_cause; // Optional std::optional<_5gmmCause> ie_5gmm_cause; // Optional
std::optional<GprsTimer3> ie_back_off_timer_value; // Optional std::optional<GprsTimer3> ie_back_off_timer_value; // Optional
}; };
......
...@@ -52,7 +52,7 @@ class RegistrationReject : public NasMmPlainHeader { ...@@ -52,7 +52,7 @@ class RegistrationReject : public NasMmPlainHeader {
// TODO: Get // TODO: Get
public: public:
_5GMM_Cause ie_5gmm_cause; // Mandatory _5gmmCause ie_5gmm_cause; // Mandatory
std::optional<GprsTimer2> ie_T3346_value; // Optional std::optional<GprsTimer2> ie_T3346_value; // Optional
std::optional<GprsTimer2> ie_T3502_value; // Optional std::optional<GprsTimer2> ie_T3502_value; // Optional
std::optional<EapMessage> ie_eap_message; // Optional std::optional<EapMessage> ie_eap_message; // Optional
......
...@@ -52,7 +52,7 @@ void SecurityModeReject::SetHeader(uint8_t security_header_type) { ...@@ -52,7 +52,7 @@ void SecurityModeReject::SetHeader(uint8_t security_header_type) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void SecurityModeReject::Set5gmmCause(uint8_t value) { void SecurityModeReject::Set5gmmCause(uint8_t value) {
ie_5gmm_cause = new _5GMM_Cause(0x00, value); ie_5gmm_cause = new _5gmmCause(0x00, value);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
...@@ -86,7 +86,7 @@ int SecurityModeReject::Decode( ...@@ -86,7 +86,7 @@ int SecurityModeReject::Decode(
Logger::nas_mm().debug("decoding SecurityModeReject message"); Logger::nas_mm().debug("decoding SecurityModeReject message");
int decoded_size = 3; int decoded_size = 3;
plain_header = header; plain_header = header;
ie_5gmm_cause = new _5GMM_Cause(); ie_5gmm_cause = new _5gmmCause();
decoded_size += decoded_size +=
ie_5gmm_cause->Decode(buf + decoded_size, len - decoded_size, false); ie_5gmm_cause->Decode(buf + decoded_size, len - decoded_size, false);
Logger::nas_mm().debug("decoded_size(%d)", decoded_size); Logger::nas_mm().debug("decoded_size(%d)", decoded_size);
......
...@@ -44,7 +44,7 @@ class SecurityModeReject { ...@@ -44,7 +44,7 @@ class SecurityModeReject {
public: public:
NasMmPlainHeader* plain_header; NasMmPlainHeader* plain_header;
_5GMM_Cause* ie_5gmm_cause; _5gmmCause* ie_5gmm_cause;
}; };
} // namespace nas } // namespace nas
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment