blob: 861212a64bd4a813f6fbbb9cf285edc260c4070d [file] [log] [blame]
Harald Welteabc65052016-05-06 23:27:38 +02001#include <string.h>
2#include <stdio.h>
3#include <errno.h>
4#include <signal.h>
5
6#include <osmocom/core/linuxlist.h>
7#include <osmocom/core/msgb.h>
8#include <osmocom/core/select.h>
9#include <osmocom/core/application.h>
Neels Hofmeyr64a40bf2017-01-13 03:10:54 +010010#include <osmocom/core/utils.h>
Harald Welteabc65052016-05-06 23:27:38 +020011#include <osmocom/gsm/gsup.h>
12
Neels Hofmeyrdb1d8012016-12-08 21:22:58 +010013#include <openbsc/gsup_client.h>
Harald Welteabc65052016-05-06 23:27:38 +020014#include <openbsc/debug.h>
15
Neels Hofmeyr0e5c1e12016-12-08 21:19:57 +010016static struct gsup_client *g_gc;
Harald Welteabc65052016-05-06 23:27:38 +020017
18
19/***********************************************************************
20 * IMSI Operation
21 ***********************************************************************/
22static LLIST_HEAD(g_imsi_ops);
23
24struct imsi_op_stats {
25 uint32_t num_alloc;
26 uint32_t num_released;
27 uint32_t num_rx_success;
28 uint32_t num_rx_error;
29 uint32_t num_timeout;
30};
31
32enum imsi_op_type {
33 IMSI_OP_SAI,
34 IMSI_OP_LU,
35 IMSI_OP_ISD,
36 _NUM_IMSI_OP
37};
38
39static const struct value_string imsi_op_names[] = {
40 { IMSI_OP_SAI, "SAI" },
41 { IMSI_OP_LU, "LU" },
42 { IMSI_OP_ISD, "ISD" },
43 { 0, NULL }
44};
45
46static struct imsi_op_stats imsi_op_stats[_NUM_IMSI_OP];
47
48struct imsi_op {
49 struct llist_head list;
50 char imsi[17];
51 enum imsi_op_type type;
52 struct osmo_timer_list timer;
53};
54
55static struct imsi_op *imsi_op_find(const char *imsi,
56 enum imsi_op_type type)
57{
58 struct imsi_op *io;
59
60 llist_for_each_entry(io, &g_imsi_ops, list) {
61 if (!strcmp(io->imsi, imsi) && io->type == type)
62 return io;
63 }
64 return NULL;
65}
66
67static void imsi_op_timer_cb(void *data);
68
69static struct imsi_op *imsi_op_alloc(void *ctx, const char *imsi,
70 enum imsi_op_type type)
71{
72 struct imsi_op *io;
73
74 if (imsi_op_find(imsi, type))
75 return NULL;
76
77 io = talloc_zero(ctx, struct imsi_op);
78 strncpy(io->imsi, imsi, sizeof(io->imsi));
79 io->imsi[sizeof(io->imsi)-1] = '\0';
80 io->type = type;
81 io->timer.cb = imsi_op_timer_cb;
82 io->timer.data = io;
83 llist_add(&io->list, &g_imsi_ops);
84 imsi_op_stats[type].num_alloc++;
85
86 return io;
87}
88
89static void imsi_op_release(struct imsi_op *io)
90{
91 osmo_timer_del(&io->timer);
92 llist_del(&io->list);
93 imsi_op_stats[io->type].num_released++;
94 talloc_free(io);
95}
96
97static void imsi_op_timer_cb(void *data)
98{
99 struct imsi_op *io = data;
100 printf("%s: Timer expiration\n", io->imsi);
101 imsi_op_stats[io->type].num_timeout++;
102 imsi_op_release(io);
103}
104
105/* allocate + generate + send Send-Auth-Info */
106int req_auth_info(const char *imsi)
107{
108 struct imsi_op *io = imsi_op_alloc(g_gc, imsi, IMSI_OP_SAI);
109 struct osmo_gsup_message gsup = {0};
110 struct msgb *msg = msgb_alloc_headroom(1200, 200, __func__);
111
Neels Hofmeyr64a40bf2017-01-13 03:10:54 +0100112 osmo_strlcpy(gsup.imsi, io->imsi, sizeof(gsup.imsi));
Harald Welteabc65052016-05-06 23:27:38 +0200113 gsup.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
114
115 osmo_gsup_encode(msg, &gsup);
116
Neels Hofmeyr0e5c1e12016-12-08 21:19:57 +0100117 return gsup_client_send(g_gc, msg);
Harald Welteabc65052016-05-06 23:27:38 +0200118}
119
120/* allocate + generate + send Send-Auth-Info */
121int req_loc_upd(const char *imsi)
122{
123 struct imsi_op *io = imsi_op_alloc(g_gc, imsi, IMSI_OP_LU);
124 struct osmo_gsup_message gsup = {0};
125 struct msgb *msg = msgb_alloc_headroom(1200, 200, __func__);
126
Neels Hofmeyr64a40bf2017-01-13 03:10:54 +0100127 osmo_strlcpy(gsup.imsi, io->imsi, sizeof(gsup.imsi));
Harald Welteabc65052016-05-06 23:27:38 +0200128 gsup.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
129
130 osmo_gsup_encode(msg, &gsup);
131
Neels Hofmeyr0e5c1e12016-12-08 21:19:57 +0100132 return gsup_client_send(g_gc, msg);
Harald Welteabc65052016-05-06 23:27:38 +0200133}
134
135int resp_isd(struct imsi_op *io)
136{
137 struct osmo_gsup_message gsup = {0};
138 struct msgb *msg = msgb_alloc_headroom(1200, 200, __func__);
139
Neels Hofmeyr64a40bf2017-01-13 03:10:54 +0100140 osmo_strlcpy(gsup.imsi, io->imsi, sizeof(gsup.imsi));
Harald Welteabc65052016-05-06 23:27:38 +0200141 gsup.message_type = OSMO_GSUP_MSGT_INSERT_DATA_RESULT;
142
143 osmo_gsup_encode(msg, &gsup);
144
145 imsi_op_release(io);
146
Neels Hofmeyr0e5c1e12016-12-08 21:19:57 +0100147 return gsup_client_send(g_gc, msg);
Harald Welteabc65052016-05-06 23:27:38 +0200148}
149
150/* receive an incoming GSUP message */
151static void imsi_op_rx_gsup(struct imsi_op *io, const struct osmo_gsup_message *gsup)
152{
153 int is_error = 0;
154
155 if (OSMO_GSUP_IS_MSGT_ERROR(gsup->message_type)) {
156 imsi_op_stats[io->type].num_rx_error++;
157 is_error = 1;
158 } else
159 imsi_op_stats[io->type].num_rx_success++;
160
161 switch (io->type) {
162 case IMSI_OP_SAI:
163 printf("%s; SAI Response%s\n", io->imsi, is_error ? ": ERROR" : "");
164 /* now that we have auth tuples, request LU */
165 req_loc_upd(io->imsi);
166 imsi_op_release(io);
167 break;
168 case IMSI_OP_LU:
169 printf("%s; LU Response%s\n", io->imsi, is_error ? ": ERROR" : "");
170 imsi_op_release(io);
171 break;
172 case IMSI_OP_ISD:
173 printf("%s; ISD Request%s\n", io->imsi, is_error ? ": ERROR" : "");
174 resp_isd(io);
175 break;
176 default:
177 printf("%s: Unknown\n", io->imsi);
178 imsi_op_release(io);
179 break;
180 }
181}
182
183static int op_type_by_gsup_msgt(enum osmo_gsup_message_type msg_type)
184{
185 switch (msg_type) {
186 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
187 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
188 return IMSI_OP_SAI;
189 case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:
190 case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR:
191 return IMSI_OP_LU;
192 case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:
193 return IMSI_OP_ISD;
194 default:
195 printf("Unknown GSUP msg_type %u\n", msg_type);
196 return -1;
197 }
198}
199
Neels Hofmeyr0e5c1e12016-12-08 21:19:57 +0100200static int gsupc_read_cb(struct gsup_client *gsupc, struct msgb *msg)
Harald Welteabc65052016-05-06 23:27:38 +0200201{
202 struct osmo_gsup_message gsup_msg = {0};
203 struct imsi_op *io;
204 int rc;
205
206 DEBUGP(DGPRS, "Rx GSUP %s\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
207
208 rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup_msg);
209 if (rc < 0)
210 return rc;
211
212 if (!gsup_msg.imsi[0])
213 return -1;
214
215 rc = op_type_by_gsup_msgt(gsup_msg.message_type);
216 if (rc < 0)
217 return rc;
218
219 switch (rc) {
220 case IMSI_OP_SAI:
221 case IMSI_OP_LU:
222 io = imsi_op_find(gsup_msg.imsi, rc);
223 if (!io)
224 return -1;
225 break;
226 case IMSI_OP_ISD:
227 /* ISD is an inbound transaction */
228 io = imsi_op_alloc(g_gc, gsup_msg.imsi, IMSI_OP_ISD);
229 break;
230 }
231
232 imsi_op_rx_gsup(io, &gsup_msg);
233 msgb_free(msg);
234
235 return 0;
236}
237
238static void print_report(void)
239{
240 unsigned int i;
241
242 for (i = 0; i < ARRAY_SIZE(imsi_op_stats); i++) {
243 struct imsi_op_stats *st = &imsi_op_stats[i];
244 const char *name = get_value_string(imsi_op_names, i);
245 printf("%s: %u alloc, %u released, %u success, %u error , %u tout\n",
246 name, st->num_alloc, st->num_released, st->num_rx_success,
247 st->num_rx_error, st->num_timeout);
248 }
249}
250
251static void sig_cb(int sig)
252{
253 switch (sig) {
254 case SIGINT:
255 print_report();
256 exit(0);
257 break;
258 }
259}
260
261void *tall_bsc_ctx = NULL;
262
263/* default categories */
Neels Hofmeyr7aef97a2016-12-08 21:28:29 +0100264static struct log_info_cat default_categories[] = {
Harald Welteabc65052016-05-06 23:27:38 +0200265};
266
Neels Hofmeyr7aef97a2016-12-08 21:28:29 +0100267static const struct log_info gsup_test_client_log_info = {
268 .cat = default_categories,
269 .num_cat = ARRAY_SIZE(default_categories),
Harald Welteabc65052016-05-06 23:27:38 +0200270};
271
272int main(int argc, char **argv)
273{
274 unsigned long long i;
275 char *server_host = "127.0.0.1";
276 uint16_t server_port = 2222;
277
Neels Hofmeyr7aef97a2016-12-08 21:28:29 +0100278 osmo_init_logging(&gsup_test_client_log_info);
Harald Welteabc65052016-05-06 23:27:38 +0200279
Neels Hofmeyr0e5c1e12016-12-08 21:19:57 +0100280 g_gc = gsup_client_create(server_host, server_port, gsupc_read_cb,
281 NULL);
Harald Welteabc65052016-05-06 23:27:38 +0200282
283
284 signal(SIGINT, sig_cb);
285
286 for (i = 0; i < 10000; i++) {
287 unsigned long long imsi = 901790000000000 + i;
288 char imsi_buf[17];
289 snprintf(imsi_buf, sizeof(imsi_buf), "%015llu", imsi);
290 req_auth_info(imsi_buf);
291 osmo_select_main(0);
292 }
293
294 while (1) {
295 osmo_select_main(0);
296 }
297
298 print_report();
299 exit(0);
300}