blob: 707b64bf2765f8241c71f42ff83df767b91a3dbe [file] [log] [blame]
Jacob Erlbeckcdebf742014-10-14 14:49:37 +02001/* Test routines for the BSSGP implementation in libosmogb
2 *
3 * (C) 2014 by sysmocom s.f.m.c. GmbH
4 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * Skeleton based on bssgp_fc_test.c
7 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
8 */
9
10#undef _GNU_SOURCE
11#define _GNU_SOURCE
12
13#include <osmocom/core/application.h>
14#include <osmocom/core/utils.h>
15#include <osmocom/core/logging.h>
16#include <osmocom/core/talloc.h>
17#include <osmocom/core/prim.h>
18#include <osmocom/gprs/gprs_bssgp.h>
19#include <osmocom/gprs/gprs_ns.h>
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +020020#include <osmocom/gprs/gprs_bssgp_bss.h>
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020021
22#include <stdio.h>
23#include <stdlib.h>
24#include <stdint.h>
25#include <string.h>
26#include <getopt.h>
27#include <unistd.h>
28#include <netinet/ip.h>
Holger Hans Peter Freythere0a1a802014-10-25 12:19:56 +020029#include <sys/socket.h>
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020030#include <dlfcn.h>
31
32#define BSS_NSEI 0x0b55
33
34static struct osmo_prim_hdr last_oph = {0};
35
36/* override */
37ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
38 const struct sockaddr *dest_addr, socklen_t addrlen)
39{
40 typedef ssize_t (*sendto_t)(int, const void *, size_t, int,
41 const struct sockaddr *, socklen_t);
42 static sendto_t real_sendto = NULL;
43 uint32_t dest_host = htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
44
45 if (!real_sendto)
46 real_sendto = dlsym(RTLD_NEXT, "sendto");
47
Holger Hans Peter Freytherfdb46672015-11-09 16:32:43 +000048 fprintf(stderr, "MESSAGE to 0x%08x, msg length %zu\n%s\n",
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020049 dest_host, len, osmo_hexdump(buf, len));
50
51 return len;
52}
53
54/* override */
55int gprs_ns_callback(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
56 struct msgb *msg, uint16_t bvci)
57{
Holger Hans Peter Freytherfdb46672015-11-09 16:32:43 +000058 fprintf(stderr, "CALLBACK, event %d, msg length %td, bvci 0x%04x\n%s\n\n",
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020059 event, msgb_bssgp_len(msg), bvci,
60 osmo_hexdump(msgb_bssgph(msg), msgb_bssgp_len(msg)));
61 return 0;
62}
63
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +020064struct msgb *last_ns_tx_msg = NULL;
65
66/* override */
67int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg)
68{
69 msgb_free(last_ns_tx_msg);
70 last_ns_tx_msg = msg;
71
72 return msgb_length(msg);
73}
74
Jacob Erlbeckcdebf742014-10-14 14:49:37 +020075int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
76{
77 printf("BSSGP primitive, SAP %d, prim = %d, op = %d, msg = %s\n",
78 oph->sap, oph->primitive, oph->operation, msgb_hexdump(oph->msg));
79
80 last_oph.sap = oph->sap;
81 last_oph.primitive = oph->primitive;
82 last_oph.operation = oph->operation;
83 last_oph.msg = NULL;
84 return -1;
85}
86
87static void msgb_bssgp_send_and_free(struct msgb *msg)
88{
89 msgb_nsei(msg) = BSS_NSEI;
90
91 bssgp_rcvmsg(msg);
92
93 msgb_free(msg);
94}
95
96static void send_bssgp_supend(enum bssgp_pdu_type pdu_type, uint32_t tlli)
97{
98 struct msgb *msg = bssgp_msgb_alloc();
99 uint32_t tlli_be = htonl(tlli);
100 uint8_t rai[] = {0x0f, 0xf1, 0x80, 0x20, 0x37, 0x00};
101
102 msgb_v_put(msg, pdu_type);
103 msgb_tvlv_put(msg, BSSGP_IE_TLLI, sizeof(tlli_be), (uint8_t *)&tlli_be);
104 msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, sizeof(rai), &rai[0]);
105
106 msgb_bssgp_send_and_free(msg);
107}
108
109static void send_bssgp_resume(enum bssgp_pdu_type pdu_type, uint32_t tlli)
110{
111 struct msgb *msg = bssgp_msgb_alloc();
112 uint32_t tlli_be = htonl(tlli);
113 uint8_t rai[] = {0x0f, 0xf1, 0x80, 0x20, 0x37, 0x00};
114 uint8_t suspend_ref = 1;
115
116 msgb_v_put(msg, pdu_type);
117 msgb_tvlv_put(msg, BSSGP_IE_TLLI, sizeof(tlli_be), (uint8_t *)&tlli_be);
118 msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, sizeof(rai), &rai[0]);
119 msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref);
120
121 msgb_bssgp_send_and_free(msg);
122}
123
124static void test_bssgp_suspend_resume(void)
125{
126 const uint32_t tlli = 0xf0123456;
127
128 printf("----- %s START\n", __func__);
129 memset(&last_oph, 0, sizeof(last_oph));
130
131 send_bssgp_supend(BSSGP_PDUT_SUSPEND, tlli);
Jacob Erlbeckb43baf22014-09-10 12:43:28 +0200132 OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_SUSPEND);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200133
134 send_bssgp_resume(BSSGP_PDUT_RESUME, tlli);
Jacob Erlbeckb43baf22014-09-10 12:43:28 +0200135 OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_RESUME);
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200136
137 printf("----- %s END\n", __func__);
138}
139
Jacob Erlbeck36153dc2015-03-17 10:21:17 +0100140static void send_bssgp_status(enum gprs_bssgp_cause cause, uint16_t *bvci)
141{
142 struct msgb *msg = bssgp_msgb_alloc();
143 uint8_t cause_ = cause;
144
145 msgb_v_put(msg, BSSGP_PDUT_STATUS);
146 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause_);
147 if (bvci) {
148 uint16_t bvci_ = htons(*bvci);
149 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &bvci_);
150 }
151
152 msgb_bssgp_send_and_free(msg);
153}
154
155static void test_bssgp_status(void)
156{
157 uint16_t bvci;
158
159 printf("----- %s START\n", __func__);
160
161 send_bssgp_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL);
162 OSMO_ASSERT(last_oph.primitive == PRIM_NM_STATUS);
163
164 /* Enforce prim != PRIM_NM_STATUS */
165 last_oph.primitive = PRIM_NM_LLC_DISCARDED;
166
167 bvci = 1234;
168 send_bssgp_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci);
169 OSMO_ASSERT(last_oph.primitive == PRIM_NM_STATUS);
170
171 printf("----- %s END\n", __func__);
172}
173
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200174static void test_bssgp_bad_reset()
175{
Jacob Erlbeck2c581972015-06-18 11:51:34 +0200176 struct msgb *msg;
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200177 uint16_t bvci_be = htons(2);
178 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
179
Jacob Erlbeck2c581972015-06-18 11:51:34 +0200180 printf("----- %s START\n", __func__);
181 msg = bssgp_msgb_alloc();
182
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200183 msgb_v_put(msg, BSSGP_PDUT_BVC_RESET);
184 msgb_tvlv_put(msg, BSSGP_IE_BVCI, sizeof(bvci_be), (uint8_t *)&bvci_be);
185 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, sizeof(cause), &cause);
186
187 msgb_bvci(msg) = 0xbad;
188
189 msgb_bssgp_send_and_free(msg);
Jacob Erlbeck2c581972015-06-18 11:51:34 +0200190
191 printf("----- %s END\n", __func__);
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200192}
193
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +0200194static void test_bssgp_flow_control_bvc(void)
195{
196 struct bssgp_bvc_ctx bctx = {
197 .nsei = 0x1234,
198 .bvci = 0x5678,
199 };
200 const uint8_t tag = 42;
201 const uint32_t bmax = 0x1022 * 100;
202 const uint32_t rate = 0xc040 / 8 * 100;
203 const uint32_t bmax_ms = bmax / 2;
204 const uint32_t rate_ms = rate / 2;
205 uint8_t ratio = 0x78;
206 uint32_t qdelay = 0x1144 * 10;
207 int rc;
208
209 static uint8_t expected_simple_msg[] = {
210 0x26,
211 0x1e, 0x81, 0x2a, /* tag */
212 0x05, 0x82, 0x10, 0x22, /* Bmax */
213 0x03, 0x82, 0xc0, 0x40, /* R */
214 0x01, 0x82, 0x08, 0x11, /* Bmax_MS */
215 0x1c, 0x82, 0x60, 0x20, /* R_MS */
216 };
217
218 static uint8_t expected_ext_msg[] = {
219 0x26,
220 0x1e, 0x81, 0x2a, /* tag */
221 0x05, 0x82, 0x10, 0x22, /* Bmax */
222 0x03, 0x82, 0xc0, 0x40, /* R */
223 0x01, 0x82, 0x08, 0x11, /* Bmax_MS */
224 0x1c, 0x82, 0x60, 0x20, /* R_MS */
225 0x3c, 0x81, 0x78, /* ratio */
226 0x06, 0x82, 0x11, 0x44, /* Qdelay */
227 };
228
229 printf("----- %s START\n", __func__);
230
231 rc = bssgp_tx_fc_bvc(&bctx, tag, bmax, rate, bmax_ms, rate_ms,
232 NULL, NULL);
233
234 OSMO_ASSERT(rc >= 0);
235 OSMO_ASSERT(last_ns_tx_msg != NULL);
236 printf("Got message: %s\n", msgb_hexdump(last_ns_tx_msg));
237 OSMO_ASSERT(msgb_length(last_ns_tx_msg) == sizeof(expected_simple_msg));
238 OSMO_ASSERT(0 == memcmp(msgb_data(last_ns_tx_msg),
239 expected_simple_msg, sizeof(expected_simple_msg)));
240
241 rc = bssgp_tx_fc_bvc(&bctx, tag, bmax, rate, bmax_ms, rate_ms,
242 &ratio, &qdelay);
243
244 OSMO_ASSERT(rc >= 0);
245 OSMO_ASSERT(last_ns_tx_msg != NULL);
246 printf("Got message: %s\n", msgb_hexdump(last_ns_tx_msg));
247 OSMO_ASSERT(msgb_length(last_ns_tx_msg) == sizeof(expected_ext_msg));
248 OSMO_ASSERT(0 == memcmp(msgb_data(last_ns_tx_msg),
249 expected_ext_msg, sizeof(expected_ext_msg)));
250
251 msgb_free(last_ns_tx_msg);
252 last_ns_tx_msg = NULL;
253
254 printf("----- %s END\n", __func__);
255}
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200256
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200257static struct log_info info = {};
258
259int main(int argc, char **argv)
260{
261 struct sockaddr_in bss_peer= {0};
262
263 osmo_init_logging(&info);
264 log_set_use_color(osmo_stderr_target, 0);
265 log_set_print_filename(osmo_stderr_target, 0);
266
267 bssgp_nsi = gprs_ns_instantiate(gprs_ns_callback, NULL);
268
269 bss_peer.sin_family = AF_INET;
270 bss_peer.sin_port = htons(32000);
271 bss_peer.sin_addr.s_addr = htonl(0x7f0000ff);
272
273 gprs_ns_nsip_connect(bssgp_nsi, &bss_peer, BSS_NSEI, BSS_NSEI+1);
274
275
276 printf("===== BSSGP test START\n");
277 test_bssgp_suspend_resume();
Jacob Erlbeck36153dc2015-03-17 10:21:17 +0100278 test_bssgp_status();
Jacob Erlbeckb535e392015-04-07 17:52:44 +0200279 test_bssgp_bad_reset();
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +0200280 test_bssgp_flow_control_bvc();
Jacob Erlbeckcdebf742014-10-14 14:49:37 +0200281 printf("===== BSSGP test END\n\n");
282
283 exit(EXIT_SUCCESS);
284}