blob: 14933f29b94c36c1c5c1f4d1c6a26d514688ec19 [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;
291
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100292 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800293 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
294 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800295 return -1;
296 }
297
298 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
299 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
300 cmn->h0, cmn->h1);
301
302 switch (cmn->h0) {
303 case MTP_TRF_RESTR_MSG_GRP:
304 switch (cmn->h1) {
305 case MTP_RESTR_MSG_ALLWED:
306 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST should be next: %p\n", link);
307 link->sccp_up = 0;
308 mtp_link_sccp_down(link);
309
310 msg = mtp_tfp_alloc(link, 0);
311 if (!msg)
312 return -1;
313 mtp_link_submit(link, msg);
314
315 msg = mtp_tra_alloc(link);
316 if (!msg)
317 return -1;
318
319 mtp_link_submit(link, msg);
320 return 0;
321 break;
322 }
323 break;
324 }
325
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100326 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 +0800327 return -1;
328}
329
330static int mtp_link_regular_msg(struct mtp_link *link, struct mtp_level_3_hdr *hdr, int l3_len)
331{
332 struct msgb *out;
333 struct mtp_level_3_mng *mng;
334
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100335 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800336 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
337 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800338 return -1;
339 }
340
341 mng = (struct mtp_level_3_mng *) &hdr->data[0];
342 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
343 mng->cmn.h0, mng->cmn.h1);
344
345 switch (mng->cmn.h0) {
346 case MTP_TST_MSG_GRP:
347 switch (mng->cmn.h1) {
348 case MTP_TST_MSG_SLTM:
349 /* simply respond to the request... */
350 out = mtp_create_slta(link, mng, l3_len);
351 if (!out)
352 return -1;
353 mtp_link_submit(link, out);
354 return 0;
355 break;
356 case MTP_TST_MSG_SLTA:
357 if (mng->length != 14) {
358 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
359 return -1;
360 }
361
362 if (l3_len != 16) {
363 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
364 return -1;
365 }
366
367 if (memcmp(mng->data, link->test_ptrn, sizeof(link->test_ptrn)) != 0) {
368 LOGP(DINP, LOGL_ERROR, "Wrong test pattern SLTA\n");
369 return -1;
370 }
371
372 /* we had a matching slta */
373 bsc_del_timer(&link->t1_timer);
374 link->sltm_pending = 0;
375 mtp_link_slta_recv(link);
376 return 0;
377 break;
378 }
379 break;
380 }
381
382 return -1;
383}
384
385static int mtp_link_sccp_data(struct mtp_link *link, struct mtp_level_3_hdr *hdr, struct msgb *msg, int l3_len)
386{
387 struct msgb *out;
388 struct sccp_con_ctrl_prt_mgt *prt;
389
390 msg->l2h = &hdr->data[0];
391 if (msgb_l2len(msg) != l3_len) {
392 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
393 return -1;
394 }
395
396
397 if (link->sccp_up) {
398 mtp_link_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
399 return 0;
400 } else {
401 struct sccp_parse_result sccp;
402 memset(&sccp, 0, sizeof(sccp));
403 if (sccp_parse_header(msg, &sccp) != 0) {
404 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
405 return -1;
406 }
407
408 if (sccp_determine_msg_type(msg) != SCCP_MSG_TYPE_UDT) {
409 LOGP(DINP, LOGL_ERROR, "Dropping sccp data: 0x%x\n",
410 sccp_determine_msg_type(msg));
411 return -1;
412 }
413
414 if (msgb_l3len(msg) != 5) {
415 LOGP(DINP, LOGL_ERROR, "SCCP UDT msg of unexpected size: %u\n",
416 msgb_l3len(msg));
417 return -1;
418 }
419
420 if (msg->l3h[0] != SCCP_SST) {
421 LOGP(DINP, LOGL_ERROR, "Expected SCCP SST but got 0x%x\n",
422 msg->l3h[0]);
423 return -1;
424 }
425
426 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
427 if (prt->assn != 254 || prt->apoc != MTP_MAKE_APOC(link->opc)) {
428 LOGP(DINP, LOGL_ERROR, "Unknown SSN/APOC assn: %u, apoc: %u/%u\n",
429 prt->assn, ntohs(prt->apoc), prt->apoc);
430 return -1;
431 }
432
433 out = mtp_sccp_alloc_ssa(link, MTP_LINK_SLS(hdr->addr));
434 if (!out)
435 return -1;
436
437 link->sccp_up = 1;
438 link->was_up = 1;
439 LOGP(DINP, LOGL_INFO, "SCCP is established. %p\n", link);
440 mtp_link_submit(link, out);
441 }
442 return 0;
443}
444
445int mtp_link_data(struct mtp_link *link, struct msgb *msg)
446{
447 int rc = -1;
448 struct mtp_level_3_hdr *hdr;
449 int l3_len;
450
451 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
452 return -1;
453
454 if (!link->running) {
455 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
456 return -1;
457 }
458
459 hdr = (struct mtp_level_3_hdr *) msg->l2h;
460 l3_len = msgb_l2len(msg) - sizeof(*hdr);
461
462 switch (hdr->ser_ind) {
463 case MTP_SI_MNT_SNM_MSG:
464 rc = mtp_link_sign_msg(link, hdr, l3_len);
465 break;
466 case MTP_SI_MNT_REG_MSG:
467 rc = mtp_link_regular_msg(link, hdr, l3_len);
468 break;
469 case MTP_SI_MNT_SCCP:
470 rc = mtp_link_sccp_data(link, hdr, msg, l3_len);
471 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100472 case MTP_SI_MNT_ISUP:
473 LOGP(DINP, LOGL_ERROR, "ISUP handling not implemented.\n");
474 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800475 default:
476 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
477 break;
478 }
479
480 return rc;
481}
482
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800483int 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 +0800484{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800485 uint8_t *put_ptr;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800486 struct mtp_level_3_hdr *hdr;
487 struct msgb *msg;
488
489 if (!link->sccp_up) {
490 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
491 return -1;
492 }
493
494 msg = mtp_msg_alloc(link);
495 if (!msg)
496 return -1;
497
498 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800499 hdr->ser_ind = MTP_SI_MNT_SCCP;
500
501 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->opc);
502
503 /* copy the raw sccp data */
504 put_ptr = msgb_put(msg, length);
505 memcpy(put_ptr, data, length);
506
507 mtp_link_submit(link, msg);
508 return 0;
509}