-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNASHelperS1AP_AttachRequest.cpp
More file actions
199 lines (179 loc) · 8.19 KB
/
NASHelperS1AP_AttachRequest.cpp
File metadata and controls
199 lines (179 loc) · 8.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#include "NASHelperS1AP.hpp"
#include <utility>
namespace {
bool appendTlvOptional(const std::uint8_t* ie,
std::size_t n,
std::size_t& i,
std::uint8_t expectedIei,
NASHelperS1AP::AttachRequestInformationElementsParse& out) {
if (i + 2U > n || ie[i] != expectedIei) {
return false;
}
const std::uint8_t len = ie[i + 1];
if (i + 2U + static_cast<std::size_t>(len) > n) {
return false;
}
NASHelperS1AP::AttachRequestOptionalInformationElement opt{};
opt.iei = expectedIei;
opt.encoding = NASHelperS1AP::AttachRequestOptionalInformationElement::Encoding::Tlv;
opt.value.assign(ie + i + 2U, ie + i + 2U + static_cast<std::size_t>(len));
out.optionals.push_back(std::move(opt));
i += 2U + static_cast<std::size_t>(len);
return true;
}
bool appendTvFixedOptional(const std::uint8_t* ie,
std::size_t n,
std::size_t& i,
std::uint8_t expectedIei,
std::size_t totalOctets,
NASHelperS1AP::AttachRequestInformationElementsParse& out) {
if (i + totalOctets > n || ie[i] != expectedIei) {
return false;
}
NASHelperS1AP::AttachRequestOptionalInformationElement opt{};
opt.iei = expectedIei;
opt.encoding = NASHelperS1AP::AttachRequestOptionalInformationElement::Encoding::TvFixed;
if (totalOctets > 1U) {
opt.value.assign(ie + i + 1U, ie + i + totalOctets);
}
out.optionals.push_back(std::move(opt));
i += totalOctets;
return true;
}
bool appendHalfOctetTvOptional(std::uint8_t b,
std::size_t& i,
NASHelperS1AP::AttachRequestInformationElementsParse& out) {
NASHelperS1AP::AttachRequestOptionalInformationElement opt{};
opt.iei = static_cast<std::uint8_t>(b & 0xF0U);
opt.encoding = NASHelperS1AP::AttachRequestOptionalInformationElement::Encoding::TvHalfOctetIei;
opt.tv_half_octet = b;
out.optionals.push_back(std::move(opt));
i += 1U;
return true;
}
/// TS 24.301 type 1 TV: IEI in bits 8–5 (single octet), table 8.2.4 optional half-octet tags.
bool isAttachRequestHalfOctetType1Tv(std::uint8_t b) {
const unsigned h = b >> 4U;
return h == 9U || h == 0xCU || h == 0xDU || h == 0xEU || h == 0xFU;
}
} // namespace
bool NASHelperS1AP::tryParseAttachRequestInformationElements(const std::uint8_t* const informationElements,
const std::size_t informationElementOctetCount,
AttachRequestInformationElementsParse& out) {
out = AttachRequestInformationElementsParse{};
if (informationElements == nullptr || informationElementOctetCount < 2U) {
return false;
}
std::size_t i = 0U;
out.mandatory.eps_attach_type_and_nas_key_set_identifier_octet = informationElements[i++];
const std::uint8_t mobileIdentityLen = informationElements[i++];
if (mobileIdentityLen == 0U || i + static_cast<std::size_t>(mobileIdentityLen) > informationElementOctetCount) {
return false;
}
out.mandatory.eps_mobile_identity_value = informationElements + i;
out.mandatory.eps_mobile_identity_value_octet_count = static_cast<std::size_t>(mobileIdentityLen);
i += static_cast<std::size_t>(mobileIdentityLen);
if (i >= informationElementOctetCount) {
return false;
}
const std::uint8_t ueCapLen = informationElements[i++];
if (i + static_cast<std::size_t>(ueCapLen) > informationElementOctetCount) {
return false;
}
out.mandatory.ue_network_capability_value = informationElements + i;
out.mandatory.ue_network_capability_value_octet_count = static_cast<std::size_t>(ueCapLen);
i += static_cast<std::size_t>(ueCapLen);
if (i + 2U > informationElementOctetCount) {
return false;
}
const std::uint16_t esmLen = static_cast<std::uint16_t>(
(static_cast<unsigned>(informationElements[i]) << 8U) | static_cast<unsigned>(informationElements[i + 1]));
i += 2U;
if (i + static_cast<std::size_t>(esmLen) > informationElementOctetCount) {
return false;
}
out.mandatory.esm_message_container_value = informationElements + i;
out.mandatory.esm_message_container_value_octet_count = static_cast<std::size_t>(esmLen);
i += static_cast<std::size_t>(esmLen);
out.mandatory.mandatory_total_octets = i;
out.ok = true;
while (i < informationElementOctetCount) {
const std::uint8_t b = informationElements[i];
bool consumed = false;
switch (b) {
case 0x19U:
consumed = appendTvFixedOptional(informationElements, informationElementOctetCount, i, 0x19U, 4U, out);
break;
case 0x50U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x50U, out);
break;
case 0x52U:
consumed = appendTvFixedOptional(informationElements, informationElementOctetCount, i, 0x52U, 6U, out);
break;
case 0x5CU:
consumed = appendTvFixedOptional(informationElements, informationElementOctetCount, i, 0x5CU, 3U, out);
break;
case 0x31U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x31U, out);
break;
case 0x13U:
consumed = appendTvFixedOptional(informationElements, informationElementOctetCount, i, 0x13U, 6U, out);
break;
case 0x11U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x11U, out);
break;
case 0x20U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x20U, out);
break;
case 0x40U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x40U, out);
break;
case 0x5DU:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x5DU, out);
break;
case 0x10U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x10U, out);
break;
case 0x6AU:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x6AU, out);
break;
case 0x5EU:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x5EU, out);
break;
case 0x6EU:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x6EU, out);
break;
case 0x6FU:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x6FU, out);
break;
case 0x6DU:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x6DU, out);
break;
case 0x17U:
consumed = appendTvFixedOptional(informationElements, informationElementOctetCount, i, 0x17U, 2U, out);
break;
case 0x35U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x35U, out);
break;
case 0x36U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x36U, out);
break;
case 0x38U:
consumed = appendTlvOptional(informationElements, informationElementOctetCount, i, 0x38U, out);
break;
default:
break;
}
if (consumed) {
continue;
}
if (isAttachRequestHalfOctetType1Tv(b)) {
appendHalfOctetTvOptional(b, i, out);
continue;
}
break;
}
out.unparsed_begin = informationElements + i;
out.unparsed_octet_count = informationElementOctetCount - i;
return true;
}