blob: 315a4d07d40bf32debd115b7463321e497503f19 [file] [log] [blame]
Alexander Couzens1c8785d2020-12-17 06:58:53 +01001/* test routines for NS connection handling
2 * (C) 2020 sysmocom - s.f.m.c. GmbH
3 * Author: Alexander Couzens <lynxis@fe80.eu>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#undef _GNU_SOURCE
9#define _GNU_SOURCE
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <stdint.h>
15#include <string.h>
16#include <getopt.h>
17#include <dlfcn.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20
21#include <osmocom/core/fsm.h>
22#include <osmocom/core/msgb.h>
Alexander Couzens47afc422021-01-17 20:12:46 +010023#include <osmocom/core/utils.h>
Alexander Couzens1c8785d2020-12-17 06:58:53 +010024#include <osmocom/core/application.h>
25#include <osmocom/core/utils.h>
26#include <osmocom/core/logging.h>
27#include <osmocom/core/socket.h>
28#include <osmocom/core/talloc.h>
29#include <osmocom/core/write_queue.h>
30#include <osmocom/gprs/gprs_msgb.h>
31#include <osmocom/gprs/gprs_ns2.h>
32#include <osmocom/gprs/gprs_bssgp.h>
33
34#include "../../src/gb/gprs_ns2_internal.h"
35
36int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
37{
38 return -1;
39}
40
41static struct log_info info = {};
42
43static int ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
44{
45 return 0;
46}
47
Alexander Couzens47afc422021-01-17 20:12:46 +010048static struct msgb *get_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
49{
50 struct gprs_ns_hdr *nsh;
51 struct osmo_wqueue *queue = bind->priv;
52
53 while (!llist_empty(&queue->msg_queue)) {
54 struct msgb *msg = msgb_dequeue(&queue->msg_queue);
55 nsh = (struct gprs_ns_hdr *) msg->l2h;
56 if (nsh->pdu_type == pdu_type)
57 return msg;
58 msgb_free(msg);
59 }
60
61 return NULL;
62}
63
64static bool find_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
65{
66 struct msgb *msg;
67 msg = get_pdu(bind, pdu_type);
68 if (msg) {
69 msgb_free(msg);
70 return true;
71 }
72
73 return false;
74}
75
Alexander Couzensaf5bfeb2021-01-17 20:12:37 +010076static void clear_pdus(struct gprs_ns2_vc_bind *bind)
Alexander Couzens1c8785d2020-12-17 06:58:53 +010077{
Alexander Couzensaf5bfeb2021-01-17 20:12:37 +010078 struct osmo_wqueue *queue = bind->priv;
79 osmo_wqueue_clear(queue);
Alexander Couzens1c8785d2020-12-17 06:58:53 +010080}
81
82struct gprs_ns2_vc_driver vc_driver_dummy = {
83 .name = "GB UDP dummy",
Alexander Couzensaf5bfeb2021-01-17 20:12:37 +010084 .free_bind = clear_pdus,
Alexander Couzens1c8785d2020-12-17 06:58:53 +010085};
86
87static int vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
88{
89 struct gprs_ns2_vc_bind *bind = nsvc->bind;
90 struct osmo_wqueue *queue = bind->priv;
91
92 osmo_wqueue_enqueue(queue, msg);
93 return 0;
94}
95
96static struct gprs_ns2_vc_bind *dummy_bind(struct gprs_ns2_inst *nsi, const char *name)
97{
98 struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
99 OSMO_ASSERT(bind);
100
101 bind->name = talloc_strdup(bind, name);
102 bind->driver = &vc_driver_dummy;
103 bind->ll = GPRS_NS2_LL_UDP;
104 bind->transfer_capability = 42;
105 bind->nsi = nsi;
106 bind->send_vc = vc_sendmsg;
107 bind->priv = talloc_zero(bind, struct osmo_wqueue);
108 struct osmo_wqueue *queue = bind->priv;
109
110 INIT_LLIST_HEAD(&bind->nsvc);
111 llist_add(&bind->list, &nsi->binding);
112 osmo_wqueue_init(queue, 100);
113
114 return bind;
115}
116
117void test_nse_transfer_cap(void *ctx)
118{
119 struct gprs_ns2_inst *nsi;
120 struct gprs_ns2_vc_bind *bind[2];
121 struct gprs_ns2_nse *nse;
122 struct gprs_ns2_vc *nsvc[3];
123
124 /* create a UDP dummy bind[0] with transfer cap 42.
125 * create nse (nsei 1001)
126 * create 2x nsvc with the same bind.
127 * nsvc[0] or nsvc[1] is alive (or both) cap == 42
128 *
129 * create a second bind with transfer cap == 23
130 * create 3rd nsvc with bind[1]
131 * transfer cap should be 42 + 23
132 */
133
134 printf("--- Testing NSE transfer cap\n");
135
136 printf("---- Create NSE + Binds\n");
137 nsi = gprs_ns2_instantiate(ctx, ns_prim_cb, NULL);
138 bind[0] = dummy_bind(nsi, "transfercap1");
139 bind[1] = dummy_bind(nsi, "transfercap2");
140 bind[1]->transfer_capability = 23;
141 nse = gprs_ns2_create_nse(nsi, 1001, GPRS_NS2_LL_UDP, NS2_DIALECT_STATIC_ALIVE);
142 OSMO_ASSERT(nse);
143
144 printf("---- Test with NSVC[0]\n");
Harald Welte603f4042020-11-29 17:39:19 +0100145 nsvc[0] = ns2_vc_alloc(bind[0], nse, false, NS2_VC_MODE_ALIVE, NULL);
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100146 OSMO_ASSERT(nsvc[0]);
147 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 0);
148 nsvc[0]->fi->state = 3; /* HACK: 3 = GPRS_NS2_ST_UNBLOCKED */
149 ns2_nse_notify_unblocked(nsvc[0], true);
150 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 42);
151
152 printf("---- Test with NSVC[1]\n");
Harald Welte603f4042020-11-29 17:39:19 +0100153 nsvc[1] = ns2_vc_alloc(bind[0], nse, false, NS2_VC_MODE_ALIVE, NULL);
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100154 OSMO_ASSERT(nsvc[1]);
155 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 42);
156 nsvc[1]->fi->state = 3; /* HACK: 3 = GPRS_NS2_ST_UNBLOCKED */
157 ns2_nse_notify_unblocked(nsvc[1], true);
158 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 42);
159
160 printf("---- Test with NSVC[2]\n");
Harald Welte603f4042020-11-29 17:39:19 +0100161 nsvc[2] = ns2_vc_alloc(bind[1], nse, false, NS2_VC_MODE_ALIVE, NULL);
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100162 OSMO_ASSERT(nsvc[2]);
163 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 42);
164 nsvc[2]->fi->state = 3; /* HACK: 3 = GPRS_NS2_ST_UNBLOCKED */
165 ns2_nse_notify_unblocked(nsvc[2], true);
166 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 42 + 23);
167
168 printf("---- Test with NSVC[1] removed\n");
169 /* reset nsvc[1] to be unconfigured - shouldn't change anything */
170 nsvc[1]->fi->state = 0; /* HACK: 0 = GPRS_NS2_ST_UNCONFIGURED */
171 ns2_nse_notify_unblocked(nsvc[1], false);
172 OSMO_ASSERT(ns2_count_transfer_cap(nse, 0) == 42 + 23);
173
Alexander Couzensaca31b82021-01-17 20:15:20 +0100174 gprs_ns2_free(nsi);
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100175 printf("--- Finish NSE transfer cap\n");
176
177}
178
Alexander Couzens47afc422021-01-17 20:12:46 +0100179/* setup NSE with 2x NSVCs.
180 * block 1x NSVC
181 * unblock 1x NSVC*/
182void test_block_unblock_nsvc(void *ctx)
183{
184 struct gprs_ns2_inst *nsi;
185 struct gprs_ns2_vc_bind *bind[2];
186 struct gprs_ns2_nse *nse;
187 struct gprs_ns2_vc *nsvc[2];
188 struct gprs_ns_hdr *nsh;
189 struct msgb *msg;
190 char idbuf[32];
191
192 printf("--- Testing NSE block unblock nsvc\n");
193 printf("---- Create NSE + Binds\n");
194 nsi = gprs_ns2_instantiate(ctx, ns_prim_cb, NULL);
195 bind[0] = dummy_bind(nsi, "bblock1");
196 bind[1] = dummy_bind(nsi, "bblock2");
197 nse = gprs_ns2_create_nse(nsi, 1001, GPRS_NS2_LL_UDP, NS2_DIALECT_STATIC_RESETBLOCK);
198 OSMO_ASSERT(nse);
199
200 for (int i=0; i<2; i++) {
201 printf("---- Create NSVC[i]\n");
202 snprintf(idbuf, sizeof(idbuf), "NSE%05u-dummy-%i", nse->nsei, i);
203 nsvc[i] = ns2_vc_alloc(bind[i], nse, false, NS2_VC_MODE_BLOCKRESET, idbuf);
204 OSMO_ASSERT(nsvc[i]);
205 nsvc[i]->fi->state = 3; /* HACK: 3 = GPRS_NS2_ST_UNBLOCKED */
206 /* ensure the fi->state works correct */
207 OSMO_ASSERT(gprs_ns2_vc_is_unblocked(nsvc[i]));
208 ns2_nse_notify_unblocked(nsvc[i], true);
209 }
210
211 /* both nsvcs are unblocked and alive. Let's block it. */
212 OSMO_ASSERT(!find_pdu(bind[0], NS_PDUT_BLOCK));
213 clear_pdus(bind[0]);
214 ns2_vc_block(nsvc[0]);
215 OSMO_ASSERT(find_pdu(bind[0], NS_PDUT_BLOCK));
216 /* state == BLOCKED */
217 clear_pdus(bind[0]);
218
219 /* now unblocking it */
220 ns2_vc_unblock(nsvc[0]);
221 OSMO_ASSERT(find_pdu(bind[0], NS_PDUT_UNBLOCK));
222 clear_pdus(bind[0]);
223
224 msg = msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "test_unblock");
225 msg->l2h = msgb_put(msg, sizeof(*nsh));
226 nsh = (struct gprs_ns_hdr *) msg->l2h;
227 nsh->pdu_type = NS_PDUT_UNBLOCK_ACK;
228 ns2_recv_vc(nsvc[0], msg);
229
230 OSMO_ASSERT(gprs_ns2_vc_is_unblocked(nsvc[0]));
231 gprs_ns2_free(nsi);
232 printf("--- Finish NSE block unblock nsvc\n");
233}
234
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100235int main(int argc, char **argv)
236{
237 void *ctx = talloc_named_const(NULL, 0, "gprs_ns2_test");
238 osmo_init_logging2(ctx, &info);
239 log_set_use_color(osmo_stderr_target, 0);
240 log_set_print_filename(osmo_stderr_target, 0);
241 log_set_print_filename(osmo_stderr_target, 0);
242 log_set_log_level(osmo_stderr_target, LOGL_INFO);
243 setlinebuf(stdout);
244
245 printf("===== NS2 protocol test START\n");
246 test_nse_transfer_cap(ctx);
Alexander Couzens47afc422021-01-17 20:12:46 +0100247 test_block_unblock_nsvc(ctx);
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100248 printf("===== NS2 protocol test END\n\n");
249
Alexander Couzense19b7962021-01-17 20:07:54 +0100250 talloc_free(ctx);
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100251 exit(EXIT_SUCCESS);
252}