blob: c53000e8982584889c9ba3390c0ab2a915eed90d [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 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +01007 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080010 * (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
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080016 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080019 *
20 */
21#include <mtp_data.h>
22#include <mtp_level3.h>
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +010023#include <bsc_data.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080024#include <cellmgr_debug.h>
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +010025#include <isup_types.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080026
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080027#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080028
Holger Hans Peter Freythercf381e22010-08-04 18:39:26 +080029#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080030
31#include <arpa/inet.h>
32
33#include <string.h>
34
35static void *tall_mtp_ctx = NULL;
36
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010037static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type, const uint8_t *data, unsigned int length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +010038
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010039static struct msgb *mtp_msg_alloc(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080040{
41 struct mtp_level_3_hdr *hdr;
42 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
43 if (!msg) {
44 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
45 return NULL;
46 }
47
48 msg->l2h = msgb_put(msg, sizeof(*hdr));
49 hdr = (struct mtp_level_3_hdr *) msg->l2h;
50 hdr->addr = MTP_ADDR(0x0, link->dpc, link->opc);
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +010051 hdr->ni = link->ni;
Holger Hans Peter Freythere976df12010-11-26 21:07:11 +010052 hdr->spare = link->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080053 return msg;
54}
55
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010056static struct msgb *mtp_create_sltm(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080057{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080058 const uint8_t test_ptrn[14] = { 'G', 'S', 'M', 'M', 'M', 'S', };
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080059 struct mtp_level_3_hdr *hdr;
60 struct mtp_level_3_mng *mng;
61 struct msgb *msg = mtp_msg_alloc(link);
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080062 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080063 if (!msg)
64 return NULL;
65
66 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080067 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
68
69 mng = (struct mtp_level_3_mng *) msgb_put(msg, sizeof(*mng));
70 mng->cmn.h0 = MTP_TST_MSG_GRP;
71 mng->cmn.h1 = MTP_TST_MSG_SLTM;
72 mng->length = ARRAY_SIZE(test_ptrn);
73
74 data = msgb_put(msg, ARRAY_SIZE(test_ptrn));
75 memcpy(data, test_ptrn, ARRAY_SIZE(test_ptrn));
76
77 /* remember the last tst ptrn... once we have some */
78 memcpy(link->test_ptrn, test_ptrn, ARRAY_SIZE(test_ptrn));
79
80 return msg;
81}
82
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010083static struct msgb *mtp_create_slta(struct mtp_link_set *link, struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080084{
85 struct mtp_level_3_hdr *hdr;
86 struct mtp_level_3_mng *mng;
87 struct msgb *out = mtp_msg_alloc(link);
88
89 if (!out)
90 return NULL;
91
92 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080093 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
94 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
95 mng->cmn.h0 = MTP_TST_MSG_GRP;
96 mng->cmn.h1 = MTP_TST_MSG_SLTA;
97 mng->length = l3_len - 2;
98 msgb_put(out, mng->length);
99 memcpy(mng->data, in_mng->data, mng->length);
100
101 return out;
102}
103
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100104static struct msgb *mtp_tfp_alloc(struct mtp_link_set *link, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800105{
106 struct mtp_level_3_hdr *hdr;
107 struct mtp_level_3_prohib *prb;
108 struct msgb *out = mtp_msg_alloc(link);
109
110 if (!out)
111 return NULL;
112
113 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800114 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
115 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
116 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
117 prb->cmn.h1 = MTP_PROHIBIT_MSG_SIG;
118 prb->apoc = MTP_MAKE_APOC(apoc);
119 return out;
120}
121
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100122static struct msgb *mtp_tra_alloc(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800123{
124 struct mtp_level_3_hdr *hdr;
125 struct mtp_level_3_cmn *cmn;
126 struct msgb *out = mtp_msg_alloc(link);
127
128 if (!out)
129 return NULL;
130
131 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800132 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
133 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
134 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
135 cmn->h1 = MTP_RESTR_MSG_ALLWED;
136 return out;
137}
138
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100139static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *link,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100140 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800141{
142 struct sccp_data_unitdata *udt;
143 struct sccp_con_ctrl_prt_mgt *prt;
144 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800145 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800146
147
148 struct msgb *out = mtp_msg_alloc(link);
149
150 if (!out)
151 return NULL;
152
153 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800154 hdr->ser_ind = MTP_SI_MNT_SCCP;
155
156 /* this appears to be round robin or such.. */
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100157 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800158
159 /* generate the UDT message... libsccp does not offer formating yet */
160 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
161 udt->type = SCCP_MSG_TYPE_UDT;
162 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
163 udt->variable_called = 3;
164 udt->variable_calling = 5;
165 udt->variable_data = 7;
166
167 /* put the called and calling address. It is LV */
168 data = msgb_put(out, 2 + 1);
169 data[0] = 2;
170 data[1] = 0x42;
171 data[2] = 0x1;
172
173 data = msgb_put(out, 2 + 1);
174 data[0] = 2;
175 data[1] = 0x42;
176 data[2] = 0x1;
177
178 data = msgb_put(out, 1);
179 data[0] = sizeof(*prt);
180
181 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100182 prt->sst = type;
183 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100184 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800185 prt->mul_ind = 0;
186
187 return out;
188}
189
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100190void mtp_link_set_init(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800191{
192 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
193}
194
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100195static void mtp_send_sltm(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800196{
197 struct msgb *msg;
198
199 link->sltm_pending = 1;
200 msg = mtp_create_sltm(link);
201 if (!msg) {
202 LOGP(DINP, LOGL_ERROR, "Failed to allocate SLTM.\n");
203 return;
204 }
205
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100206 mtp_link_set_submit(link->slc[0], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800207}
208
209static void mtp_sltm_t1_timeout(void *_link)
210{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100211 struct mtp_link_set *link = (struct mtp_link_set *) _link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800212
213 if (link->slta_misses == 0) {
214 LOGP(DINP, LOGL_ERROR, "No SLTM response. Retrying. Link: %p\n", link);
215 ++link->slta_misses;
216 mtp_send_sltm(link);
217 bsc_schedule_timer(&link->t1_timer, MTP_T1);
218 } else {
219 LOGP(DINP, LOGL_ERROR, "Two missing SLTAs. Restart link: %p\n", link);
220 link->sccp_up = 0;
221 link->running = 0;
222 bsc_del_timer(&link->t2_timer);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100223 mtp_link_set_sccp_down(link);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100224 mtp_link_restart(link->slc[0]);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800225 }
226}
227
228static void mtp_sltm_t2_timeout(void *_link)
229{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100230 struct mtp_link_set *link = (struct mtp_link_set *) _link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800231
232 if (!link->running) {
233 LOGP(DINP, LOGL_INFO, "Not restarting SLTM timer on link: %p\n", link);
234 return;
235 }
236
237 link->slta_misses = 0;
238 mtp_send_sltm(link);
239
240 bsc_schedule_timer(&link->t1_timer, MTP_T1);
241
242 if (link->sltm_once && link->was_up)
243 LOGP(DINP, LOGL_INFO, "Not sending SLTM again as configured.\n");
244 else
245 bsc_schedule_timer(&link->t2_timer, MTP_T2);
246}
247
248static void mtp_delayed_start(void *link)
249{
250 mtp_sltm_t2_timeout(link);
251}
252
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100253struct mtp_link_set *mtp_link_set_alloc(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800254{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100255 struct mtp_link_set *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800256
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100257 link = talloc_zero(tall_mtp_ctx, struct mtp_link_set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800258 if (!link)
259 return NULL;
260
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100261 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800262 link->t1_timer.data = link;
263 link->t1_timer.cb = mtp_sltm_t1_timeout;
264 link->t2_timer.data = link;
265 link->t2_timer.cb = mtp_sltm_t2_timeout;
266 link->delay_timer.data = link;
267 link->delay_timer.cb = mtp_delayed_start;
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100268 INIT_LLIST_HEAD(&link->links);
269
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800270 return link;
271}
272
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100273void mtp_link_set_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800274{
275 bsc_del_timer(&link->t1_timer);
276 bsc_del_timer(&link->t2_timer);
277 bsc_del_timer(&link->delay_timer);
278 link->sccp_up = 0;
279 link->running = 0;
280 link->sltm_pending = 0;
281
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100282 mtp_link_set_sccp_down(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800283}
284
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100285void mtp_link_set_reset(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800286{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100287 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800288 link->running = 1;
289 bsc_schedule_timer(&link->delay_timer, START_DELAY);
290}
291
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100292static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800293{
294 struct msgb *msg;
295 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100296 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800297
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100298 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800299 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
300 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800301 return -1;
302 }
303
304 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
305 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
306 cmn->h0, cmn->h1);
307
308 switch (cmn->h0) {
309 case MTP_TRF_RESTR_MSG_GRP:
310 switch (cmn->h1) {
311 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherff9cd6f2010-12-31 21:47:14 +0100312 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800313 link->sccp_up = 0;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100314 mtp_link_set_sccp_down(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800315
316 msg = mtp_tfp_alloc(link, 0);
317 if (!msg)
318 return -1;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100319 mtp_link_set_submit(link->slc[0], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800320
321 msg = mtp_tra_alloc(link);
322 if (!msg)
323 return -1;
324
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100325 mtp_link_set_submit(link->slc[0], msg);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100326 link->sccp_up = 1;
327 link->was_up = 1;
328 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed. %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800329 return 0;
330 break;
331 }
332 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100333 case MTP_PROHIBIT_MSG_GRP:
334 switch (cmn->h1) {
335 case MTP_PROHIBIT_MSG_SIG:
336 if (l3_len < 3) {
337 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
338 return -1;
339 }
340
341 apc = (uint16_t *) &hdr->data[1];
342 LOGP(DINP, LOGL_INFO,
343 "TFP for the affected point code: %d\n", *apc);
344 return 0;
345 break;
346 }
347 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800348 }
349
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100350 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 +0800351 return -1;
352}
353
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100354static int mtp_link_regular_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800355{
356 struct msgb *out;
357 struct mtp_level_3_mng *mng;
358
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100359 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800360 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
361 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800362 return -1;
363 }
364
365 mng = (struct mtp_level_3_mng *) &hdr->data[0];
366 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
367 mng->cmn.h0, mng->cmn.h1);
368
369 switch (mng->cmn.h0) {
370 case MTP_TST_MSG_GRP:
371 switch (mng->cmn.h1) {
372 case MTP_TST_MSG_SLTM:
373 /* simply respond to the request... */
374 out = mtp_create_slta(link, mng, l3_len);
375 if (!out)
376 return -1;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100377 mtp_link_set_submit(link->slc[0], out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800378 return 0;
379 break;
380 case MTP_TST_MSG_SLTA:
381 if (mng->length != 14) {
382 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
383 return -1;
384 }
385
386 if (l3_len != 16) {
387 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
388 return -1;
389 }
390
391 if (memcmp(mng->data, link->test_ptrn, sizeof(link->test_ptrn)) != 0) {
392 LOGP(DINP, LOGL_ERROR, "Wrong test pattern SLTA\n");
393 return -1;
394 }
395
396 /* we had a matching slta */
397 bsc_del_timer(&link->t1_timer);
398 link->sltm_pending = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800399 return 0;
400 break;
401 }
402 break;
403 }
404
405 return -1;
406}
407
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100408static int mtp_link_sccp_data(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, struct msgb *msg, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800409{
410 struct msgb *out;
411 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100412 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100413 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800414
415 msg->l2h = &hdr->data[0];
416 if (msgb_l2len(msg) != l3_len) {
417 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
418 return -1;
419 }
420
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100421 if (!link->sccp_up) {
422 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
423 return -1;
424 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800425
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100426 memset(&sccp, 0, sizeof(sccp));
427 if (sccp_parse_header(msg, &sccp) != 0) {
428 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
429 return -1;
430 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800431
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100432 /* check if it is a SST */
433 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
434 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800435 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100436 LOGP(DINP, LOGL_ERROR,
437 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800438 msgb_l3len(msg));
439 return -1;
440 }
441
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800442 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100443 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100444 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
445 ntohs(prt->apoc), prt->apoc);
446 type = SCCP_SSP;
447 } else if (prt->assn != 1 && prt->assn != 254 &&
448 prt->assn != 7 && prt->assn != 8 && prt->assn != 146) {
449 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
450 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100451 type = SCCP_SSP;
452 } else {
453 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800454 }
455
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100456 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100457 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800458 if (!out)
459 return -1;
460
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100461 mtp_link_set_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100462 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800463 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100464
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100465 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800466 return 0;
467}
468
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100469int mtp_link_set_data(struct mtp_link_set *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800470{
471 int rc = -1;
472 struct mtp_level_3_hdr *hdr;
473 int l3_len;
474
475 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
476 return -1;
477
478 if (!link->running) {
479 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
480 return -1;
481 }
482
483 hdr = (struct mtp_level_3_hdr *) msg->l2h;
484 l3_len = msgb_l2len(msg) - sizeof(*hdr);
485
486 switch (hdr->ser_ind) {
487 case MTP_SI_MNT_SNM_MSG:
488 rc = mtp_link_sign_msg(link, hdr, l3_len);
489 break;
490 case MTP_SI_MNT_REG_MSG:
491 rc = mtp_link_regular_msg(link, hdr, l3_len);
492 break;
493 case MTP_SI_MNT_SCCP:
494 rc = mtp_link_sccp_data(link, hdr, msg, l3_len);
495 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100496 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100497 msg->l3h = &hdr->data[0];
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100498 rc = mtp_link_set_forward_isup(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100499 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800500 default:
501 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
502 break;
503 }
504
505 return rc;
506}
507
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100508int mtp_link_set_submit_sccp_data(struct mtp_link_set *link, int sls, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800509{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800510
511 if (!link->sccp_up) {
512 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
513 return -1;
514 }
515
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100516 if (sls == -1) {
517 sls = link->last_sls;
518 link->last_sls = (link->last_sls + 1) % 16;
519 }
520
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100521 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100522}
523
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100524int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100525 const uint8_t *data, unsigned int length)
526{
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100527 return mtp_int_submit(link, link->opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100528}
529
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100530static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100531 const uint8_t *data, unsigned int length)
532{
533 uint8_t *put_ptr;
534 struct mtp_level_3_hdr *hdr;
535 struct msgb *msg;
536
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800537 msg = mtp_msg_alloc(link);
538 if (!msg)
539 return -1;
540
541 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100542 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800543
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100544 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800545
546 /* copy the raw sccp data */
547 put_ptr = msgb_put(msg, length);
548 memcpy(put_ptr, data, length);
549
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100550 mtp_link_set_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800551 return 0;
552}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100553
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100554static struct mtp_link *find_next_link(struct mtp_link_set *set,
555 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100556{
557 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100558 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100559
560 if (llist_empty(&set->links))
561 return NULL;
562
563 if (data == NULL)
564 found = 1;
565
566 /* try to find the next one */
567 llist_for_each_entry(next, &set->links, entry) {
568 if (found && next->available)
569 return next;
570 if (next == data)
571 found = 1;
572 }
573
574 /* try to find any one */
575 llist_for_each_entry(next, &set->links, entry)
576 if (next->available)
577 return next;
578
579 return NULL;
580}
581
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100582void mtp_link_set_init_slc(struct mtp_link_set *set)
583{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100584 struct mtp_link *link = NULL;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100585 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100586
587
588 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
589 link = find_next_link(set, link);
590 set->slc[i] = link;
591 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100592}
593
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100594void mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100595{
596 llist_add_tail(&lnk->entry, &set->links);
597 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100598}