Skip to content

Commit

Permalink
add type 2/3/4 parser. add parsing for MobileManagementDownlinkLocati…
Browse files Browse the repository at this point in the history
…onUpdateAccept
  • Loading branch information
marenz2569 committed Jul 4, 2024
1 parent aa56364 commit b2e53b1
Show file tree
Hide file tree
Showing 5 changed files with 393 additions and 0 deletions.
169 changes: 169 additions & 0 deletions include/l3/mobile_management_packet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#pragma once

#include "l3/mobile_link_entity_packet.hpp"
#include "utils/bit_vector.hpp"
#include "utils/type234_parser.hpp"
#include <bitset>
#include <optional>
#include <variant>

enum class MobileManagementDownlinkPacketType {
Expand Down Expand Up @@ -129,10 +133,175 @@ constexpr auto to_string(MobileManagementPacketType type) -> const char* {
return std::visit([](auto&& arg) { return to_string(arg); }, type);
}

enum class LocationUpdateType {
kRoamingLocationUpdating,
kMigrationLocationUpdating,
kPeriodicLocationUpdating,
kItsiAttach,
kServiceRestorationRoamingLocationUpdating,
kServiceRestorationMigratingLocationUpdating,
kDemandLocationUpdating,
kDisableMsUpdating,
};

constexpr auto to_string(LocationUpdateType type) -> const char* {
switch (type) {
case LocationUpdateType::kRoamingLocationUpdating:
return "Roaming location updating";
case LocationUpdateType::kMigrationLocationUpdating:
return "Migrating location updating";
case LocationUpdateType::kPeriodicLocationUpdating:
return "Periodic location updating";
case LocationUpdateType::kItsiAttach:
return "ITSI attach";
case LocationUpdateType::kServiceRestorationRoamingLocationUpdating:
return "Service restoration roaming location updating";
case LocationUpdateType::kServiceRestorationMigratingLocationUpdating:
return "Service restoration migrating location updating";
case LocationUpdateType::kDemandLocationUpdating:
return "Demand location updating";
case LocationUpdateType::kDisableMsUpdating:
return "Disabled MS updating";
}
};

enum class LocationUpdateAcceptType {
kRoamingLocationUpdating,
kTemporaryRegistration,
kPeriodicLocationUpdating,
kItsiAttach,
kServiceRestorationRoamingLocationUpdating,
kMigratingOrServiceRestorationMigratingLocationUpdating,
kDemandLocationUpdating,
kDisableMsUpdating,
};

constexpr auto to_string(LocationUpdateAcceptType type) -> const char* {
switch (type) {
case LocationUpdateAcceptType::kRoamingLocationUpdating:
return "Roaming location updating";
case LocationUpdateAcceptType::kTemporaryRegistration:
return "Temporary registration";
case LocationUpdateAcceptType::kPeriodicLocationUpdating:
return "Periodic location updating";
case LocationUpdateAcceptType::kItsiAttach:
return "ITSI attach";
case LocationUpdateAcceptType::kServiceRestorationRoamingLocationUpdating:
return "Service restoration roaming location updating";
case LocationUpdateAcceptType::kMigratingOrServiceRestorationMigratingLocationUpdating:
return "Migrating or service restoration migrating location updating";
case LocationUpdateAcceptType::kDemandLocationUpdating:
return "Demand location updating";
case LocationUpdateAcceptType::kDisableMsUpdating:
return "Disabled MS updating";
}
};

enum class MobileManagementDownlinkType34ElementIdentifiers {
kReservedForFutureExtension,
kDefaultGroupAttachLifetime,
kNewRegisteredArea,
kSecurityDownlink,
kGroupReportResponse,
kGroupIdentityLocationAccept,
kDmMsAddress,
kGroupIdentityDownlink,
kReserved8,
kReserved9,
kAuthenticationDownlink,
kReserved11,
kGroupIdentitySecurityRelatedInformation,
kCellTypeControl,
kReserved14,
kProprietary,
};

constexpr auto to_string(MobileManagementDownlinkType34ElementIdentifiers type) -> const char* {
switch (type) {
case MobileManagementDownlinkType34ElementIdentifiers::kReservedForFutureExtension:
return "Reserved for future extension";
case MobileManagementDownlinkType34ElementIdentifiers::kDefaultGroupAttachLifetime:
return "Default group attachment lifetime";
case MobileManagementDownlinkType34ElementIdentifiers::kNewRegisteredArea:
return "New registered area";
case MobileManagementDownlinkType34ElementIdentifiers::kSecurityDownlink:
return "Security downlink, see ETSI EN 300 392-7";
case MobileManagementDownlinkType34ElementIdentifiers::kGroupReportResponse:
return "Group report response";
case MobileManagementDownlinkType34ElementIdentifiers::kGroupIdentityLocationAccept:
return "Group identity location accept";
case MobileManagementDownlinkType34ElementIdentifiers::kDmMsAddress:
return "DM-MS address, see ETSI EN 300 396-5";
case MobileManagementDownlinkType34ElementIdentifiers::kGroupIdentityDownlink:
return "Group identity downlink";
case MobileManagementDownlinkType34ElementIdentifiers::kReserved8:
return "Reserved 8 for any future specified Type 3/4 element";
case MobileManagementDownlinkType34ElementIdentifiers::kReserved9:
return "Reserved 9 for any future specified Type 3/4 element";
case MobileManagementDownlinkType34ElementIdentifiers::kAuthenticationDownlink:
return "Authentication downlink, see ETSI EN 300 392-7";
case MobileManagementDownlinkType34ElementIdentifiers::kReserved11:
return "Reserved 11 for any future specified Type 3/4 element";
case MobileManagementDownlinkType34ElementIdentifiers::kGroupIdentitySecurityRelatedInformation:
return "Group Identity Security Related Information, see ETSI EN 300 392-7";
case MobileManagementDownlinkType34ElementIdentifiers::kCellTypeControl:
return "Cell type control";
case MobileManagementDownlinkType34ElementIdentifiers::kReserved14:
return "Reserved 14 for any future specified Type 3/4 element";
case MobileManagementDownlinkType34ElementIdentifiers::kProprietary:
return "Proprietary";
}
};

struct MobileManagementDownlinkLocationUpdateAccept {
LocationUpdateAcceptType location_update_accept_type_;
Address address_;
std::optional<unsigned _BitInt(16)> subscriber_class_;
std::optional<unsigned _BitInt(14)> energy_saving_information_;
std::optional<unsigned _BitInt(4)> scch_information_;
std::optional<unsigned _BitInt(2)> distribution_on_18th_frame_;

Type234Parser<MobileManagementDownlinkType34ElementIdentifiers>::Map optional_elements_;

MobileManagementDownlinkLocationUpdateAccept() = delete;

explicit MobileManagementDownlinkLocationUpdateAccept(BitVector&);
};

inline auto operator<<(std::ostream& stream, const MobileManagementDownlinkLocationUpdateAccept& packet)
-> std::ostream& {
stream << "D-LOCATION UPDATE ACCEPT " << to_string(packet.location_update_accept_type_) << std::endl;
if (packet.subscriber_class_) {
stream << " subscriber class: " << std::bitset<16>(*packet.subscriber_class_) << std::endl;
}
if (packet.energy_saving_information_) {
stream << " energy saving information: " << std::bitset<14>(*packet.energy_saving_information_) << std::endl;
}
if (packet.scch_information_) {
stream << " scch information: " << std::bitset<4>(*packet.scch_information_) << std::endl;
}
if (packet.distribution_on_18th_frame_) {
stream << " distribution on 18th frame: " << std::bitset<2>(*packet.distribution_on_18th_frame_) << std::endl;
}
for (const auto& [key, value] : packet.optional_elements_) {
stream << " " << to_string(key) << " " << value << std::endl;
}
return stream;
};

struct MobileManagementPacket : public MobileLinkEntityPacket {
MobileManagementPacketType packet_type_;
std::optional<MobileManagementDownlinkLocationUpdateAccept> downlink_location_update_accept_;

MobileManagementPacket() = delete;

explicit MobileManagementPacket(const MobileLinkEntityPacket& packet);
};

inline auto operator<<(std::ostream& stream, const MobileManagementPacket& packet) -> std::ostream& {
stream << "MM " << to_string(packet.packet_type_) << std::endl;
if (packet.downlink_location_update_accept_) {
stream << *packet.downlink_location_update_accept_;
}
return stream;
};
33 changes: 33 additions & 0 deletions include/utils/address.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,39 @@ class Address {
[[nodiscard]] auto smi() const noexcept { return smi_; }
[[nodiscard]] auto usage_marker() const noexcept { return usage_marker_; }

auto merge(const Address& other) {
if (other.country_code_) {
country_code_ = other.country_code_;
}
if (other.network_code_) {
network_code_ = other.network_code_;
}
if (other.sna_) {
sna_ = other.sna_;
}
if (other.ssi_) {
ssi_ = other.ssi_;
}
if (other.event_label_) {
event_label_ = other.event_label_;
}
if (other.ussi_) {
ussi_ = other.ussi_;
}
if (other.smi_) {
smi_ = other.smi_;
}
if (other.usage_marker_) {
usage_marker_ = other.usage_marker_;
}
};

auto merge(const std::optional<Address>& address) {
if (address) {
merge(*address);
}
}

friend auto operator<<(std::ostream& stream, const Address& address_type) -> std::ostream&;

private:
Expand Down
113 changes: 113 additions & 0 deletions include/utils/type234_parser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (C) 2024 Transit Live Mapping Solutions
* All rights reserved.
*
* Authors:
* Marenz Schmidl
*/

#pragma once

#include "utils/bit_vector.hpp"
#include <cstddef>
#include <map>
#include <optional>
#include <set>
#include <stdexcept>

template <std::size_t N> struct BitVectorElement {
public:
BitVectorElement() = delete;
explicit BitVectorElement(BitVector& data)
: x_(data.take<N>()){};

// NOLINTNEXTLINE(google-explicit-constructor)
operator unsigned _BitInt(N)() const noexcept { return x_; }

private:
unsigned _BitInt(N) x_;
};

template <typename ElementIdentifier> struct Type34Element {
BitVector unparsed_bits;
unsigned repeated_elements = 1;
};

template <typename ElementIdentifier>
inline auto operator<<(std::ostream& stream, const Type34Element<ElementIdentifier>& element) -> std::ostream& {
stream << "#" << element.repeated_elements << ": " << element.unparsed_bits;
return stream;
};

template <typename ElementIdentifier> class Type234Parser {
public:
using Map = std::map<ElementIdentifier, Type34Element<ElementIdentifier>>;

Type234Parser() = delete;

Type234Parser(BitVector& data, std::set<ElementIdentifier> allowed_type3_elements,
std::set<ElementIdentifier> allowed_type4_elements)
// Extract the O-bit
: present_(static_cast<bool>(data.take<1>()))
, allowed_type3_elements_(allowed_type3_elements)
, allowed_type4_elements_(allowed_type4_elements){};

template <typename T> auto parse_type2(BitVector& data) -> std::optional<T> {
if (!present_) {
return {};
}

std::optional<T> type2_element;
// P-bit present?
if (data.take<1>()) {
type2_element = T(data);
}
return type2_element;
}

auto parse_type34(BitVector& data) -> Map {
if (!present_) {
return {};
}

Map elements;

while (data.bits_left()) {
// M-bit present?
if (data.take<1>() == 0) {
break;
}
auto element_identifier = ElementIdentifier(data.take<4>());
auto length_indicator = data.take<11>();
// Is this a type 3 element?
if (allowed_type3_elements_.count(element_identifier)) {
const auto element_data = data.take_vector(length_indicator);
if (elements.count(element_identifier)) {
throw std::runtime_error("This element identifier already occured.");
}
elements[element_identifier] = Type34Element<ElementIdentifier>{.unparsed_bits = element_data};
continue;
}
// Is this a type 4 element?
if (allowed_type4_elements_.count(element_identifier)) {
const auto repeated_elements = data.take<6>();
const auto element_data = data.take_vector(length_indicator);
if (elements.count(element_identifier)) {
throw std::runtime_error("This element identifier already occured.");
}
elements[element_identifier] = Type34Element<ElementIdentifier>{.unparsed_bits = element_data,
.repeated_elements = repeated_elements};
continue;
}
// Is this element invalid?
throw std::runtime_error("This element identifier is not allowed in the current parser config.");
}

return elements;
}

private:
bool present_ = false;
std::set<ElementIdentifier> allowed_type3_elements_;
std::set<ElementIdentifier> allowed_type4_elements_;
};
4 changes: 4 additions & 0 deletions src/borzoi/borzoi_sender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "borzoi/borzoi_converter.hpp"
#include "l3/circuit_mode_control_entity_packet.hpp"
#include "l3/mobile_link_entity_packet.hpp"
#include "l3/mobile_management_packet.hpp"
#include "l3/short_data_service_packet.hpp"
#include <cpr/body.h>
#include <cpr/cprtypes.h>
Expand Down Expand Up @@ -110,6 +111,9 @@ void BorzoiSender::worker() {
std::cout << *sds;
}
}
if (auto* mm = dynamic_cast<MobileManagementPacket*>(llc)) {
std::cout << *mm;
}
std::cout << std::endl;
}
}
Expand Down
Loading

0 comments on commit b2e53b1

Please sign in to comment.