The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
sccp.c
Go to the documentation of this file.
1/*
2 * @copyright (c) 2016, Network RADIUS SAS (license@networkradius.com)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Network RADIUS SAS nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/**
29 * $Id: 7911a8da148463176e4344fea79a2347e63d30f6 $
30 * @file rlm_sigtran/sccp.c
31 * @brief Implement SCCP/TCAP glue layer
32 *
33 * @author Arran Cudbard-Bell
34 *
35 * @copyright 2016 Network RADIUS SAS (license@networkradius.com)
36 */
37#define LOG_PREFIX "sigtran - osmocom thread"
38
39#include <osmocom/core/talloc.h>
40
41#include <freeradius-devel/server/base.h>
42#include <freeradius-devel/util/debug.h>
43#include <osmocom/core/msgb.h>
44#include <osmocom/core/utils.h>
45
46#include "sigtran.h"
47
48#undef DEBUG
49
50#include "libosmo-m3ua/include/cellmgr_debug.h"
51#include "libosmo-m3ua/include/mtp_data.h"
52#include "libosmo-m3ua/include/sctp_m3ua.h"
53
54static uint32_t last_txn_id = 0; //!< Global transaction ID
55static fr_rb_tree_t *txn_tree = NULL; //!< Global transaction tree... Should really be per module.
57
58/** Compare rounds of a transaction
59 *
60 */
61static int sigtran_txn_cmp(void const *one, void const *two)
62{
63 sigtran_transaction_t const *a = one; /* May be stack allocated */
64 sigtran_transaction_t const *b = two; /* May be stack allocated */
65
66 CMP_RETURN(a, b, ctx.otid);
67
68 return CMP(a->ctx.invoke_id, b->ctx.invoke_id);
69}
70
71static void sigtran_tcap_timeout(void *data)
72{
73 sigtran_transaction_t *txn = talloc_get_type_abort(data, sigtran_transaction_t);
74
75 ERROR("OTID %u Invoke ID %u timeout", txn->ctx.otid, txn->ctx.invoke_id);
76
77 /*
78 * Remove the outstanding transaction
79 */
80 if (!fr_rb_delete(txn_tree, txn)) ERROR("Transaction removed before timeout");
81
83
84 if (sigtran_event_submit(txn->ctx.ofd, txn) < 0) {
85 ERROR("Failed informing event client of result: %s", fr_syserror(errno));
86 return;
87 }
88}
89
90/** Send a request with static MAP data in it
91 *
92 * SCCP will add its headers and call sigtran_sccp_outgoing
93 *
94 * @return
95 * - 0 on success.
96 * - <0 on failure.
97 */
98int sigtran_tcap_outgoing(UNUSED struct msgb *msg_in, void *ctx, sigtran_transaction_t *txn, UNUSED struct osmo_fd *ofd)
99{
100 static uint8_t tcap_map_raw_v2[] = {
101 0x62, 0x43, 0x48, 0x01, 0x01, 0x6b, 0x80, 0x28, /* 0x00 */
102 0x80, 0x06, 0x07, 0x00, 0x11, 0x86, 0x05, 0x01, /* 0x08 */
103 0x01, 0x01, 0xa0, 0x80, 0x60, 0x80, 0x80, 0x02, /* 0x10 */
104 0x07, 0x80, 0xa1, 0x80, 0x06, 0x07, 0x04, 0x00, /* 0x18 */
105 0x00, 0x01, 0x00, 0x0e, 0x02, 0x00, 0x00, 0x00, /* 0x20 (0x24 is version)*/
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, /* 0x30 (0x35 is invoke ID) */
107 0x14, 0xa1, 0x80, 0x02, 0x01, 0x03, 0x02, 0x01, /* 0x38 (0x3c is IMSI len, 0x3d-0x44 IMSI) */
108 0x38, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40 */
109 0xff, 0xff, 0xff, 0x00, 0x00 }; /* 0x48 */
110
111 static uint8_t tcap_map_raw_v3[] = {
112 0x62, 0x48, 0x48, 0x01, 0x01, 0x6b, 0x80, 0x28, /* 0x00 */
113 0x80, 0x06, 0x07, 0x00, 0x11, 0x86, 0x05, 0x01, /* 0x08 */
114 0x01, 0x01, 0xa0, 0x80, 0x60, 0x80, 0x80, 0x02, /* 0x10 */
115 0x07, 0x80, 0xa1, 0x80, 0x06, 0x07, 0x04, 0x00, /* 0x18 */
116 0x00, 0x01, 0x00, 0x0e, 0x03, 0x00, 0x00, 0x00, /* 0x20 (0x24 is version)*/
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, /* 0x28 */
118 0x19, 0xa1, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, /* 0x30 (0x35 is invoke ID) */
119 0x38, 0x30, 0x0d, 0x80, 0x00, 0x00, 0x00, 0x00, /* 0x38 (0x3c is IMSI len, 0x3d-0x44 IMSI) */
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, /* 0x40 */
121 0x00, 0x00 }; /* 0x48 */
122
124 talloc_get_type_abort(txn->request.data, sigtran_map_send_auth_info_req_t);
125
126 struct msgb *msg;
127
128 sigtran_conn_t *conn = talloc_get_type_abort(ctx, sigtran_conn_t);
129 struct mtp_m3ua_client_link *m3ua_client = talloc_get_type_abort(conn->mtp3_link->data,
130 struct mtp_m3ua_client_link);
131
132 fr_assert(req->imsi);
133
134 if (!mtp_m3ua_link_is_up(m3ua_client)) {
135 ERROR("Link not yet active, dropping the request");
136
137 return -1;
138 }
139
141 ERROR("Too many outstanding requests, dropping the request");
142
143 return -1;
144 }
145
146 switch (req->version) {
147 case 2:
148 DEBUG4("Allocating buffer for MAP v2, %zu bytes", sizeof(tcap_map_raw_v2));
149 msg = msgb_alloc(sizeof(tcap_map_raw_v2), "sccp: tcap_map");
150 msg->l3h = msgb_put(msg, sizeof(tcap_map_raw_v2));
151 memcpy(msg->l3h, tcap_map_raw_v2, sizeof(tcap_map_raw_v2));
152
153 *(msg->l3h + 0x3a) = talloc_array_length(req->imsi);
154 memcpy(msg->l3h + 0x3b, req->imsi, talloc_array_length(req->imsi));
155// RHEXDUMP(0, msg->l3h, sizeof(tcap_map_raw_v2), "MAPv2 Request");
156
157 break;
158
159 case 3:
160 DEBUG4("Allocating buffer for MAP v3, %zu bytes", sizeof(tcap_map_raw_v3));
161 msg = msgb_alloc(sizeof(tcap_map_raw_v3), "sccp: tcap_map");
162 msg->l3h = msgb_put(msg, sizeof(tcap_map_raw_v3));
163 memcpy(msg->l3h, tcap_map_raw_v3, sizeof(tcap_map_raw_v3));
164
165 *(msg->l3h + 0x3c) = talloc_array_length(req->imsi);
166 memcpy(msg->l3h + 0x3d, req->imsi, talloc_array_length(req->imsi));
167// RHEXDUMP(0, msg->l3h, sizeof(tcap_map_raw_v3), "MAPv3 Request");
168
169 break;
170
171 default:
172 fr_assert_fail(NULL);
173 return -1;
174 }
175
176 /*
177 * Set the transaction ID
178 */
179 txn->ctx.otid = (last_txn_id++) & UINT8_MAX; /* 8 bit for now */
180
181 txn->ctx.invoke_id++; /* Needs to be two operations */
182 txn->ctx.invoke_id &= 0x7f; /* Invoke ID is 7bits */
183 DEBUG2("Sending request with OTID %u Invoke ID %u", txn->ctx.otid, txn->ctx.invoke_id);
184
185 if (!fr_rb_insert(txn_tree, txn)) {
186 ERROR("Failed inserting transaction, maybe at txn limit?");
187
188 msgb_free(msg);
189 return -1;
190 }
191
192 /*
193 * Set OTID and Invoke ID in the packet
194 */
195 *(msg->l3h + 0x04) = txn->ctx.otid;
196 *(msg->l3h + 0x35) = txn->ctx.invoke_id;
197
198 sccp_write(msg, &conn->conf->sccp_calling_sockaddr, &conn->conf->sccp_called_sockaddr,
199 SCCP_PROTOCOL_RETURN_MESSAGE << 4 | SCCP_PROTOCOL_CLASS_0, ctx); /* Class is connectionless (ish) */
200
201 msgb_free(msg);
202
203 txn->ctx.timer.data = txn;
204 txn->ctx.timer.cb = sigtran_tcap_timeout;
205
206 osmo_timer_schedule(&txn->ctx.timer, 1, 0);
207
208 return 0;
209}
210
211/** Incoming data
212 *
213 * This should be called by the SCCP functions to give us result data
214 */
215static int sigtran_tcap_incoming(struct msgb *msg, UNUSED unsigned int length, UNUSED void *ctx)
216{
217 sigtran_vector_t *vec;
218 uint8_t *tcap = msg->l3h;
219 uint8_t *p, *end;
220 size_t len = (size_t)msgb_l3len(msg);
221
222 sigtran_transaction_t find, *found;
224
227
228 struct osmo_fd *ofd;
229 sigtran_vector_t **last;
230
231 memset(&find, 0, sizeof(find));
232
233// sigtran_conn_t *conn = talloc_get_type_abort(ctx, sigtran_conn_t);
234
235 DEBUG3("Got %zu bytes of L4 data", (size_t)msgb_l3len(msg));
236// log_request_hex(L_DBG, L_DBG_LVL_3, request, msg->l3h, (size_t)msgb_l3len(msg));
237
238 find.ctx.otid = *(msg->l3h + 0x5);
239
240 // find.ctx.invoke_id = *(msg->l3h + 0x34);
241 find.ctx.invoke_id = 1; /* Always 1 for now... */
242 DEBUG2("Received response with DTID %u Invoke ID %u", find.ctx.otid, find.ctx.invoke_id);
243
244 /*
245 * Lookup the transaction in our tree of outstanding transactions
246 */
247 found = fr_rb_find(txn_tree, &find);
248 if (!found) {
249 /*
250 * Not an error, could be a retransmission
251 */
252 ERROR("No outstanding transaction with DTID %u Invoke ID %u", find.ctx.otid, find.ctx.invoke_id);
253 return 0;
254 }
255 if (!fr_rb_delete(txn_tree, found)) { /* Remove the outstanding transaction */
256 ERROR("Failed removing transaction");
257 fr_assert(0);
258 }
259
260 txn = talloc_get_type_abort(found, sigtran_transaction_t);
261 req = talloc_get_type_abort(txn->request.data, sigtran_map_send_auth_info_req_t);
262 ofd = txn->ctx.ofd;
263 osmo_timer_del(&txn->ctx.timer); /* Remove the timeout timer */
264
265 MEM(res = talloc_zero(txn, sigtran_map_send_auth_info_res_t));
266 txn->response.type = SIGTRAN_RESPONSE_OK;
267 txn->response.data = res;
268 last = &res->vector; /* Head of vector list */
269
270#define sigtran_memdup(_x) \
271 do { \
272 p++; \
273 DEBUG4("Start 0x%02x len %u", (unsigned int)(tcap - p), p[0]); \
274 if (p[0] >= (len - (p - tcap))) { \
275 ERROR("Invalid length %u specified for vector component", p[0]); \
276 return -1; \
277 } \
278 vec->_x = talloc_memdup(vec, p + 1, p[0]); \
279 talloc_set_type(vec->_x, uint8_t); \
280 p += p[0] + 1; \
281 } while (0)
282
283 end = tcap + msgb_l3len(msg);
284
285 /*
286 * And now pretend to parse the response by looking at
287 * fixed offsets in the response data...
288 *
289 * Umm.. fixme?
290 */
291 if (req->version == 2) {
292 p = tcap + 0x40;
293 while (p < end) {
294 if ((p[0] != 0x30) || (p[1] != 0x22)) {
295 DEBUG4("Breaking out of parsing loop at %x", (uint32_t)(p - tcap));
296 break;
297 }
298 p += 2;
299
300 MEM(vec = talloc_zero(res, sigtran_vector_t));
302
303 sigtran_memdup(sim.rand);
304 sigtran_memdup(sim.sres);
305 sigtran_memdup(sim.kc);
306
307 *last = vec;
308 last = &(vec->next);
309 }
310 } else if (req->version == 3) {
311 p = tcap + 0x40; /* fixed offset for now */
312
313 MEM(vec = talloc_zero(res, sigtran_vector_t));
315 sigtran_memdup(umts.rand);
316 sigtran_memdup(umts.xres);
317 sigtran_memdup(umts.ck);
318 sigtran_memdup(umts.ik);
319 sigtran_memdup(umts.authn);
320
321 *last = vec;
322 }
323
324 if (sigtran_event_submit(ofd, txn) < 0) {
325 ERROR("Failed informing event client of result: %s", fr_syserror(errno));
326 return -1;
327 }
328
329 return 0;
330}
331
332/** Wrapper to pass data down to MTP3 layer for processing
333 *
334 * This is the write callback for the SCCP Code.
335 */
336static void sigtran_sccp_outgoing(UNUSED struct sccp_connection *sscp_conn,
337 struct msgb *msg, UNUSED void *write_ctx, void *ctx)
338{
339 sigtran_conn_t *conn = talloc_get_type_abort(ctx, sigtran_conn_t);
340
341 mtp_link_set_submit_sccp_data(conn->mtp3_link_set, -1, msg->l2h, msgb_l2len(msg));
342
343 msgb_free(msg); /* Apparently our responsibility to free this message */
344}
345
346/** Wrapper to pass data off to libsccp for processing
347 *
348 * @param set Link set data was received on.
349 * @param msg Data from the lower layer.
350 * @param sls Link number the data was received on.
351 */
352void sigtran_sccp_incoming(UNUSED struct mtp_link_set *set, struct msgb *msg, UNUSED int sls)
353{
354 sccp_system_incoming(msg);
355}
356
357/** Initialise libscctp
358 *
359 */
361{
362 sccp_set_log_area(DSCCP);
363
364 sccp_system_init(sigtran_sccp_outgoing, NULL); /* Set write callback */
365 sccp_set_variant(SCCP_VARIANT_ANSI);
366 sccp_set_read(&conn->conf->sccp_calling_sockaddr, sigtran_tcap_incoming, conn); /* Set data_available callback */
367
368 return 0;
369}
370
372{
373 if (txn_tree) {
375 return 0;
376 }
377
379 if (!txn_tree) return -1;
380
382 return 0;
383}
384
386{
387 if (--txn_tree_inst > 0) return;
388
390 txn_tree = NULL;
391}
log_entry msg
Definition acutest.h:794
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:121
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define UNUSED
Definition build.h:315
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:216
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG3(_fmt,...)
Definition log.h:266
#define DEBUG4(_fmt,...)
Definition log.h:267
talloc_free(reap)
unsigned int uint32_t
unsigned char uint8_t
unsigned long int size_t
#define UINT8_MAX
int sigtran_event_submit(struct osmo_fd *ofd, sigtran_transaction_t *txn)
Send response.
Definition event.c:283
#define fr_assert(_expr)
Definition rad_assert.h:38
#define DEBUG2(fmt,...)
Definition radclient.h:43
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:246
The main red black tree structure.
Definition rb.h:73
static uint32_t txn_tree_inst
Definition sccp.c:56
void sigtran_sccp_incoming(UNUSED struct mtp_link_set *set, struct msgb *msg, UNUSED int sls)
Wrapper to pass data off to libsccp for processing.
Definition sccp.c:352
#define sigtran_memdup(_x)
void sigtran_sccp_global_free(void)
Definition sccp.c:385
static void sigtran_sccp_outgoing(UNUSED struct sccp_connection *sscp_conn, struct msgb *msg, UNUSED void *write_ctx, void *ctx)
Wrapper to pass data down to MTP3 layer for processing.
Definition sccp.c:336
static fr_rb_tree_t * txn_tree
Global transaction tree... Should really be per module.
Definition sccp.c:55
static uint32_t last_txn_id
Global transaction ID.
Definition sccp.c:54
int sigtran_tcap_outgoing(UNUSED struct msgb *msg_in, void *ctx, sigtran_transaction_t *txn, UNUSED struct osmo_fd *ofd)
Send a request with static MAP data in it.
Definition sccp.c:98
static int sigtran_tcap_incoming(struct msgb *msg, UNUSED unsigned int length, UNUSED void *ctx)
Incoming data.
Definition sccp.c:215
int sigtran_sscp_init(sigtran_conn_t *conn)
Initialise libscctp.
Definition sccp.c:360
static void sigtran_tcap_timeout(void *data)
Definition sccp.c:71
static int sigtran_txn_cmp(void const *one, void const *two)
Compare rounds of a transaction.
Definition sccp.c:61
int sigtran_sccp_global_init(void)
Definition sccp.c:371
Declarations for various sigtran functions.
@ SIGTRAN_VECTOR_TYPE_UMTS_QUINTUPLETS
RAND, XRES, CK, IK, AUTN.
Definition sigtran.h:66
@ SIGTRAN_VECTOR_TYPE_SIM_TRIPLETS
RAND, SRES, Kc.
Definition sigtran.h:65
@ SIGTRAN_RESPONSE_OK
Request succeeded.
Definition sigtran.h:55
@ SIGTRAN_RESPONSE_FAIL
Request failed.
Definition sigtran.h:58
struct mtp_link_set * mtp3_link_set
Definition sigtran.h:184
uint8_t * imsi
BCD encoded IMSI.
Definition sigtran.h:193
sigtran_vector_type_t type
Type of vector returned.
Definition sigtran.h:218
struct sockaddr_sccp sccp_calling_sockaddr
Parsed version of the above.
Definition sigtran.h:169
sigtran_conn_conf_t * conf
Definition sigtran.h:181
uint8_t version
Application context version.
Definition sigtran.h:194
struct mtp_link * mtp3_link
Definition sigtran.h:185
sigtran_vector_t * vector
Linked list of vectors.
Definition sigtran.h:228
struct sigtran_transaction::@176 ctx
sigtran_vector_t * next
Next vector in list.
Definition sigtran.h:220
struct sigtran_transaction::@175 response
struct sigtran_transaction::@174 request
struct sockaddr_sccp sccp_called_sockaddr
Parsed version of the above.
Definition sigtran.h:171
Represents a connection to a remote SS7 entity.
Definition sigtran.h:180
MAP send auth info request.
Definition sigtran.h:191
MAP send auth info response.
Definition sigtran.h:226
Request and response from the event loop.
Definition sigtran.h:75
Authentication vector returned by HLR.
Definition sigtran.h:203
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static fr_slen_t data
Definition value.h:1265