aboutsummaryrefslogtreecommitdiffstats
path: root/library/Osmocom_VTY_Functions.ttcn
blob: a1724e919213a9c6104ce1f16d9faf797863cb52 (plain)
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
/* Osmocom VTY interface functions in TTCN-3
 * (C) 2017-2018 Harald Welte <laforge@gnumonks.org>
 * contributions by sysmocom - s.f.m.c. GmbH
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

module Osmocom_VTY_Functions {
	import from TELNETasp_PortType all;
	import from Osmocom_Types all;

	modulepar {
		charstring mp_prompt_prefix := "OpenBSC";
	}

	const charstring VTY_VIEW_SUFFIX := "> ";
	const charstring VTY_ENABLE_SUFFIX := "# ";
	const charstring VTY_CFG_SUFFIX := "(*)";

	template charstring t_vty_unknown := pattern "*% Unknown command.";

	/* configure prompts in TELNETasp module */
	function f_vty_set_prompts(TELNETasp_PT pt, charstring prompt_prefix := mp_prompt_prefix) {
		var ASP_TelnetDynamicConfig vty_prompt[3] := {
			{
				prompt := {
					id := 1,
					prompt := prompt_prefix & VTY_VIEW_SUFFIX,
					has_wildcards := false
				}
			}, {
				prompt := {
					id := 2,
					prompt := prompt_prefix & VTY_ENABLE_SUFFIX,
					has_wildcards := false
				}
			}, {
				prompt := {
					id := 3,
					prompt := prompt_prefix & VTY_CFG_SUFFIX,
					has_wildcards := true
				}
			}
		};

		/* set some configuration that isn't possible to express
		 * in the config file due to syntactic restrictions (Who invents config
		 * files that don't permit regular expressions? */
		for (var integer i := 0; i < sizeof(vty_prompt); i:= i + 1) {
			pt.send(vty_prompt[i]);
		}
	}

	/* wait for any of the permitted prompts; buffer + return all intermediate output */
	function f_vty_wait_for_prompt(TELNETasp_PT pt) return charstring {
		var charstring rx, buf := "";
		var integer fd;
		timer T := 2.0;

		T.start;
		alt {
			[] pt.receive(pattern "[\w-]+" & VTY_VIEW_SUFFIX) { };
			[] pt.receive(pattern "[\w-]+\# ") { };
			[] pt.receive(pattern "[\w-]+\(*\)\# ") { };
			[] pt.receive(t_vty_unknown) {
				testcase.stop(fail, "VTY: Unknown Command");
				};
			[] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat };
			[] pt.receive(integer:?) -> value fd {
				if (fd == -1) {
					setverdict(fail, "VTY Telnet Connection Failure");
					mtc.stop;
				} else {
					repeat; /* telnet connection succeeded */
				}
			}
			[] T.timeout {
				setverdict(fail, "VTY Timeout for prompt");
				mtc.stop;
				};
		}
		T.stop;
		return buf;
	}

	/* send a VTY command and obtain response until prompt is received */
	function f_vty_transceive_ret(TELNETasp_PT pt, charstring tx) return charstring {
		pt.send(tx);
		return f_vty_wait_for_prompt(pt);
	}

	/* send a VTY command and obtain response until prompt is received */
	function f_vty_transceive(TELNETasp_PT pt, charstring tx) {
		var charstring unused := f_vty_transceive_ret(pt, tx);
	}

	type integer BtsNr (0..255);
	type integer BtsTrxNr (0..255);
	type integer BtsTimeslotNr (0..7);
	type integer MscNr (0..255);

	type charstring BtsGprsMode ("none", "gprs", "egrps");

	/* enter the'confiugration' mode of the VTY */
	function f_vty_enter_config(TELNETasp_PT pt) {
		f_vty_transceive(pt, "configure terminal")
	}

	function f_vty_enter_cfg_network(TELNETasp_PT pt) {
		f_vty_enter_config(pt);
		f_vty_transceive(pt, "network")
	}

	function f_vty_enter_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0) {
		f_vty_enter_cfg_network(pt);
		f_vty_transceive(pt, "bts " & int2str(bts));
	}

	function f_vty_enter_cfg_trx(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0) {
		f_vty_enter_cfg_bts(pt, bts);
		f_vty_transceive(pt, "trx " & int2str(trx));
	}

	function f_vty_enter_cfg_ts(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0, BtsTimeslotNr ts) {
		f_vty_enter_cfg_trx(pt, bts, trx);
		f_vty_transceive(pt, "timeslot " & int2str(ts));
	}

	function f_vty_enter_cfg_msc(TELNETasp_PT pt, MscNr msc := 0) {
		f_vty_enter_config(pt);
		f_vty_transceive(pt, "msc " & int2str(msc));
	}

type record of charstring rof_charstring;
function f_vty_config2(TELNETasp_PT pt, rof_charstring config_nodes, charstring cmd)
{
	/* enter config mode; enter node */
	f_vty_enter_config(pt);
	for (var integer i := 0; i < sizeof(config_nodes); i := i+1) {
		f_vty_transceive(pt, config_nodes[i]);
	}
	/* execute command */
	f_vty_transceive(pt, cmd);
	/* leave config mode */
	f_vty_transceive(pt, "end");
}


function f_vty_config(TELNETasp_PT pt, charstring config_node, charstring cmd)
{
	f_vty_config2(pt, {config_node}, cmd);
}

function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
	var charstring ret := f_vty_transceive_ret(pt, cmd);
	if (not match(ret, exp_ret)) {
		setverdict(fail, "Non-matching VTY response: ", ret);
		mtc.stop;
	}
}

function f_vty_transceive_not_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
	var charstring ret := f_vty_transceive_ret(pt, cmd);
	if (match(ret, exp_ret)) {
		setverdict(fail, "Unexpected matching VTY response: ", ret);
		mtc.stop;
	}
}

function f_vty_transceive_match_regex(TELNETasp_PT pt, charstring cmd, charstring regex, integer groupno) return charstring
{
	var charstring resp := f_vty_transceive_ret(pt, cmd);
	return regexp(resp, regex, groupno);
}

function f_vty_transceive_match_regexp_retry(TELNETasp_PT pt, charstring cmd, charstring regex,
					     integer groupno, integer num_attempts, float retry_delay) return charstring
{
	 while (num_attempts > 0) {
		var charstring ret := f_vty_transceive_match_regex(pt, cmd, regex, groupno);
		if (ret != "") {
			return ret;
		}
		f_sleep(retry_delay);
		num_attempts := num_attempts - 1;
	}

	setverdict(fail, "No matching VTY response for regular expression '", regex,
		   "' after ", num_attempts, " attempts." );
	mtc.stop;
}

}