blob: 7dd3a7fcb711ab5e1ed7c28cfe8f35eff8063a30 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* MTP layer3 main handling code */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010 by On-Waves
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22#include <mtp_data.h>
23#include <mtp_level3.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080024#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080025
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080026#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080027
Holger Hans Peter Freythercf381e22010-08-04 18:39:26 +080028#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080029
30#include <arpa/inet.h>
31
32#include <string.h>
33
34static void *tall_mtp_ctx = NULL;
35
36static struct msgb *mtp_msg_alloc(struct mtp_link *link)
37{
38 struct mtp_level_3_hdr *hdr;
39 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
40 if (!msg) {
41 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
42 return NULL;
43 }
44
45 msg->l2h = msgb_put(msg, sizeof(*hdr));
46 hdr = (struct mtp_level_3_hdr *) msg->l2h;
47 hdr->addr = MTP_ADDR(0x0, link->dpc, link->opc);
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +010048 hdr->ni = link->ni;
Holger Hans Peter Freythere976df12010-11-26 21:07:11 +010049 hdr->spare = link->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080050 return msg;
51}
52
53static struct msgb *mtp_create_sltm(struct mtp_link *link)
54{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080055 const uint8_t test_ptrn[14] = { 'G', 'S', 'M', 'M', 'M', 'S', };
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080056 struct mtp_level_3_hdr *hdr;
57 struct mtp_level_3_mng *mng;
58 struct msgb *msg = mtp_msg_alloc(link);
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080059 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080060 if (!msg)
61 return NULL;
62
63 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080064 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
65
66 mng = (struct mtp_level_3_mng *) msgb_put(msg, sizeof(*mng));
67 mng->cmn.h0 = MTP_TST_MSG_GRP;
68 mng->cmn.h1 = MTP_TST_MSG_SLTM;
69 mng->length = ARRAY_SIZE(test_ptrn);
70
71 data = msgb_put(msg, ARRAY_SIZE(test_ptrn));
72 memcpy(data, test_ptrn, ARRAY_SIZE(test_ptrn));
73
74 /* remember the last tst ptrn... once we have some */
75 memcpy(link->test_ptrn, test_ptrn, ARRAY_SIZE(test_ptrn));
76
77 return msg;
78}
79
80static struct msgb *mtp_create_slta(struct mtp_link *link, struct mtp_level_3_mng *in_mng, int l3_len)
81{
82 struct mtp_level_3_hdr *hdr;
83 struct mtp_level_3_mng *mng;
84 struct msgb *out = mtp_msg_alloc(link);
85
86 if (!out)
87 return NULL;
88
89 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080090 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
91 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
92 mng->cmn.h0 = MTP_TST_MSG_GRP;
93 mng->cmn.h1 = MTP_TST_MSG_SLTA;
94 mng->length = l3_len - 2;
95 msgb_put(out, mng->length);
96 memcpy(mng->data, in_mng->data, mng->length);
97
98 return out;
99}
100
101static struct msgb *mtp_tfp_alloc(struct mtp_link *link, int apoc)
102{
103 struct mtp_level_3_hdr *hdr;
104 struct mtp_level_3_prohib *prb;
105 struct msgb *out = mtp_msg_alloc(link);
106
107 if (!out)
108 return NULL;
109
110 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800111 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
112 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
113 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
114 prb->cmn.h1 = MTP_PROHIBIT_MSG_SIG;
115 prb->apoc = MTP_MAKE_APOC(apoc);
116 return out;
117}
118
119static struct msgb *mtp_tra_alloc(struct mtp_link *link)
120{
121 struct mtp_level_3_hdr *hdr;
122 struct mtp_level_3_cmn *cmn;
123 struct msgb *out = mtp_msg_alloc(link);
124
125 if (!out)
126 return NULL;
127
128 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800129 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
130 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
131 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
132 cmn->h1 = MTP_RESTR_MSG_ALLWED;
133 return out;
134}
135
136static struct msgb *mtp_sccp_alloc_ssa(struct mtp_link *link, int sls)
137{
138 struct sccp_data_unitdata *udt;
139 struct sccp_con_ctrl_prt_mgt *prt;
140 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800141 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800142
143
144 struct msgb *out = mtp_msg_alloc(link);
145
146 if (!out)
147 return NULL;
148
149 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800150 hdr->ser_ind = MTP_SI_MNT_SCCP;
151
152 /* this appears to be round robin or such.. */
153 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->opc);
154
155 /* generate the UDT message... libsccp does not offer formating yet */
156 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
157 udt->type = SCCP_MSG_TYPE_UDT;
158 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
159 udt->variable_called = 3;
160 udt->variable_calling = 5;
161 udt->variable_data = 7;
162
163 /* put the called and calling address. It is LV */
164 data = msgb_put(out, 2 + 1);
165 data[0] = 2;
166 data[1] = 0x42;
167 data[2] = 0x1;
168
169 data = msgb_put(out, 2 + 1);
170 data[0] = 2;
171 data[1] = 0x42;
172 data[2] = 0x1;
173
174 data = msgb_put(out, 1);
175 data[0] = sizeof(*prt);
176
177 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
178 prt->sst = SCCP_SSA;
179 prt->assn = 254;
180 prt->apoc = MTP_MAKE_APOC(link->opc);
181 prt->mul_ind = 0;
182
183 return out;
184}
185
186void mtp_link_init(void)
187{
188 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
189}
190
191static void mtp_send_sltm(struct mtp_link *link)
192{
193 struct msgb *msg;
194
195 link->sltm_pending = 1;
196 msg = mtp_create_sltm(link);
197 if (!msg) {
198 LOGP(DINP, LOGL_ERROR, "Failed to allocate SLTM.\n");
199 return;
200 }
201
202 mtp_link_submit(link, msg);
203}
204
205static void mtp_sltm_t1_timeout(void *_link)
206{
207 struct mtp_link *link = (struct mtp_link *) _link;
208
209 if (link->slta_misses == 0) {
210 LOGP(DINP, LOGL_ERROR, "No SLTM response. Retrying. Link: %p\n", link);
211 ++link->slta_misses;
212 mtp_send_sltm(link);
213 bsc_schedule_timer(&link->t1_timer, MTP_T1);
214 } else {
215 LOGP(DINP, LOGL_ERROR, "Two missing SLTAs. Restart link: %p\n", link);
216 link->sccp_up = 0;
217 link->running = 0;
218 bsc_del_timer(&link->t2_timer);
219 mtp_link_sccp_down(link);
220 mtp_link_restart(link);
221 }
222}
223
224static void mtp_sltm_t2_timeout(void *_link)
225{
226 struct mtp_link *link = (struct mtp_link *) _link;
227
228 if (!link->running) {
229 LOGP(DINP, LOGL_INFO, "Not restarting SLTM timer on link: %p\n", link);
230 return;
231 }
232
233 link->slta_misses = 0;
234 mtp_send_sltm(link);
235
236 bsc_schedule_timer(&link->t1_timer, MTP_T1);
237
238 if (link->sltm_once && link->was_up)
239 LOGP(DINP, LOGL_INFO, "Not sending SLTM again as configured.\n");
240 else
241 bsc_schedule_timer(&link->t2_timer, MTP_T2);
242}
243
244static void mtp_delayed_start(void *link)
245{
246 mtp_sltm_t2_timeout(link);
247}
248
249struct mtp_link *mtp_link_alloc(void)
250{
251 struct mtp_link *link;
252
253 link = talloc_zero(tall_mtp_ctx, struct mtp_link);
254 if (!link)
255 return NULL;
256
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100257 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800258 link->t1_timer.data = link;
259 link->t1_timer.cb = mtp_sltm_t1_timeout;
260 link->t2_timer.data = link;
261 link->t2_timer.cb = mtp_sltm_t2_timeout;
262 link->delay_timer.data = link;
263 link->delay_timer.cb = mtp_delayed_start;
264 INIT_LLIST_HEAD(&link->pending_msgs);
265 return link;
266}
267
268void mtp_link_stop(struct mtp_link *link)
269{
270 bsc_del_timer(&link->t1_timer);
271 bsc_del_timer(&link->t2_timer);
272 bsc_del_timer(&link->delay_timer);
273 link->sccp_up = 0;
274 link->running = 0;
275 link->sltm_pending = 0;
276
277 mtp_link_sccp_down(link);
278}
279
280void mtp_link_reset(struct mtp_link *link)
281{
282 mtp_link_stop(link);
283 link->running = 1;
284 bsc_schedule_timer(&link->delay_timer, START_DELAY);
285}
286
287static int mtp_link_sign_msg(struct mtp_link *link, struct mtp_level_3_hdr *hdr, int l3_len)
288{
289 struct msgb *msg;
290 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100291 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800292
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100293 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800294 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
295 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800296 return -1;
297 }
298
299 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
300 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
301 cmn->h0, cmn->h1);
302
303 switch (cmn->h0) {
304 case MTP_TRF_RESTR_MSG_GRP:
305 switch (cmn->h1) {
306 case MTP_RESTR_MSG_ALLWED:
307 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST should be next: %p\n", link);
308 link->sccp_up = 0;
309 mtp_link_sccp_down(link);
310
311 msg = mtp_tfp_alloc(link, 0);
312 if (!msg)
313 return -1;
314 mtp_link_submit(link, msg);
315
316 msg = mtp_tra_alloc(link);
317 if (!msg)
318 return -1;
319
320 mtp_link_submit(link, msg);
321 return 0;
322 break;
323 }
324 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100325 case MTP_PROHIBIT_MSG_GRP:
326 switch (cmn->h1) {
327 case MTP_PROHIBIT_MSG_SIG:
328 if (l3_len < 3) {
329 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
330 return -1;
331 }
332
333 apc = (uint16_t *) &hdr->data[1];
334 LOGP(DINP, LOGL_INFO,
335 "TFP for the affected point code: %d\n", *apc);
336 return 0;
337 break;
338 }
339 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800340 }
341
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100342 LOGP(DINP, LOGL_ERROR, "Unknown message:%d/%d %s\n", cmn->h0, cmn->h1, hexdump(&hdr->data[0], l3_len));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800343 return -1;
344}
345
346static int mtp_link_regular_msg(struct mtp_link *link, struct mtp_level_3_hdr *hdr, int l3_len)
347{
348 struct msgb *out;
349 struct mtp_level_3_mng *mng;
350
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100351 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800352 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
353 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800354 return -1;
355 }
356
357 mng = (struct mtp_level_3_mng *) &hdr->data[0];
358 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
359 mng->cmn.h0, mng->cmn.h1);
360
361 switch (mng->cmn.h0) {
362 case MTP_TST_MSG_GRP:
363 switch (mng->cmn.h1) {
364 case MTP_TST_MSG_SLTM:
365 /* simply respond to the request... */
366 out = mtp_create_slta(link, mng, l3_len);
367 if (!out)
368 return -1;
369 mtp_link_submit(link, out);
370 return 0;
371 break;
372 case MTP_TST_MSG_SLTA:
373 if (mng->length != 14) {
374 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
375 return -1;
376 }
377
378 if (l3_len != 16) {
379 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
380 return -1;
381 }
382
383 if (memcmp(mng->data, link->test_ptrn, sizeof(link->test_ptrn)) != 0) {
384 LOGP(DINP, LOGL_ERROR, "Wrong test pattern SLTA\n");
385 return -1;
386 }
387
388 /* we had a matching slta */
389 bsc_del_timer(&link->t1_timer);
390 link->sltm_pending = 0;
391 mtp_link_slta_recv(link);
392 return 0;
393 break;
394 }
395 break;
396 }
397
398 return -1;
399}
400
401static int mtp_link_sccp_data(struct mtp_link *link, struct mtp_level_3_hdr *hdr, struct msgb *msg, int l3_len)
402{
403 struct msgb *out;
404 struct sccp_con_ctrl_prt_mgt *prt;
405
406 msg->l2h = &hdr->data[0];
407 if (msgb_l2len(msg) != l3_len) {
408 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
409 return -1;
410 }
411
412
413 if (link->sccp_up) {
414 mtp_link_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
415 return 0;
416 } else {
417 struct sccp_parse_result sccp;
418 memset(&sccp, 0, sizeof(sccp));
419 if (sccp_parse_header(msg, &sccp) != 0) {
420 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
421 return -1;
422 }
423
424 if (sccp_determine_msg_type(msg) != SCCP_MSG_TYPE_UDT) {
425 LOGP(DINP, LOGL_ERROR, "Dropping sccp data: 0x%x\n",
426 sccp_determine_msg_type(msg));
427 return -1;
428 }
429
430 if (msgb_l3len(msg) != 5) {
431 LOGP(DINP, LOGL_ERROR, "SCCP UDT msg of unexpected size: %u\n",
432 msgb_l3len(msg));
433 return -1;
434 }
435
436 if (msg->l3h[0] != SCCP_SST) {
437 LOGP(DINP, LOGL_ERROR, "Expected SCCP SST but got 0x%x\n",
438 msg->l3h[0]);
439 return -1;
440 }
441
442 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
443 if (prt->assn != 254 || prt->apoc != MTP_MAKE_APOC(link->opc)) {
444 LOGP(DINP, LOGL_ERROR, "Unknown SSN/APOC assn: %u, apoc: %u/%u\n",
445 prt->assn, ntohs(prt->apoc), prt->apoc);
446 return -1;
447 }
448
449 out = mtp_sccp_alloc_ssa(link, MTP_LINK_SLS(hdr->addr));
450 if (!out)
451 return -1;
452
453 link->sccp_up = 1;
454 link->was_up = 1;
455 LOGP(DINP, LOGL_INFO, "SCCP is established. %p\n", link);
456 mtp_link_submit(link, out);
457 }
458 return 0;
459}
460
461int mtp_link_data(struct mtp_link *link, struct msgb *msg)
462{
463 int rc = -1;
464 struct mtp_level_3_hdr *hdr;
465 int l3_len;
466
467 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
468 return -1;
469
470 if (!link->running) {
471 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
472 return -1;
473 }
474
475 hdr = (struct mtp_level_3_hdr *) msg->l2h;
476 l3_len = msgb_l2len(msg) - sizeof(*hdr);
477
478 switch (hdr->ser_ind) {
479 case MTP_SI_MNT_SNM_MSG:
480 rc = mtp_link_sign_msg(link, hdr, l3_len);
481 break;
482 case MTP_SI_MNT_REG_MSG:
483 rc = mtp_link_regular_msg(link, hdr, l3_len);
484 break;
485 case MTP_SI_MNT_SCCP:
486 rc = mtp_link_sccp_data(link, hdr, msg, l3_len);
487 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100488 case MTP_SI_MNT_ISUP:
489 LOGP(DINP, LOGL_ERROR, "ISUP handling not implemented.\n");
490 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800491 default:
492 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
493 break;
494 }
495
496 return rc;
497}
498
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800499int mtp_link_submit_sccp_data(struct mtp_link *link, int sls, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800500{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800501 uint8_t *put_ptr;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800502 struct mtp_level_3_hdr *hdr;
503 struct msgb *msg;
504
505 if (!link->sccp_up) {
506 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
507 return -1;
508 }
509
510 msg = mtp_msg_alloc(link);
511 if (!msg)
512 return -1;
513
514 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800515 hdr->ser_ind = MTP_SI_MNT_SCCP;
516
517 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->opc);
518
519 /* copy the raw sccp data */
520 put_ptr = msgb_put(msg, length);
521 memcpy(put_ptr, data, length);
522
523 mtp_link_submit(link, msg);
524 return 0;
525}