blob: 40839c7dd7ddac25b392fc6acebb73f1f10aab19 [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 Freythercfbe80f2011-01-18 20:35:11 +0100104static struct msgb *mtp_base_alloc(struct mtp_link_set *link, int msg, 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;
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100117 prb->cmn.h1 = msg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800118 prb->apoc = MTP_MAKE_APOC(apoc);
119 return out;
120}
121
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100122static struct msgb *mtp_tfp_alloc(struct mtp_link_set *link, int apoc)
123{
124 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
125}
126
127static struct msgb *mtp_tfa_alloc(struct mtp_link_set *link, int apoc)
128{
129 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
130}
131
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100132static struct msgb *mtp_tra_alloc(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800133{
134 struct mtp_level_3_hdr *hdr;
135 struct mtp_level_3_cmn *cmn;
136 struct msgb *out = mtp_msg_alloc(link);
137
138 if (!out)
139 return NULL;
140
141 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800142 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100143 hdr->addr = MTP_ADDR(0x0, link->dpc, opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800144 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
145 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
146 cmn->h1 = MTP_RESTR_MSG_ALLWED;
147 return out;
148}
149
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100150static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *link,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100151 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800152{
153 struct sccp_data_unitdata *udt;
154 struct sccp_con_ctrl_prt_mgt *prt;
155 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800156 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800157
158
159 struct msgb *out = mtp_msg_alloc(link);
160
161 if (!out)
162 return NULL;
163
164 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800165 hdr->ser_ind = MTP_SI_MNT_SCCP;
166
167 /* this appears to be round robin or such.. */
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100168 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800169
170 /* generate the UDT message... libsccp does not offer formating yet */
171 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
172 udt->type = SCCP_MSG_TYPE_UDT;
173 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
174 udt->variable_called = 3;
175 udt->variable_calling = 5;
176 udt->variable_data = 7;
177
178 /* put the called and calling address. It is LV */
179 data = msgb_put(out, 2 + 1);
180 data[0] = 2;
181 data[1] = 0x42;
182 data[2] = 0x1;
183
184 data = msgb_put(out, 2 + 1);
185 data[0] = 2;
186 data[1] = 0x42;
187 data[2] = 0x1;
188
189 data = msgb_put(out, 1);
190 data[0] = sizeof(*prt);
191
192 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100193 prt->sst = type;
194 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100195 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800196 prt->mul_ind = 0;
197
198 return out;
199}
200
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100201void mtp_link_set_init(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800202{
203 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
204}
205
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100206static void mtp_send_sltm(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800207{
208 struct msgb *msg;
209
210 link->sltm_pending = 1;
211 msg = mtp_create_sltm(link);
212 if (!msg) {
213 LOGP(DINP, LOGL_ERROR, "Failed to allocate SLTM.\n");
214 return;
215 }
216
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100217 mtp_link_set_submit(link->slc[0], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800218}
219
220static void mtp_sltm_t1_timeout(void *_link)
221{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100222 struct mtp_link_set *link = (struct mtp_link_set *) _link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800223
224 if (link->slta_misses == 0) {
225 LOGP(DINP, LOGL_ERROR, "No SLTM response. Retrying. Link: %p\n", link);
226 ++link->slta_misses;
227 mtp_send_sltm(link);
228 bsc_schedule_timer(&link->t1_timer, MTP_T1);
229 } else {
230 LOGP(DINP, LOGL_ERROR, "Two missing SLTAs. Restart link: %p\n", link);
231 link->sccp_up = 0;
232 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100233 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800234 bsc_del_timer(&link->t2_timer);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100235 mtp_link_set_sccp_down(link);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100236 mtp_link_restart(link->slc[0]);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800237 }
238}
239
240static void mtp_sltm_t2_timeout(void *_link)
241{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100242 struct mtp_link_set *link = (struct mtp_link_set *) _link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800243
244 if (!link->running) {
245 LOGP(DINP, LOGL_INFO, "Not restarting SLTM timer on link: %p\n", link);
246 return;
247 }
248
249 link->slta_misses = 0;
250 mtp_send_sltm(link);
251
252 bsc_schedule_timer(&link->t1_timer, MTP_T1);
253
254 if (link->sltm_once && link->was_up)
255 LOGP(DINP, LOGL_INFO, "Not sending SLTM again as configured.\n");
256 else
257 bsc_schedule_timer(&link->t2_timer, MTP_T2);
258}
259
260static void mtp_delayed_start(void *link)
261{
262 mtp_sltm_t2_timeout(link);
263}
264
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100265struct mtp_link_set *mtp_link_set_alloc(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800266{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100267 struct mtp_link_set *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800268
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100269 link = talloc_zero(tall_mtp_ctx, struct mtp_link_set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800270 if (!link)
271 return NULL;
272
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100273 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800274 link->t1_timer.data = link;
275 link->t1_timer.cb = mtp_sltm_t1_timeout;
276 link->t2_timer.data = link;
277 link->t2_timer.cb = mtp_sltm_t2_timeout;
278 link->delay_timer.data = link;
279 link->delay_timer.cb = mtp_delayed_start;
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100280 INIT_LLIST_HEAD(&link->links);
281
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800282 return link;
283}
284
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100285void mtp_link_set_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800286{
287 bsc_del_timer(&link->t1_timer);
288 bsc_del_timer(&link->t2_timer);
289 bsc_del_timer(&link->delay_timer);
290 link->sccp_up = 0;
291 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100292 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800293 link->sltm_pending = 0;
294
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100295 mtp_link_set_sccp_down(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800296}
297
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100298void mtp_link_set_reset(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800299{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100300 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800301 link->running = 1;
302 bsc_schedule_timer(&link->delay_timer, START_DELAY);
303}
304
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100305static int send_tfp(struct mtp_link_set *link, int apoc)
306{
307 struct msgb *msg;
308 msg = mtp_tfp_alloc(link, apoc);
309 if (!msg)
310 return -1;
311
312 mtp_link_set_submit(link->slc[0], msg);
313 return 0;
314}
315
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100316static int send_tra(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800317{
318 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100319 msg = mtp_tra_alloc(link, opc);
320 if (!msg)
321 return -1;
322 mtp_link_set_submit(link->slc[0], msg);
323 return 0;
324}
325
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100326static int send_tfa(struct mtp_link_set *link, int opc)
327{
328 struct msgb *msg;
329 msg = mtp_tfa_alloc(link, opc);
330 if (!msg)
331 return -1;
332 mtp_link_set_submit(link->slc[0], msg);
333 return 0;
334}
335
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100336static int linkset_up(struct mtp_link_set *set)
337{
338 /* the link set is already up */
339 if (set->linkset_up)
340 return 0;
341
342 if (send_tfp(set, 0) != 0)
343 return -1;
344 if (send_tfp(set, set->opc) != 0)
345 return -1;
346 if (set->sccp_opc != set->opc &&
347 send_tfp(set, set->sccp_opc) != 0)
348 return -1;
349 if (set->isup_opc != set->opc &&
350 send_tfp(set, set->isup_opc) != 0)
351 return -1;
352
353 /* Send the TRA for all PCs */
354 if (send_tra(set, set->opc) != 0)
355 return -1;
356 if (set->sccp_opc != set->opc &&
357 send_tfa(set, set->sccp_opc) != 0)
358 return -1;
359 if (set->isup_opc != set->opc &&
360 send_tfa(set, set->isup_opc) != 0)
361 return -1;
362
363 set->linkset_up = 1;
364 LOGP(DINP, LOGL_NOTICE,
365 "The linkset %p is considered running.\n", set);
366 return 0;
367}
368
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100369static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
370{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800371 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100372 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800373
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100374 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800375 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
376 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800377 return -1;
378 }
379
380 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
381 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
382 cmn->h0, cmn->h1);
383
384 switch (cmn->h0) {
385 case MTP_TRF_RESTR_MSG_GRP:
386 switch (cmn->h1) {
387 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherff9cd6f2010-12-31 21:47:14 +0100388 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800389 link->sccp_up = 0;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100390 mtp_link_set_sccp_down(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800391
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100392 link->sccp_up = 1;
393 link->was_up = 1;
394 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed. %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800395 return 0;
396 break;
397 }
398 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100399 case MTP_PROHIBIT_MSG_GRP:
400 switch (cmn->h1) {
401 case MTP_PROHIBIT_MSG_SIG:
402 if (l3_len < 3) {
403 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
404 return -1;
405 }
406
407 apc = (uint16_t *) &hdr->data[1];
408 LOGP(DINP, LOGL_INFO,
409 "TFP for the affected point code: %d\n", *apc);
410 return 0;
411 break;
412 }
413 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800414 }
415
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100416 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 +0800417 return -1;
418}
419
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100420static 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 +0800421{
422 struct msgb *out;
423 struct mtp_level_3_mng *mng;
424
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100425 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800426 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
427 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800428 return -1;
429 }
430
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100431 if (MTP_ADDR_DPC(hdr->addr) != link->opc) {
432 LOGP(DINP, LOGL_ERROR, "MSG for 0x%x not handled by 0x%x\n",
433 MTP_ADDR_DPC(hdr->addr), link->opc);
434 return -1;
435 }
436
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800437 mng = (struct mtp_level_3_mng *) &hdr->data[0];
438 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
439 mng->cmn.h0, mng->cmn.h1);
440
441 switch (mng->cmn.h0) {
442 case MTP_TST_MSG_GRP:
443 switch (mng->cmn.h1) {
444 case MTP_TST_MSG_SLTM:
445 /* simply respond to the request... */
446 out = mtp_create_slta(link, mng, l3_len);
447 if (!out)
448 return -1;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100449 mtp_link_set_submit(link->slc[0], out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800450 return 0;
451 break;
452 case MTP_TST_MSG_SLTA:
453 if (mng->length != 14) {
454 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
455 return -1;
456 }
457
458 if (l3_len != 16) {
459 LOGP(DINP, LOGL_ERROR, "Wrongly sized SLTA: %u\n", mng->length);
460 return -1;
461 }
462
463 if (memcmp(mng->data, link->test_ptrn, sizeof(link->test_ptrn)) != 0) {
464 LOGP(DINP, LOGL_ERROR, "Wrong test pattern SLTA\n");
465 return -1;
466 }
467
468 /* we had a matching slta */
469 bsc_del_timer(&link->t1_timer);
470 link->sltm_pending = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100471
472 /* This link of the linkset is now proven */
473 linkset_up(link);
474
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800475 return 0;
476 break;
477 }
478 break;
479 }
480
481 return -1;
482}
483
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100484static 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 +0800485{
486 struct msgb *out;
487 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100488 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100489 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800490
491 msg->l2h = &hdr->data[0];
492 if (msgb_l2len(msg) != l3_len) {
493 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
494 return -1;
495 }
496
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100497 if (!link->sccp_up) {
498 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
499 return -1;
500 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800501
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100502 memset(&sccp, 0, sizeof(sccp));
503 if (sccp_parse_header(msg, &sccp) != 0) {
504 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
505 return -1;
506 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800507
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100508 /* check if it is a SST */
509 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
510 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800511 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100512 LOGP(DINP, LOGL_ERROR,
513 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800514 msgb_l3len(msg));
515 return -1;
516 }
517
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800518 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100519 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100520 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
521 ntohs(prt->apoc), prt->apoc);
522 type = SCCP_SSP;
523 } else if (prt->assn != 1 && prt->assn != 254 &&
524 prt->assn != 7 && prt->assn != 8 && prt->assn != 146) {
525 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
526 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100527 type = SCCP_SSP;
528 } else {
529 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800530 }
531
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100532 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100533 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800534 if (!out)
535 return -1;
536
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100537 mtp_link_set_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100538 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800539 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100540
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100541 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800542 return 0;
543}
544
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100545int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800546{
547 int rc = -1;
548 struct mtp_level_3_hdr *hdr;
549 int l3_len;
550
551 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
552 return -1;
553
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100554 if (!link->the_link->running) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800555 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
556 return -1;
557 }
558
559 hdr = (struct mtp_level_3_hdr *) msg->l2h;
560 l3_len = msgb_l2len(msg) - sizeof(*hdr);
561
562 switch (hdr->ser_ind) {
563 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100564 rc = mtp_link_sign_msg(link->the_link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800565 break;
566 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100567 rc = mtp_link_regular_msg(link->the_link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800568 break;
569 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100570 rc = mtp_link_sccp_data(link->the_link, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800571 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100572 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100573 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100574 rc = mtp_link_set_isup(link->the_link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100575 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800576 default:
577 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
578 break;
579 }
580
581 return rc;
582}
583
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100584int 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 +0800585{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800586
587 if (!link->sccp_up) {
588 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
589 return -1;
590 }
591
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100592 if (sls == -1) {
593 sls = link->last_sls;
594 link->last_sls = (link->last_sls + 1) % 16;
595 }
596
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100597 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100598}
599
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100600int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100601 const uint8_t *data, unsigned int length)
602{
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100603 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100604}
605
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100606static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100607 const uint8_t *data, unsigned int length)
608{
609 uint8_t *put_ptr;
610 struct mtp_level_3_hdr *hdr;
611 struct msgb *msg;
612
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100613 if (!link->slc[sls % 16])
614 return -1;
615
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800616 msg = mtp_msg_alloc(link);
617 if (!msg)
618 return -1;
619
620 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100621 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800622
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100623 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800624
625 /* copy the raw sccp data */
626 put_ptr = msgb_put(msg, length);
627 memcpy(put_ptr, data, length);
628
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100629 mtp_link_set_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800630 return 0;
631}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100632
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100633static struct mtp_link *find_next_link(struct mtp_link_set *set,
634 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100635{
636 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100637 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100638
639 if (llist_empty(&set->links))
640 return NULL;
641
642 if (data == NULL)
643 found = 1;
644
645 /* try to find the next one */
646 llist_for_each_entry(next, &set->links, entry) {
647 if (found && next->available)
648 return next;
649 if (next == data)
650 found = 1;
651 }
652
653 /* try to find any one */
654 llist_for_each_entry(next, &set->links, entry)
655 if (next->available)
656 return next;
657
658 return NULL;
659}
660
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100661void mtp_link_set_init_slc(struct mtp_link_set *set)
662{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100663 struct mtp_link *link = NULL;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100664 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100665
666
667 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
668 link = find_next_link(set, link);
669 set->slc[i] = link;
670 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100671}
672
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100673void mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100674{
675 llist_add_tail(&lnk->entry, &set->links);
676 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100677}