blob: 775ae43bb6b19d734c2c9429dce2e93720b235e4 [file] [log] [blame]
Jacob Erlbeckcdebf742014-10-14 14:49:37 +02001/* Test routines for the BSSGP implementation in libosmogb
2 *
Harald Weltee08da972017-11-13 01:00:26 +09003 * (C) 2014 by sysmocom - s.f.m.c. GmbH
Jacob Erlbeckcdebf742014-10-14 14:49:37 +02004 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * Skeleton based on bssgp_fc_test.c
7 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
Harald Weltee08da972017-11-13 01:00:26 +09008 *
9 * SPDX-License-Identifier: GPL-2.0+
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020010 */
11
12#undef _GNU_SOURCE
13#define _GNU_SOURCE
14
15#include <osmocom/core/application.h>
16#include <osmocom/core/utils.h>
17#include <osmocom/core/logging.h>
18#include <osmocom/core/talloc.h>
19#include <osmocom/core/prim.h>
20#include <osmocom/gprs/gprs_bssgp.h>
21#include <osmocom/gprs/gprs_ns.h>
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +020022#include <osmocom/gprs/gprs_bssgp_bss.h>
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020023
24#include <stdio.h>
25#include <stdlib.h>
26#include <stdint.h>
27#include <string.h>
28#include <getopt.h>
29#include <unistd.h>
30#include <netinet/ip.h>
Holger Hans Peter Freythere0a1a802014-10-25 12:19:56 +020031#include <sys/socket.h>
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020032#include <dlfcn.h>
33
34#define BSS_NSEI 0x0b55
35
36static struct osmo_prim_hdr last_oph = {0};
37
38/* override */
39ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
40 const struct sockaddr *dest_addr, socklen_t addrlen)
41{
42 typedef ssize_t (*sendto_t)(int, const void *, size_t, int,
43 const struct sockaddr *, socklen_t);
44 static sendto_t real_sendto = NULL;
45 uint32_t dest_host = htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
46
47 if (!real_sendto)
48 real_sendto = dlsym(RTLD_NEXT, "sendto");
49
Holger Hans Peter Freytherfdb46672015-11-09 16:32:43 +000050 fprintf(stderr, "MESSAGE to 0x%08x, msg length %zu\n%s\n",
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020051 dest_host, len, osmo_hexdump(buf, len));
52
53 return len;
54}
55
56/* override */
57int gprs_ns_callback(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
58 struct msgb *msg, uint16_t bvci)
59{
Holger Hans Peter Freytherfdb46672015-11-09 16:32:43 +000060 fprintf(stderr, "CALLBACK, event %d, msg length %td, bvci 0x%04x\n%s\n\n",
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020061 event, msgb_bssgp_len(msg), bvci,
62 osmo_hexdump(msgb_bssgph(msg), msgb_bssgp_len(msg)));
63 return 0;
64}
65
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +020066struct msgb *last_ns_tx_msg = NULL;
67
68/* override */
69int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg)
70{
71 msgb_free(last_ns_tx_msg);
72 last_ns_tx_msg = msg;
73
74 return msgb_length(msg);
75}
76
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020077int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
78{
79 printf("BSSGP primitive, SAP %d, prim = %d, op = %d, msg = %s\n",
80 oph->sap, oph->primitive, oph->operation, msgb_hexdump(oph->msg));
81
82 last_oph.sap = oph->sap;
83 last_oph.primitive = oph->primitive;
84 last_oph.operation = oph->operation;
85 last_oph.msg = NULL;
86 return -1;
87}
88
89static void msgb_bssgp_send_and_free(struct msgb *msg)
90{
91 msgb_nsei(msg) = BSS_NSEI;
92
93 bssgp_rcvmsg(msg);
94
95 msgb_free(msg);
96}
97
98static void send_bssgp_supend(enum bssgp_pdu_type pdu_type, uint32_t tlli)
99{
100 struct msgb *msg = bssgp_msgb_alloc();
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200101 uint8_t rai[] = {0x0f, 0xf1, 0x80, 0x20, 0x37, 0x00};
102
103 msgb_v_put(msg, pdu_type);
Maxe29ec852018-01-05 14:30:22 +0100104
105 bssgp_msgb_tlli_put(msg, tlli);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200106 msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, sizeof(rai), &rai[0]);
107
108 msgb_bssgp_send_and_free(msg);
109}
110
111static void send_bssgp_resume(enum bssgp_pdu_type pdu_type, uint32_t tlli)
112{
113 struct msgb *msg = bssgp_msgb_alloc();
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200114 uint8_t rai[] = {0x0f, 0xf1, 0x80, 0x20, 0x37, 0x00};
115 uint8_t suspend_ref = 1;
116
117 msgb_v_put(msg, pdu_type);
Maxe29ec852018-01-05 14:30:22 +0100118
119 bssgp_msgb_tlli_put(msg, tlli);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200120 msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, sizeof(rai), &rai[0]);
121 msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref);
122
123 msgb_bssgp_send_and_free(msg);
124}
125
126static void test_bssgp_suspend_resume(void)
127{
128 const uint32_t tlli = 0xf0123456;
129
130 printf("----- %s START\n", __func__);
131 memset(&last_oph, 0, sizeof(last_oph));
132
133 send_bssgp_supend(BSSGP_PDUT_SUSPEND, tlli);
Jacob Erlbeckb43baf22014-09-10 12:43:28 +0200134 OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_SUSPEND);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200135
136 send_bssgp_resume(BSSGP_PDUT_RESUME, tlli);
Jacob Erlbeckb43baf22014-09-10 12:43:28 +0200137 OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_RESUME);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200138
139 printf("----- %s END\n", __func__);
140}
141
Jacob Erlbeck36153dc2015-03-17 10:21:17 +0100142static void send_bssgp_status(enum gprs_bssgp_cause cause, uint16_t *bvci)
143{
144 struct msgb *msg = bssgp_msgb_alloc();
145 uint8_t cause_ = cause;
146
147 msgb_v_put(msg, BSSGP_PDUT_STATUS);
148 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause_);
149 if (bvci) {
150 uint16_t bvci_ = htons(*bvci);
151 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &bvci_);
152 }
153
154 msgb_bssgp_send_and_free(msg);
155}
156
157static void test_bssgp_status(void)
158{
159 uint16_t bvci;
160
161 printf("----- %s START\n", __func__);
162
163 send_bssgp_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL);
164 OSMO_ASSERT(last_oph.primitive == PRIM_NM_STATUS);
165
166 /* Enforce prim != PRIM_NM_STATUS */
167 last_oph.primitive = PRIM_NM_LLC_DISCARDED;
168
169 bvci = 1234;
170 send_bssgp_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci);
171 OSMO_ASSERT(last_oph.primitive == PRIM_NM_STATUS);
172
173 printf("----- %s END\n", __func__);
174}
175
Harald Weltee61d4592022-11-03 11:05:58 +0100176static void test_bssgp_bad_reset(void)
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200177{
Jacob Erlbeck2c581972015-06-18 11:51:34 +0200178 struct msgb *msg;
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200179 uint16_t bvci_be = htons(2);
180 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
181
Jacob Erlbeck2c581972015-06-18 11:51:34 +0200182 printf("----- %s START\n", __func__);
183 msg = bssgp_msgb_alloc();
184
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200185 msgb_v_put(msg, BSSGP_PDUT_BVC_RESET);
186 msgb_tvlv_put(msg, BSSGP_IE_BVCI, sizeof(bvci_be), (uint8_t *)&bvci_be);
187 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, sizeof(cause), &cause);
188
189 msgb_bvci(msg) = 0xbad;
190
191 msgb_bssgp_send_and_free(msg);
Jacob Erlbeck2c581972015-06-18 11:51:34 +0200192
193 printf("----- %s END\n", __func__);
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200194}
195
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +0200196static void test_bssgp_flow_control_bvc(void)
197{
198 struct bssgp_bvc_ctx bctx = {
199 .nsei = 0x1234,
200 .bvci = 0x5678,
201 };
202 const uint8_t tag = 42;
203 const uint32_t bmax = 0x1022 * 100;
204 const uint32_t rate = 0xc040 / 8 * 100;
205 const uint32_t bmax_ms = bmax / 2;
206 const uint32_t rate_ms = rate / 2;
207 uint8_t ratio = 0x78;
208 uint32_t qdelay = 0x1144 * 10;
209 int rc;
210
211 static uint8_t expected_simple_msg[] = {
212 0x26,
213 0x1e, 0x81, 0x2a, /* tag */
214 0x05, 0x82, 0x10, 0x22, /* Bmax */
215 0x03, 0x82, 0xc0, 0x40, /* R */
216 0x01, 0x82, 0x08, 0x11, /* Bmax_MS */
217 0x1c, 0x82, 0x60, 0x20, /* R_MS */
218 };
219
220 static uint8_t expected_ext_msg[] = {
221 0x26,
222 0x1e, 0x81, 0x2a, /* tag */
223 0x05, 0x82, 0x10, 0x22, /* Bmax */
224 0x03, 0x82, 0xc0, 0x40, /* R */
225 0x01, 0x82, 0x08, 0x11, /* Bmax_MS */
226 0x1c, 0x82, 0x60, 0x20, /* R_MS */
227 0x3c, 0x81, 0x78, /* ratio */
228 0x06, 0x82, 0x11, 0x44, /* Qdelay */
229 };
230
231 printf("----- %s START\n", __func__);
232
233 rc = bssgp_tx_fc_bvc(&bctx, tag, bmax, rate, bmax_ms, rate_ms,
234 NULL, NULL);
235
236 OSMO_ASSERT(rc >= 0);
237 OSMO_ASSERT(last_ns_tx_msg != NULL);
238 printf("Got message: %s\n", msgb_hexdump(last_ns_tx_msg));
239 OSMO_ASSERT(msgb_length(last_ns_tx_msg) == sizeof(expected_simple_msg));
240 OSMO_ASSERT(0 == memcmp(msgb_data(last_ns_tx_msg),
241 expected_simple_msg, sizeof(expected_simple_msg)));
242
243 rc = bssgp_tx_fc_bvc(&bctx, tag, bmax, rate, bmax_ms, rate_ms,
244 &ratio, &qdelay);
245
246 OSMO_ASSERT(rc >= 0);
247 OSMO_ASSERT(last_ns_tx_msg != NULL);
248 printf("Got message: %s\n", msgb_hexdump(last_ns_tx_msg));
249 OSMO_ASSERT(msgb_length(last_ns_tx_msg) == sizeof(expected_ext_msg));
250 OSMO_ASSERT(0 == memcmp(msgb_data(last_ns_tx_msg),
251 expected_ext_msg, sizeof(expected_ext_msg)));
252
253 msgb_free(last_ns_tx_msg);
254 last_ns_tx_msg = NULL;
255
256 printf("----- %s END\n", __func__);
257}
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200258
Harald Weltee61d4592022-11-03 11:05:58 +0100259static void test_bssgp_msgb_copy(void)
Jacob Erlbeckf78ec5c2015-11-17 09:53:23 +0100260{
261 struct msgb *msg, *msg2;
262 uint16_t bvci_be = htons(2);
263 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
264
265 printf("----- %s START\n", __func__);
266 msg = bssgp_msgb_alloc();
267
268 msg->l3h = msgb_data(msg);
269 msgb_v_put(msg, BSSGP_PDUT_BVC_RESET);
270 msgb_tvlv_put(msg, BSSGP_IE_BVCI, sizeof(bvci_be), (uint8_t *)&bvci_be);
271 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, sizeof(cause), &cause);
272
273 msgb_bvci(msg) = 0xbad;
274 msgb_nsei(msg) = 0xbee;
275
276 printf("Old msgb: %s\n", msgb_hexdump(msg));
277 msg2 = bssgp_msgb_copy(msg, "test");
278 printf("New msgb: %s\n", msgb_hexdump(msg2));
279
280 OSMO_ASSERT(msgb_bvci(msg2) == 0xbad);
281 OSMO_ASSERT(msgb_nsei(msg2) == 0xbee);
282 OSMO_ASSERT(msgb_l3(msg2) == msgb_data(msg2));
283 OSMO_ASSERT(msgb_bssgph(msg2) == msgb_data(msg2));
284 OSMO_ASSERT(msgb_bssgp_len(msg2) == msgb_length(msg2));
285
286 msgb_free(msg);
287 msgb_free(msg2);
288
289 printf("----- %s END\n", __func__);
290}
291
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200292static struct log_info info = {};
293
294int main(int argc, char **argv)
295{
296 struct sockaddr_in bss_peer= {0};
Neels Hofmeyra829b452018-04-05 03:02:35 +0200297 void *ctx = talloc_named_const(NULL, 0, "gprs_bssgp_test");
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200298
Neels Hofmeyra829b452018-04-05 03:02:35 +0200299 osmo_init_logging2(ctx, &info);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200300 log_set_use_color(osmo_stderr_target, 0);
Pau Espin Pedrol01e0d3e2021-02-18 19:25:44 +0100301 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200302
Neels Hofmeyra829b452018-04-05 03:02:35 +0200303 msgb_talloc_ctx_init(ctx, 0);
304
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200305 bssgp_nsi = gprs_ns_instantiate(gprs_ns_callback, NULL);
306
307 bss_peer.sin_family = AF_INET;
308 bss_peer.sin_port = htons(32000);
309 bss_peer.sin_addr.s_addr = htonl(0x7f0000ff);
310
311 gprs_ns_nsip_connect(bssgp_nsi, &bss_peer, BSS_NSEI, BSS_NSEI+1);
312
313
314 printf("===== BSSGP test START\n");
315 test_bssgp_suspend_resume();
Jacob Erlbeck36153dc2015-03-17 10:21:17 +0100316 test_bssgp_status();
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200317 test_bssgp_bad_reset();
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +0200318 test_bssgp_flow_control_bvc();
Jacob Erlbeckf78ec5c2015-11-17 09:53:23 +0100319 test_bssgp_msgb_copy();
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200320 printf("===== BSSGP test END\n\n");
321
322 exit(EXIT_SUCCESS);
323}