提取3GPP LTE/5GNR中RRC的ASN.1

本文介绍了如何从 3GPP 36.331 或者 38.331 中提取出 RRC 中的 ASN.1 部分抽象描述内容。

ASN.1 标准简介

在电信和计算机网络领域,ASN.1Abstract Syntax Notation One) 是一套标准,是描述数据、编码、传输、解码的灵活的抽象语义记法。它提供了一套正式、无歧义和精确的规则以描述独立于特定计算机硬件的对象结构。


ASN.1 标准下载

描述ASN.1记法的标准:

  • ITU-T Rec. X.680 | ISO/IEC 8824-1

  • ITU-T Rec. X.681 | ISO/IEC 8824-2

  • ITU-T Rec. X.682 | ISO/IEC 8824-3

  • ITU-T Rec. X.683 | ISO/IEC 8824-4

从ITU-T网站免费下载

描述ASN.1编码规则的标准

  • ITU-T Rec. X.690 | ISO/IEC 8825-1 (BER, CER and DER)
  • ITU-T Rec. X.691 | ISO/IEC 8825-2 (PER)
  • ITU-T Rec. X.692 | ISO/IEC 8825-3 (ECN)
  • ITU-T Rec. X.693 | ISO/IEC 8825-4 (XER)

ASN.1标准列表

关于 ASN.1的标准,可以在 ISO/ITU-T 中找到关于本部分标准的链接,打开 http://www.itu.int/ITU-T/recommendations/index.aspx 在 search 栏输入 x.680~x.683 或 x.690 可以查看到 ASN.1 的具体标准及编解码的方法,或者从 http://www.itu.int/ITU-T/studygroups/com17/languages/ 获得相关文档


范例

FooProtocol 结构的定义系使用 ASN.1 表示法:

1
2
3
4
5
6
7
8
9
10
11
12
13
FooProtocol DEFINITIONS ::= BEGIN

FooQuestion ::= SEQUENCE {
trackingNumber INTEGER,
question IA5String
}

FooAnswer ::= SEQUENCE {
questionNumber INTEGER,
answer BOOLEAN
}

END

ASN.1没有定义的谈话流动。 这是协议的文本描述。

假设消息,符合与foo的协议将被发送到接收方。这种特定的消息(PDU):

1
2
3
4
myQuestion FooQuestion ::= {
trackingNumber 5,
question "Anybody there?"
}

要通过网络发送上述消息,需要编码成位元字串(string of bits)。ASN.1定义了不同的算法来完成这项任务,被称为编码规则。有很多,最简单的一个是DER.

Foo协议规范应明确名称一套编码规则的使用,Foo的协议,使用者 知道他们应该使用哪一个。


下载3GPP协议

打开https://www.3gpp.org/ftp/Specs/archive

比如下载 38.331

5G NR 的无线资源控制(RRC)协议是 38.331

LTE 的无线资源控制(RRC)协议是 36.331


协议中的 ASN.1 描述长这个样子 😎

当然你可以手动复制粘贴出来,但是这样效率低下,浪费时间。因此推荐使用工具或者自己用代码来提取。具体方法请继续往下看哦 🌱


转换工具下载

https://github.com/Dybinx/txt2asn1 中下载 txt2asn1

下载好的工具 txt2asn1.exe


开始转换为 ASN.1

下载好 38.331或者36.331,在 word 中打开协议,选择另存为,将其保存为 TXT 格式。

另存为txt

在 txt2asn1 所在的路径下打开终端,输入:

1
txt2asn1.exe 待转换txt文件路径

就能转换得到 ASN1文件了。

比如我输入:

1
txt2asn1.exe 36331-g00.txt

就能获得 36331-g00.asn1 文件了。

转换成功


VS Code 打开生成的文件看一看 ,效果美滋滋 🍦

image-20200529120447300

推荐在 VS Code 中安装 ASN.1 VS Code Extension ,格式化后的 ASN.1 即美观又方便查看。

安装的拓展

阅读过程中,可以按住 Ctrl 然后点击鼠标左键,就能实现在一些配置信息之间跳转。

跳转示例


转换ASN.1-方式二

新建一个 C++ 项目 ,在 main.cpp 中粘贴如下的代码。注意把 input_file 的路径改一下。代码来自 peng_yw

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
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;


int main()

{
std::string output_file;

std::string input_file = "D:/Project_codeing/VisualStudio/Cplusplus/3GPP-ASN.1/Get-3GPP-ASN.1/Files/36331-g00.txt";

std::cout << input_file.c_str() << std::endl;

int pos = input_file.find('.');

if (pos == std::string::npos)

{

output_file = input_file + ".asn1";

}

else

{
output_file = input_file + "_.asn1";
// output_file = input_file.substr(0, pos) + ".asn1";

}



std::fstream input;

input.open(input_file.c_str(), std::fstream::in);

if (input.fail() == true)

{

std::cout << "Please check input file is correct !" << std::endl;

return 1;

}


std::fstream output;

output.open(output_file.c_str(), std::fstream::out);

if (output.fail() == true)

{

std::cout << "The output file can not be created here !" << std::endl;

return 1;

}


std::string input_line;

std::vector<std::string > vec_asn;

std::vector<std::string >::iterator itr;


const unsigned long cul_asn_idle = 0x0;

const unsigned long cul_asn_start = 0x1;


unsigned long asn_state = cul_asn_idle;


while (std::getline(input, input_line))

{

if (cul_asn_idle == asn_state)

{

if (input_line.find("-- ASN1START") != std::string::npos)

{

asn_state |= cul_asn_start;

}



continue;

}



if (0 != (cul_asn_start & asn_state))

{

if (input_line.find("-- ASN1STOP") != std::string::npos)

{

asn_state = cul_asn_idle;

}

else

{

vec_asn.push_back(input_line);

}

}

}



for (itr = vec_asn.begin(); itr != vec_asn.end(); ++itr)

{

output << *itr << std::endl;

}



input.close();

output.close();

return 0;

}

当然可以把输入参数那里不要固定死,弄成一个输入参数的程序,这样在命令行中使用的话也会很方便的。

编译项目后运行,然后就会在 input_file 的路径下产生一个后缀为 .asn1的文件。

生成的示例

利用开源ASN1C库实现asn.1的编解码,生成C代码

http://lionet.info/asn1c/download.html 中下载 Windows installer ,然后安装。

关于详细的使用方式可以在项目地址中查看到:https://github.com/vlm/asn1c 。关于这个编译器的详细的文档在 doc / asn1c-usage.pdf 中。

快速使用

在安装编译器(请参阅 INSTALL.md)之后,您可以使用 asn1c 命令编译 ASN. 1规范:

1
asn1c <module.asn1>                         # Compile module

如果多个规范包含相互依赖关系,则必须同时指定所有规范:

1
asn1c <module1.asn1> <module2.asn1> ...     # Compile interdependent modules

实际测试

samples 文件夹下有 ASN.1 示例文件,就让我来测试一下吧。

这是我的目录结构

输入以下命令行

1
asn1c -P ./samples/rfc3280-*.asn1

在本例中,-P选项用于在标准输出上打印编译后的文本。 默认行为是asn1c编译器为在指定ASN.1模块中找到的每个ASN.1类型创建多个.c和.h文件。

这样就打印出来了:

打印

在使用说明 asn1c-usage.pdf 中有其他使用的示例。

比如输入:

1
asn1c ./samples/rfc3280-*.asn1

编译

编译成功,可以看到已经产生了很多的 .c.h 文件。

编译后生成的c代码




《小池》

杨万里

泉眼无声惜细流,树阴照水爱晴柔。
小荷才露尖尖角,早有蜻蜓立上头。

🍉