blob: 67ae70eac562ef01cdd01d95ba6986fcc3def79b [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 Freythera8ce0612011-01-20 16:30:24 +010039struct 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 Freyther050577a2011-01-20 19:28:15 +010056static struct msgb *mtp_create_slta(struct mtp_link_set *link, int sls,
57 struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080058{
59 struct mtp_level_3_hdr *hdr;
60 struct mtp_level_3_mng *mng;
61 struct msgb *out = mtp_msg_alloc(link);
62
63 if (!out)
64 return NULL;
65
66 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080067 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010068 hdr->addr = MTP_ADDR(sls, link->dpc, link->opc);
69
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080070 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
71 mng->cmn.h0 = MTP_TST_MSG_GRP;
72 mng->cmn.h1 = MTP_TST_MSG_SLTA;
73 mng->length = l3_len - 2;
74 msgb_put(out, mng->length);
75 memcpy(mng->data, in_mng->data, mng->length);
76
77 return out;
78}
79
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010080
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +010081static struct msgb *mtp_base_alloc(struct mtp_link_set *link, int msg, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080082{
83 struct mtp_level_3_hdr *hdr;
84 struct mtp_level_3_prohib *prb;
85 struct msgb *out = mtp_msg_alloc(link);
86
87 if (!out)
88 return NULL;
89
90 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080091 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
92 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
93 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +010094 prb->cmn.h1 = msg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080095 prb->apoc = MTP_MAKE_APOC(apoc);
96 return out;
97}
98
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +010099static struct msgb *mtp_tfp_alloc(struct mtp_link_set *link, int apoc)
100{
101 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
102}
103
104static struct msgb *mtp_tfa_alloc(struct mtp_link_set *link, int apoc)
105{
106 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
107}
108
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100109static struct msgb *mtp_tra_alloc(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800110{
111 struct mtp_level_3_hdr *hdr;
112 struct mtp_level_3_cmn *cmn;
113 struct msgb *out = mtp_msg_alloc(link);
114
115 if (!out)
116 return NULL;
117
118 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800119 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100120 hdr->addr = MTP_ADDR(0x0, link->dpc, opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800121 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
122 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
123 cmn->h1 = MTP_RESTR_MSG_ALLWED;
124 return out;
125}
126
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100127static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *link,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100128 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800129{
130 struct sccp_data_unitdata *udt;
131 struct sccp_con_ctrl_prt_mgt *prt;
132 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800133 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800134
135
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_SCCP;
143
144 /* this appears to be round robin or such.. */
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100145 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800146
147 /* generate the UDT message... libsccp does not offer formating yet */
148 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
149 udt->type = SCCP_MSG_TYPE_UDT;
150 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
151 udt->variable_called = 3;
152 udt->variable_calling = 5;
153 udt->variable_data = 7;
154
155 /* put the called and calling address. It is LV */
156 data = msgb_put(out, 2 + 1);
157 data[0] = 2;
158 data[1] = 0x42;
159 data[2] = 0x1;
160
161 data = msgb_put(out, 2 + 1);
162 data[0] = 2;
163 data[1] = 0x42;
164 data[2] = 0x1;
165
166 data = msgb_put(out, 1);
167 data[0] = sizeof(*prt);
168
169 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100170 prt->sst = type;
171 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100172 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800173 prt->mul_ind = 0;
174
175 return out;
176}
177
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100178void mtp_link_set_init(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800179{
180 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
181}
182
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100183struct mtp_link_set *mtp_link_set_alloc(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800184{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100185 struct mtp_link_set *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800186
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100187 link = talloc_zero(tall_mtp_ctx, struct mtp_link_set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800188 if (!link)
189 return NULL;
190
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100191 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100192 INIT_LLIST_HEAD(&link->links);
193
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800194 return link;
195}
196
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100197void mtp_link_set_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800198{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100199 struct mtp_link *lnk;
200 llist_for_each_entry(lnk, &link->links, entry)
201 mtp_link_stop_link_test(lnk);
202
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800203 link->sccp_up = 0;
204 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100205 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800206}
207
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100208void mtp_link_set_reset(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800209{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100210 struct mtp_link *lnk;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100211 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800212 link->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100213
214 llist_for_each_entry(lnk, &link->links, entry)
215 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800216}
217
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100218static int send_tfp(struct mtp_link_set *link, int apoc)
219{
220 struct msgb *msg;
221 msg = mtp_tfp_alloc(link, apoc);
222 if (!msg)
223 return -1;
224
225 mtp_link_set_submit(link->slc[0], msg);
226 return 0;
227}
228
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100229static int send_tra(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800230{
231 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100232 msg = mtp_tra_alloc(link, opc);
233 if (!msg)
234 return -1;
235 mtp_link_set_submit(link->slc[0], msg);
236 return 0;
237}
238
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100239static int send_tfa(struct mtp_link_set *link, int opc)
240{
241 struct msgb *msg;
242 msg = mtp_tfa_alloc(link, opc);
243 if (!msg)
244 return -1;
245 mtp_link_set_submit(link->slc[0], msg);
246 return 0;
247}
248
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100249static int linkset_up(struct mtp_link_set *set)
250{
251 /* the link set is already up */
252 if (set->linkset_up)
253 return 0;
254
255 if (send_tfp(set, 0) != 0)
256 return -1;
257 if (send_tfp(set, set->opc) != 0)
258 return -1;
259 if (set->sccp_opc != set->opc &&
260 send_tfp(set, set->sccp_opc) != 0)
261 return -1;
262 if (set->isup_opc != set->opc &&
263 send_tfp(set, set->isup_opc) != 0)
264 return -1;
265
266 /* Send the TRA for all PCs */
267 if (send_tra(set, set->opc) != 0)
268 return -1;
269 if (set->sccp_opc != set->opc &&
270 send_tfa(set, set->sccp_opc) != 0)
271 return -1;
272 if (set->isup_opc != set->opc &&
273 send_tfa(set, set->isup_opc) != 0)
274 return -1;
275
276 set->linkset_up = 1;
277 LOGP(DINP, LOGL_NOTICE,
278 "The linkset %p is considered running.\n", set);
279 return 0;
280}
281
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100282static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
283{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800284 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100285 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800286
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100287 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800288 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
289 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800290 return -1;
291 }
292
293 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
294 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
295 cmn->h0, cmn->h1);
296
297 switch (cmn->h0) {
298 case MTP_TRF_RESTR_MSG_GRP:
299 switch (cmn->h1) {
300 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherff9cd6f2010-12-31 21:47:14 +0100301 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %p\n", link);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100302 link->sccp_up = 1;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100303 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed. %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800304 return 0;
305 break;
306 }
307 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100308 case MTP_PROHIBIT_MSG_GRP:
309 switch (cmn->h1) {
310 case MTP_PROHIBIT_MSG_SIG:
311 if (l3_len < 3) {
312 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
313 return -1;
314 }
315
316 apc = (uint16_t *) &hdr->data[1];
317 LOGP(DINP, LOGL_INFO,
318 "TFP for the affected point code: %d\n", *apc);
319 return 0;
320 break;
321 }
322 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800323 }
324
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100325 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 +0800326 return -1;
327}
328
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100329static int mtp_link_regular_msg(struct mtp_link *link, struct mtp_level_3_hdr *hdr, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800330{
331 struct msgb *out;
332 struct mtp_level_3_mng *mng;
333
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100334 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800335 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
336 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800337 return -1;
338 }
339
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100340 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100341 LOGP(DINP, LOGL_ERROR, "MSG for 0x%x not handled by 0x%x\n",
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100342 MTP_ADDR_DPC(hdr->addr), link->set->opc);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100343 return -1;
344 }
345
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800346 mng = (struct mtp_level_3_mng *) &hdr->data[0];
347 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
348 mng->cmn.h0, mng->cmn.h1);
349
350 switch (mng->cmn.h0) {
351 case MTP_TST_MSG_GRP:
352 switch (mng->cmn.h1) {
353 case MTP_TST_MSG_SLTM:
354 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100355 out = mtp_create_slta(link->set,
356 MTP_LINK_SLS(hdr->addr),
357 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800358 if (!out)
359 return -1;
Holger Hans Peter Freyther95057b92011-01-20 19:00:44 +0100360 mtp_link_set_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800361 return 0;
362 break;
363 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100364 /* If this link is proven set it up */
365 if (mtp_link_slta(link, l3_len, mng) == 0)
366 linkset_up(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800367 break;
368 }
369 break;
370 }
371
372 return -1;
373}
374
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100375static 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 +0800376{
377 struct msgb *out;
378 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100379 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100380 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800381
382 msg->l2h = &hdr->data[0];
383 if (msgb_l2len(msg) != l3_len) {
384 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
385 return -1;
386 }
387
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100388 if (!link->sccp_up) {
389 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
390 return -1;
391 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800392
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100393 memset(&sccp, 0, sizeof(sccp));
394 if (sccp_parse_header(msg, &sccp) != 0) {
395 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
396 return -1;
397 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800398
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100399 /* check if it is a SST */
400 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
401 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800402 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100403 LOGP(DINP, LOGL_ERROR,
404 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800405 msgb_l3len(msg));
406 return -1;
407 }
408
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800409 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100410 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100411 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
412 ntohs(prt->apoc), prt->apoc);
413 type = SCCP_SSP;
414 } else if (prt->assn != 1 && prt->assn != 254 &&
415 prt->assn != 7 && prt->assn != 8 && prt->assn != 146) {
416 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
417 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100418 type = SCCP_SSP;
419 } else {
420 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800421 }
422
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100423 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100424 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800425 if (!out)
426 return -1;
427
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100428 mtp_link_set_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100429 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800430 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100431
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100432 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800433 return 0;
434}
435
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100436int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800437{
438 int rc = -1;
439 struct mtp_level_3_hdr *hdr;
440 int l3_len;
441
442 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
443 return -1;
444
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100445 if (!link->set->running) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800446 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
447 return -1;
448 }
449
450 hdr = (struct mtp_level_3_hdr *) msg->l2h;
451 l3_len = msgb_l2len(msg) - sizeof(*hdr);
452
453 switch (hdr->ser_ind) {
454 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100455 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800456 break;
457 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100458 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800459 break;
460 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100461 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800462 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100463 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100464 msg->l3h = &hdr->data[0];
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100465 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100466 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800467 default:
468 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
469 break;
470 }
471
472 return rc;
473}
474
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100475int 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 +0800476{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800477
478 if (!link->sccp_up) {
479 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
480 return -1;
481 }
482
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100483 if (sls == -1) {
484 sls = link->last_sls;
485 link->last_sls = (link->last_sls + 1) % 16;
486 }
487
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100488 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100489}
490
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100491int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100492 const uint8_t *data, unsigned int length)
493{
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100494 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100495}
496
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100497static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100498 const uint8_t *data, unsigned int length)
499{
500 uint8_t *put_ptr;
501 struct mtp_level_3_hdr *hdr;
502 struct msgb *msg;
503
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100504 if (!link->slc[sls % 16])
505 return -1;
506
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800507 msg = mtp_msg_alloc(link);
508 if (!msg)
509 return -1;
510
511 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100512 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800513
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100514 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800515
516 /* copy the raw sccp data */
517 put_ptr = msgb_put(msg, length);
518 memcpy(put_ptr, data, length);
519
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100520 mtp_link_set_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800521 return 0;
522}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100523
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100524static struct mtp_link *find_next_link(struct mtp_link_set *set,
525 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100526{
527 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100528 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100529
530 if (llist_empty(&set->links))
531 return NULL;
532
533 if (data == NULL)
534 found = 1;
535
536 /* try to find the next one */
537 llist_for_each_entry(next, &set->links, entry) {
538 if (found && next->available)
539 return next;
540 if (next == data)
541 found = 1;
542 }
543
544 /* try to find any one */
545 llist_for_each_entry(next, &set->links, entry)
546 if (next->available)
547 return next;
548
549 return NULL;
550}
551
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100552void mtp_link_set_init_slc(struct mtp_link_set *set)
553{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100554 struct mtp_link *link = NULL;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100555 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100556
557
558 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
559 link = find_next_link(set, link);
560 set->slc[i] = link;
561 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100562}
563
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100564void mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100565{
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100566 lnk->set = set;
Holger Hans Peter Freyther1cc24562011-01-20 18:26:18 +0100567 lnk->link_no = set->nr_links++;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100568 mtp_link_init(lnk);
569
570 llist_add_tail(&lnk->entry, &set->links);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100571 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100572}