blob: 4f6564cc73f3b25e2a0b8205935ec69c8263af72 [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 Freyther9543f4a2011-01-24 20:49:58 +010040void mtp_link_submit(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010041{
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010042 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_OUT]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010043 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_OUT_MSG]);
44 link->write(link, msg);
45}
46
47
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010048struct msgb *mtp_msg_alloc(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080049{
50 struct mtp_level_3_hdr *hdr;
51 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
52 if (!msg) {
53 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
54 return NULL;
55 }
56
57 msg->l2h = msgb_put(msg, sizeof(*hdr));
58 hdr = (struct mtp_level_3_hdr *) msg->l2h;
59 hdr->addr = MTP_ADDR(0x0, link->dpc, link->opc);
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +010060 hdr->ni = link->ni;
Holger Hans Peter Freythere976df12010-11-26 21:07:11 +010061 hdr->spare = link->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080062 return msg;
63}
64
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010065static struct msgb *mtp_create_slta(struct mtp_link_set *link, int sls,
66 struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080067{
68 struct mtp_level_3_hdr *hdr;
69 struct mtp_level_3_mng *mng;
70 struct msgb *out = mtp_msg_alloc(link);
71
72 if (!out)
73 return NULL;
74
75 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080076 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010077 hdr->addr = MTP_ADDR(sls, link->dpc, link->opc);
78
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080079 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
80 mng->cmn.h0 = MTP_TST_MSG_GRP;
81 mng->cmn.h1 = MTP_TST_MSG_SLTA;
82 mng->length = l3_len - 2;
83 msgb_put(out, mng->length);
84 memcpy(mng->data, in_mng->data, mng->length);
85
86 return out;
87}
88
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010089
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +010090static struct msgb *mtp_base_alloc(struct mtp_link_set *link, int msg, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080091{
92 struct mtp_level_3_hdr *hdr;
93 struct mtp_level_3_prohib *prb;
94 struct msgb *out = mtp_msg_alloc(link);
95
96 if (!out)
97 return NULL;
98
99 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800100 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
101 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
102 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100103 prb->cmn.h1 = msg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800104 prb->apoc = MTP_MAKE_APOC(apoc);
105 return out;
106}
107
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100108static struct msgb *mtp_tfp_alloc(struct mtp_link_set *link, int apoc)
109{
110 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
111}
112
113static struct msgb *mtp_tfa_alloc(struct mtp_link_set *link, int apoc)
114{
115 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
116}
117
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100118static struct msgb *mtp_tra_alloc(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800119{
120 struct mtp_level_3_hdr *hdr;
121 struct mtp_level_3_cmn *cmn;
122 struct msgb *out = mtp_msg_alloc(link);
123
124 if (!out)
125 return NULL;
126
127 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800128 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100129 hdr->addr = MTP_ADDR(0x0, link->dpc, opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800130 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
131 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
132 cmn->h1 = MTP_RESTR_MSG_ALLWED;
133 return out;
134}
135
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100136static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *link,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100137 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800138{
139 struct sccp_data_unitdata *udt;
140 struct sccp_con_ctrl_prt_mgt *prt;
141 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800142 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800143
144
145 struct msgb *out = mtp_msg_alloc(link);
146
147 if (!out)
148 return NULL;
149
150 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800151 hdr->ser_ind = MTP_SI_MNT_SCCP;
152
153 /* this appears to be round robin or such.. */
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100154 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800155
156 /* generate the UDT message... libsccp does not offer formating yet */
157 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
158 udt->type = SCCP_MSG_TYPE_UDT;
159 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
160 udt->variable_called = 3;
161 udt->variable_calling = 5;
162 udt->variable_data = 7;
163
164 /* put the called and calling address. It is LV */
165 data = msgb_put(out, 2 + 1);
166 data[0] = 2;
167 data[1] = 0x42;
168 data[2] = 0x1;
169
170 data = msgb_put(out, 2 + 1);
171 data[0] = 2;
172 data[1] = 0x42;
173 data[2] = 0x1;
174
175 data = msgb_put(out, 1);
176 data[0] = sizeof(*prt);
177
178 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100179 prt->sst = type;
180 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100181 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800182 prt->mul_ind = 0;
183
184 return out;
185}
186
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100187void mtp_link_set_init(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800188{
189 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
190}
191
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100192struct mtp_link_set *mtp_link_set_alloc(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800193{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100194 static int linkset_no = 0;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100195 struct mtp_link_set *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800196
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100197 link = talloc_zero(tall_mtp_ctx, struct mtp_link_set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800198 if (!link)
199 return NULL;
200
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100201 link->ctrg = rate_ctr_group_alloc(link,
202 mtp_link_set_rate_ctr_desc(),
203 linkset_no++);
204 if (!link->ctrg) {
205 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
206 return NULL;
207 }
208
209
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100210 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100211 INIT_LLIST_HEAD(&link->links);
212
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800213 return link;
214}
215
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100216void mtp_link_set_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800217{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100218 struct mtp_link *lnk;
219 llist_for_each_entry(lnk, &link->links, entry)
220 mtp_link_stop_link_test(lnk);
221
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800222 link->sccp_up = 0;
223 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100224 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800225}
226
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100227void mtp_link_set_reset(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800228{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100229 struct mtp_link *lnk;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100230 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800231 link->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100232
233 llist_for_each_entry(lnk, &link->links, entry)
234 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800235}
236
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100237static int send_tfp(struct mtp_link_set *link, int apoc)
238{
239 struct msgb *msg;
240 msg = mtp_tfp_alloc(link, apoc);
241 if (!msg)
242 return -1;
243
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100244 mtp_link_submit(link->slc[0], msg);
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100245 return 0;
246}
247
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100248static int send_tra(struct mtp_link_set *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800249{
250 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100251 msg = mtp_tra_alloc(link, opc);
252 if (!msg)
253 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100254 mtp_link_submit(link->slc[0], msg);
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100255 return 0;
256}
257
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100258static int send_tfa(struct mtp_link_set *link, int opc)
259{
260 struct msgb *msg;
261 msg = mtp_tfa_alloc(link, opc);
262 if (!msg)
263 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100264 mtp_link_submit(link->slc[0], msg);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100265 return 0;
266}
267
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100268static int linkset_up(struct mtp_link_set *set)
269{
270 /* the link set is already up */
271 if (set->linkset_up)
272 return 0;
273
274 if (send_tfp(set, 0) != 0)
275 return -1;
276 if (send_tfp(set, set->opc) != 0)
277 return -1;
278 if (set->sccp_opc != set->opc &&
279 send_tfp(set, set->sccp_opc) != 0)
280 return -1;
281 if (set->isup_opc != set->opc &&
282 send_tfp(set, set->isup_opc) != 0)
283 return -1;
284
285 /* Send the TRA for all PCs */
286 if (send_tra(set, set->opc) != 0)
287 return -1;
288 if (set->sccp_opc != set->opc &&
289 send_tfa(set, set->sccp_opc) != 0)
290 return -1;
291 if (set->isup_opc != set->opc &&
292 send_tfa(set, set->isup_opc) != 0)
293 return -1;
294
295 set->linkset_up = 1;
296 LOGP(DINP, LOGL_NOTICE,
297 "The linkset %p is considered running.\n", set);
298 return 0;
299}
300
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100301static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
302{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800303 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100304 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800305
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100306 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800307 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
308 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800309 return -1;
310 }
311
312 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
313 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
314 cmn->h0, cmn->h1);
315
316 switch (cmn->h0) {
317 case MTP_TRF_RESTR_MSG_GRP:
318 switch (cmn->h1) {
319 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherff9cd6f2010-12-31 21:47:14 +0100320 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %p\n", link);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100321 link->sccp_up = 1;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100322 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed. %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800323 return 0;
324 break;
325 }
326 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100327 case MTP_PROHIBIT_MSG_GRP:
328 switch (cmn->h1) {
329 case MTP_PROHIBIT_MSG_SIG:
330 if (l3_len < 3) {
331 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
332 return -1;
333 }
334
335 apc = (uint16_t *) &hdr->data[1];
336 LOGP(DINP, LOGL_INFO,
337 "TFP for the affected point code: %d\n", *apc);
338 return 0;
339 break;
340 }
341 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800342 }
343
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100344 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 +0800345 return -1;
346}
347
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100348static 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 +0800349{
350 struct msgb *out;
351 struct mtp_level_3_mng *mng;
352
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100353 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800354 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
355 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800356 return -1;
357 }
358
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100359 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100360 LOGP(DINP, LOGL_ERROR, "MSG for 0x%x not handled by 0x%x\n",
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100361 MTP_ADDR_DPC(hdr->addr), link->set->opc);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100362 return -1;
363 }
364
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800365 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... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100374 out = mtp_create_slta(link->set,
375 MTP_LINK_SLS(hdr->addr),
376 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800377 if (!out)
378 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100379 mtp_link_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800380 return 0;
381 break;
382 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100383 /* If this link is proven set it up */
384 if (mtp_link_slta(link, l3_len, mng) == 0)
385 linkset_up(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800386 break;
387 }
388 break;
389 }
390
391 return -1;
392}
393
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100394static 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 +0800395{
396 struct msgb *out;
397 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100398 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100399 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800400
401 msg->l2h = &hdr->data[0];
402 if (msgb_l2len(msg) != l3_len) {
403 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
404 return -1;
405 }
406
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100407 if (!link->sccp_up) {
408 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
409 return -1;
410 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800411
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100412 memset(&sccp, 0, sizeof(sccp));
413 if (sccp_parse_header(msg, &sccp) != 0) {
414 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
415 return -1;
416 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800417
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100418 /* check if it is a SST */
419 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
420 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800421 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100422 LOGP(DINP, LOGL_ERROR,
423 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424 msgb_l3len(msg));
425 return -1;
426 }
427
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800428 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100429 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100430 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
431 ntohs(prt->apoc), prt->apoc);
432 type = SCCP_SSP;
433 } else if (prt->assn != 1 && prt->assn != 254 &&
434 prt->assn != 7 && prt->assn != 8 && prt->assn != 146) {
435 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
436 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100437 type = SCCP_SSP;
438 } else {
439 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800440 }
441
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100442 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100443 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800444 if (!out)
445 return -1;
446
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100447 mtp_link_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100448 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800449 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100450
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100451 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100452 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800453 return 0;
454}
455
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100456int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800457{
458 int rc = -1;
459 struct mtp_level_3_hdr *hdr;
460 int l3_len;
461
462 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
463 return -1;
464
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100465 if (!link->set->running) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800466 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
467 return -1;
468 }
469
470 hdr = (struct mtp_level_3_hdr *) msg->l2h;
471 l3_len = msgb_l2len(msg) - sizeof(*hdr);
472
Holger Hans Peter Freyther326a1f72011-01-24 20:52:30 +0100473 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_IN]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100474 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
475
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800476 switch (hdr->ser_ind) {
477 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100478 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800479 break;
480 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100481 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800482 break;
483 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100484 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800485 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100486 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100487 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100488 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100489 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100490 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800491 default:
492 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
493 break;
494 }
495
496 return rc;
497}
498
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100499int 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 +0800500{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800501
502 if (!link->sccp_up) {
503 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
504 return -1;
505 }
506
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100507 if (sls == -1) {
508 sls = link->last_sls;
509 link->last_sls = (link->last_sls + 1) % 16;
510 }
511
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100512 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100513 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100514}
515
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100516int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100517 const uint8_t *data, unsigned int length)
518{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100519 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100520 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100521}
522
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100523static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100524 const uint8_t *data, unsigned int length)
525{
526 uint8_t *put_ptr;
527 struct mtp_level_3_hdr *hdr;
528 struct msgb *msg;
529
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100530 if (!link->slc[sls % 16])
531 return -1;
532
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800533 msg = mtp_msg_alloc(link);
534 if (!msg)
535 return -1;
536
537 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100538 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800539
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100540 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800541
542 /* copy the raw sccp data */
543 put_ptr = msgb_put(msg, length);
544 memcpy(put_ptr, data, length);
545
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100546 mtp_link_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800547 return 0;
548}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100549
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100550static struct mtp_link *find_next_link(struct mtp_link_set *set,
551 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100552{
553 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100554 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100555
556 if (llist_empty(&set->links))
557 return NULL;
558
559 if (data == NULL)
560 found = 1;
561
562 /* try to find the next one */
563 llist_for_each_entry(next, &set->links, entry) {
564 if (found && next->available)
565 return next;
566 if (next == data)
567 found = 1;
568 }
569
570 /* try to find any one */
571 llist_for_each_entry(next, &set->links, entry)
572 if (next->available)
573 return next;
574
575 return NULL;
576}
577
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100578void mtp_link_set_init_slc(struct mtp_link_set *set)
579{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100580 struct mtp_link *link = NULL;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100581 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100582
583
584 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
585 link = find_next_link(set, link);
586 set->slc[i] = link;
587 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100588}
589
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100590int mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100591{
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100592 lnk->set = set;
Holger Hans Peter Freyther1cc24562011-01-20 18:26:18 +0100593 lnk->link_no = set->nr_links++;
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100594 if (mtp_link_init(lnk) != 0)
595 return -1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100596
597 llist_add_tail(&lnk->entry, &set->links);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100598 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100599 return 0;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100600}