blob: 6dee90f5078b5ac736eb97f0c68325417471f7e2 [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 Freytherc5d897e2011-01-21 20:54:55 +010026#include <counter.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080027
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080028#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080029
Holger Hans Peter Freythercf381e22010-08-04 18:39:26 +080030#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080031
32#include <arpa/inet.h>
33
34#include <string.h>
35
36static void *tall_mtp_ctx = NULL;
37
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010038static 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 +010039
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010040void mtp_link_set_submit(struct mtp_link *link, struct msgb *msg)
41{
42 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_OUT_MSG]);
43 link->write(link, msg);
44}
45
46
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010047struct msgb *mtp_msg_alloc(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080048{
49 struct mtp_level_3_hdr *hdr;
50 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
51 if (!msg) {
52 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
53 return NULL;
54 }
55
56 msg->l2h = msgb_put(msg, sizeof(*hdr));
57 hdr = (struct mtp_level_3_hdr *) msg->l2h;
58 hdr->addr = MTP_ADDR(0x0, link->dpc, link->opc);
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +010059 hdr->ni = link->ni;
Holger Hans Peter Freythere976df12010-11-26 21:07:11 +010060 hdr->spare = link->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080061 return msg;
62}
63
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010064static struct msgb *mtp_create_slta(struct mtp_link_set *link, int sls,
65 struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080066{
67 struct mtp_level_3_hdr *hdr;
68 struct mtp_level_3_mng *mng;
69 struct msgb *out = mtp_msg_alloc(link);
70
71 if (!out)
72 return NULL;
73
74 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080075 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010076 hdr->addr = MTP_ADDR(sls, link->dpc, link->opc);
77
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080078 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
79 mng->cmn.h0 = MTP_TST_MSG_GRP;
80 mng->cmn.h1 = MTP_TST_MSG_SLTA;
81 mng->length = l3_len - 2;
82 msgb_put(out, mng->length);
83 memcpy(mng->data, in_mng->data, mng->length);
84
85 return out;
86}
87
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010088
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +010089static struct msgb *mtp_base_alloc(struct mtp_link_set *link, int msg, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080090{
91 struct mtp_level_3_hdr *hdr;
92 struct mtp_level_3_prohib *prb;
93 struct msgb *out = mtp_msg_alloc(link);
94
95 if (!out)
96 return NULL;
97
98 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080099 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
100 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
101 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100102 prb->cmn.h1 = msg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800103 prb->apoc = MTP_MAKE_APOC(apoc);
104 return out;
105}
106
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100107static struct msgb *mtp_tfp_alloc(struct mtp_link_set *link, int apoc)
108{
109 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
110}
111
112static struct msgb *mtp_tfa_alloc(struct mtp_link_set *link, int apoc)
113{
114 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
115}
116
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100117static struct msgb *mtp_tra_alloc(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800118{
119 struct mtp_level_3_hdr *hdr;
120 struct mtp_level_3_cmn *cmn;
121 struct msgb *out = mtp_msg_alloc(link);
122
123 if (!out)
124 return NULL;
125
126 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800127 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100128 hdr->addr = MTP_ADDR(0x0, link->dpc, opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800129 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
130 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
131 cmn->h1 = MTP_RESTR_MSG_ALLWED;
132 return out;
133}
134
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100135static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *link,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100136 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800137{
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.. */
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100153 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800154
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));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100178 prt->sst = type;
179 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100180 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800181 prt->mul_ind = 0;
182
183 return out;
184}
185
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100186void mtp_link_set_init(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800187{
188 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
189}
190
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100191struct mtp_link_set *mtp_link_set_alloc(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800192{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100193 static int linkset_no = 0;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100194 struct mtp_link_set *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800195
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100196 link = talloc_zero(tall_mtp_ctx, struct mtp_link_set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800197 if (!link)
198 return NULL;
199
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100200 link->ctrg = rate_ctr_group_alloc(link,
201 mtp_link_set_rate_ctr_desc(),
202 linkset_no++);
203 if (!link->ctrg) {
204 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
205 return NULL;
206 }
207
208
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100209 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100210 INIT_LLIST_HEAD(&link->links);
211
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800212 return link;
213}
214
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100215void mtp_link_set_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800216{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100217 struct mtp_link *lnk;
218 llist_for_each_entry(lnk, &link->links, entry)
219 mtp_link_stop_link_test(lnk);
220
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800221 link->sccp_up = 0;
222 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100223 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800224}
225
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100226void mtp_link_set_reset(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800227{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100228 struct mtp_link *lnk;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100229 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800230 link->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100231
232 llist_for_each_entry(lnk, &link->links, entry)
233 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800234}
235
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100236static int send_tfp(struct mtp_link_set *link, int apoc)
237{
238 struct msgb *msg;
239 msg = mtp_tfp_alloc(link, apoc);
240 if (!msg)
241 return -1;
242
243 mtp_link_set_submit(link->slc[0], msg);
244 return 0;
245}
246
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100247static int send_tra(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800248{
249 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100250 msg = mtp_tra_alloc(link, opc);
251 if (!msg)
252 return -1;
253 mtp_link_set_submit(link->slc[0], msg);
254 return 0;
255}
256
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100257static int send_tfa(struct mtp_link_set *link, int opc)
258{
259 struct msgb *msg;
260 msg = mtp_tfa_alloc(link, opc);
261 if (!msg)
262 return -1;
263 mtp_link_set_submit(link->slc[0], msg);
264 return 0;
265}
266
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100267static int linkset_up(struct mtp_link_set *set)
268{
269 /* the link set is already up */
270 if (set->linkset_up)
271 return 0;
272
273 if (send_tfp(set, 0) != 0)
274 return -1;
275 if (send_tfp(set, set->opc) != 0)
276 return -1;
277 if (set->sccp_opc != set->opc &&
278 send_tfp(set, set->sccp_opc) != 0)
279 return -1;
280 if (set->isup_opc != set->opc &&
281 send_tfp(set, set->isup_opc) != 0)
282 return -1;
283
284 /* Send the TRA for all PCs */
285 if (send_tra(set, set->opc) != 0)
286 return -1;
287 if (set->sccp_opc != set->opc &&
288 send_tfa(set, set->sccp_opc) != 0)
289 return -1;
290 if (set->isup_opc != set->opc &&
291 send_tfa(set, set->isup_opc) != 0)
292 return -1;
293
294 set->linkset_up = 1;
295 LOGP(DINP, LOGL_NOTICE,
296 "The linkset %p is considered running.\n", set);
297 return 0;
298}
299
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100300static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
301{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800302 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100303 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800304
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100305 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800306 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
307 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800308 return -1;
309 }
310
311 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
312 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
313 cmn->h0, cmn->h1);
314
315 switch (cmn->h0) {
316 case MTP_TRF_RESTR_MSG_GRP:
317 switch (cmn->h1) {
318 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherff9cd6f2010-12-31 21:47:14 +0100319 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %p\n", link);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100320 link->sccp_up = 1;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100321 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed. %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800322 return 0;
323 break;
324 }
325 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100326 case MTP_PROHIBIT_MSG_GRP:
327 switch (cmn->h1) {
328 case MTP_PROHIBIT_MSG_SIG:
329 if (l3_len < 3) {
330 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
331 return -1;
332 }
333
334 apc = (uint16_t *) &hdr->data[1];
335 LOGP(DINP, LOGL_INFO,
336 "TFP for the affected point code: %d\n", *apc);
337 return 0;
338 break;
339 }
340 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800341 }
342
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100343 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 +0800344 return -1;
345}
346
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100347static 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 +0800348{
349 struct msgb *out;
350 struct mtp_level_3_mng *mng;
351
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100352 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800353 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
354 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800355 return -1;
356 }
357
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100358 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100359 LOGP(DINP, LOGL_ERROR, "MSG for 0x%x not handled by 0x%x\n",
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100360 MTP_ADDR_DPC(hdr->addr), link->set->opc);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100361 return -1;
362 }
363
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800364 mng = (struct mtp_level_3_mng *) &hdr->data[0];
365 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
366 mng->cmn.h0, mng->cmn.h1);
367
368 switch (mng->cmn.h0) {
369 case MTP_TST_MSG_GRP:
370 switch (mng->cmn.h1) {
371 case MTP_TST_MSG_SLTM:
372 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100373 out = mtp_create_slta(link->set,
374 MTP_LINK_SLS(hdr->addr),
375 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800376 if (!out)
377 return -1;
Holger Hans Peter Freyther95057b92011-01-20 19:00:44 +0100378 mtp_link_set_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800379 return 0;
380 break;
381 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100382 /* If this link is proven set it up */
383 if (mtp_link_slta(link, l3_len, mng) == 0)
384 linkset_up(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800385 break;
386 }
387 break;
388 }
389
390 return -1;
391}
392
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100393static 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 +0800394{
395 struct msgb *out;
396 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100397 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100398 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800399
400 msg->l2h = &hdr->data[0];
401 if (msgb_l2len(msg) != l3_len) {
402 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
403 return -1;
404 }
405
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100406 if (!link->sccp_up) {
407 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
408 return -1;
409 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800410
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100411 memset(&sccp, 0, sizeof(sccp));
412 if (sccp_parse_header(msg, &sccp) != 0) {
413 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
414 return -1;
415 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800416
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100417 /* check if it is a SST */
418 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
419 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800420 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100421 LOGP(DINP, LOGL_ERROR,
422 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800423 msgb_l3len(msg));
424 return -1;
425 }
426
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800427 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100428 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100429 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
430 ntohs(prt->apoc), prt->apoc);
431 type = SCCP_SSP;
432 } else if (prt->assn != 1 && prt->assn != 254 &&
433 prt->assn != 7 && prt->assn != 8 && prt->assn != 146) {
434 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
435 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100436 type = SCCP_SSP;
437 } else {
438 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800439 }
440
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100441 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100442 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800443 if (!out)
444 return -1;
445
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100446 mtp_link_set_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100447 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800448 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100449
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100450 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100451 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800452 return 0;
453}
454
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100455int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800456{
457 int rc = -1;
458 struct mtp_level_3_hdr *hdr;
459 int l3_len;
460
461 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
462 return -1;
463
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100464 if (!link->set->running) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800465 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
466 return -1;
467 }
468
469 hdr = (struct mtp_level_3_hdr *) msg->l2h;
470 l3_len = msgb_l2len(msg) - sizeof(*hdr);
471
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100472 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
473
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800474 switch (hdr->ser_ind) {
475 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100476 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800477 break;
478 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100479 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800480 break;
481 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100482 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800483 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100484 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100485 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100486 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100487 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100488 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800489 default:
490 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
491 break;
492 }
493
494 return rc;
495}
496
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100497int 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 +0800498{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800499
500 if (!link->sccp_up) {
501 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
502 return -1;
503 }
504
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100505 if (sls == -1) {
506 sls = link->last_sls;
507 link->last_sls = (link->last_sls + 1) % 16;
508 }
509
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100510 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100511 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100512}
513
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100514int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100515 const uint8_t *data, unsigned int length)
516{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100517 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100518 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100519}
520
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100521static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100522 const uint8_t *data, unsigned int length)
523{
524 uint8_t *put_ptr;
525 struct mtp_level_3_hdr *hdr;
526 struct msgb *msg;
527
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100528 if (!link->slc[sls % 16])
529 return -1;
530
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800531 msg = mtp_msg_alloc(link);
532 if (!msg)
533 return -1;
534
535 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100536 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800537
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100538 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800539
540 /* copy the raw sccp data */
541 put_ptr = msgb_put(msg, length);
542 memcpy(put_ptr, data, length);
543
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100544 mtp_link_set_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800545 return 0;
546}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100547
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100548static struct mtp_link *find_next_link(struct mtp_link_set *set,
549 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100550{
551 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100552 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100553
554 if (llist_empty(&set->links))
555 return NULL;
556
557 if (data == NULL)
558 found = 1;
559
560 /* try to find the next one */
561 llist_for_each_entry(next, &set->links, entry) {
562 if (found && next->available)
563 return next;
564 if (next == data)
565 found = 1;
566 }
567
568 /* try to find any one */
569 llist_for_each_entry(next, &set->links, entry)
570 if (next->available)
571 return next;
572
573 return NULL;
574}
575
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100576void mtp_link_set_init_slc(struct mtp_link_set *set)
577{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100578 struct mtp_link *link = NULL;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100579 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100580
581
582 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
583 link = find_next_link(set, link);
584 set->slc[i] = link;
585 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100586}
587
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100588void mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100589{
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100590 lnk->set = set;
Holger Hans Peter Freyther1cc24562011-01-20 18:26:18 +0100591 lnk->link_no = set->nr_links++;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100592 mtp_link_init(lnk);
593
594 llist_add_tail(&lnk->entry, &set->links);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100595 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100596}