blob: 83c8d63fe8abb8fded765ab914744869ea2f6917 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* MTP layer3 main handling code */
2/*
Holger Hans Peter Freyther0452f222011-02-03 13:35:42 +01003 * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010-2011 by On-Waves
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08005 * 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
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010036static 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 +010037
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +010038void mtp_link_submit(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010039{
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010040 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_OUT]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010041 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_OUT_MSG]);
42 link->write(link, msg);
43}
44
45
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010046struct msgb *mtp_msg_alloc(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080047{
48 struct mtp_level_3_hdr *hdr;
49 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
50 if (!msg) {
51 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
52 return NULL;
53 }
54
55 msg->l2h = msgb_put(msg, sizeof(*hdr));
56 hdr = (struct mtp_level_3_hdr *) msg->l2h;
57 hdr->addr = MTP_ADDR(0x0, link->dpc, link->opc);
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +010058 hdr->ni = link->ni;
Holger Hans Peter Freythere976df12010-11-26 21:07:11 +010059 hdr->spare = link->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080060 return msg;
61}
62
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010063static struct msgb *mtp_create_slta(struct mtp_link_set *link, int sls,
64 struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080065{
66 struct mtp_level_3_hdr *hdr;
67 struct mtp_level_3_mng *mng;
68 struct msgb *out = mtp_msg_alloc(link);
69
70 if (!out)
71 return NULL;
72
73 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080074 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010075 hdr->addr = MTP_ADDR(sls, link->dpc, link->opc);
76
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080077 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
78 mng->cmn.h0 = MTP_TST_MSG_GRP;
79 mng->cmn.h1 = MTP_TST_MSG_SLTA;
80 mng->length = l3_len - 2;
81 msgb_put(out, mng->length);
82 memcpy(mng->data, in_mng->data, mng->length);
83
84 return out;
85}
86
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010087
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010088static struct msgb *mtp_base_alloc(struct mtp_link *link, int msg, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080089{
90 struct mtp_level_3_hdr *hdr;
91 struct mtp_level_3_prohib *prb;
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010092 struct msgb *out = mtp_msg_alloc(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080093
94 if (!out)
95 return NULL;
96
97 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080098 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010099 hdr->addr = MTP_ADDR(link->first_sls, link->set->dpc, link->set->opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800100 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 Freyther7d336a52011-01-25 13:29:56 +0100107static struct msgb *mtp_tfp_alloc(struct mtp_link *link, int apoc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100108{
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100109 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100110}
111
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100112static struct msgb *mtp_tfa_alloc(struct mtp_link *link, int apoc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100113{
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100114 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100115}
116
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100117static struct msgb *mtp_tra_alloc(struct mtp_link *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;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100121 struct msgb *out = mtp_msg_alloc(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800122
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 Freyther7d336a52011-01-25 13:29:56 +0100128 hdr->addr = MTP_ADDR(0x0, link->set->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_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800187{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100188 struct mtp_link *lnk;
189 llist_for_each_entry(lnk, &link->links, entry)
190 mtp_link_stop_link_test(lnk);
191
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800192 link->sccp_up = 0;
193 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100194 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800195}
196
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100197void mtp_link_set_reset(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;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100200 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800201 link->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100202
203 llist_for_each_entry(lnk, &link->links, entry)
204 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800205}
206
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100207static int send_tfp(struct mtp_link *link, int apoc)
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100208{
209 struct msgb *msg;
210 msg = mtp_tfp_alloc(link, apoc);
211 if (!msg)
212 return -1;
213
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100214 mtp_link_submit(link, msg);
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100215 return 0;
216}
217
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100218static int send_tra(struct mtp_link *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800219{
220 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100221 msg = mtp_tra_alloc(link, opc);
222 if (!msg)
223 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100224 mtp_link_submit(link, msg);
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100225 return 0;
226}
227
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100228static int send_tfa(struct mtp_link *link, int opc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100229{
230 struct msgb *msg;
231 msg = mtp_tfa_alloc(link, opc);
232 if (!msg)
233 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100234 mtp_link_submit(link, msg);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100235 return 0;
236}
237
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100238static int linkset_up(struct mtp_link *link)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100239{
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100240 struct mtp_link_set *set = link->set;
241
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100242 /* the link set is already up */
243 if (set->linkset_up)
244 return 0;
245
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100246 if (send_tfp(link, 0) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100247 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100248 if (send_tfp(link, set->opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100249 return -1;
250 if (set->sccp_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100251 send_tfp(link, set->sccp_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100252 return -1;
253 if (set->isup_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100254 send_tfp(link, set->isup_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100255 return -1;
256
257 /* Send the TRA for all PCs */
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100258 if (send_tra(link, set->opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100259 return -1;
260 if (set->sccp_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100261 send_tfa(link, set->sccp_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100262 return -1;
263 if (set->isup_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100264 send_tfa(link, set->isup_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100265 return -1;
266
267 set->linkset_up = 1;
268 LOGP(DINP, LOGL_NOTICE,
Holger Hans Peter Freyther38d936a2011-01-26 12:41:42 +0100269 "The linkset %s is considered running.\n", set->name);
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100270 return 0;
271}
272
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100273static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
274{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800275 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100276 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800277
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100278 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800279 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
280 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800281 return -1;
282 }
283
284 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
285 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
286 cmn->h0, cmn->h1);
287
288 switch (cmn->h0) {
289 case MTP_TRF_RESTR_MSG_GRP:
290 switch (cmn->h1) {
291 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherd3f412b2011-01-28 18:52:16 +0100292 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %s.\n", link->name);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100293 link->sccp_up = 1;
Holger Hans Peter Freytherd3f412b2011-01-28 18:52:16 +0100294 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed on %s.\n", link->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800295 return 0;
296 break;
297 }
298 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100299 case MTP_PROHIBIT_MSG_GRP:
300 switch (cmn->h1) {
301 case MTP_PROHIBIT_MSG_SIG:
302 if (l3_len < 3) {
303 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
304 return -1;
305 }
306
307 apc = (uint16_t *) &hdr->data[1];
308 LOGP(DINP, LOGL_INFO,
309 "TFP for the affected point code: %d\n", *apc);
310 return 0;
311 break;
312 }
313 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800314 }
315
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100316 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 +0800317 return -1;
318}
319
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100320static 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 +0800321{
322 struct msgb *out;
323 struct mtp_level_3_mng *mng;
324
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100325 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800326 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
327 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800328 return -1;
329 }
330
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100331 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100332 LOGP(DINP, LOGL_ERROR, "MSG for 0x%x not handled by 0x%x\n",
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100333 MTP_ADDR_DPC(hdr->addr), link->set->opc);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100334 return -1;
335 }
336
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800337 mng = (struct mtp_level_3_mng *) &hdr->data[0];
338 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
339 mng->cmn.h0, mng->cmn.h1);
340
341 switch (mng->cmn.h0) {
342 case MTP_TST_MSG_GRP:
343 switch (mng->cmn.h1) {
344 case MTP_TST_MSG_SLTM:
345 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100346 out = mtp_create_slta(link->set,
347 MTP_LINK_SLS(hdr->addr),
348 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800349 if (!out)
350 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100351 mtp_link_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800352 return 0;
353 break;
354 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100355 /* If this link is proven set it up */
356 if (mtp_link_slta(link, l3_len, mng) == 0)
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100357 linkset_up(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800358 break;
359 }
360 break;
361 }
362
363 return -1;
364}
365
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100366static 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 +0800367{
368 struct msgb *out;
369 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100370 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100371 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800372
373 msg->l2h = &hdr->data[0];
374 if (msgb_l2len(msg) != l3_len) {
375 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
376 return -1;
377 }
378
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100379 if (!link->sccp_up) {
380 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
381 return -1;
382 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800383
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100384 memset(&sccp, 0, sizeof(sccp));
385 if (sccp_parse_header(msg, &sccp) != 0) {
386 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
387 return -1;
388 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800389
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100390 /* check if it is a SST */
391 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
392 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800393 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100394 LOGP(DINP, LOGL_ERROR,
395 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800396 msgb_l3len(msg));
397 return -1;
398 }
399
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800400 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100401 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100402 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
403 ntohs(prt->apoc), prt->apoc);
404 type = SCCP_SSP;
Holger Hans Peter Freyther1b5d8462011-02-17 01:48:42 +0100405 } else if (!link->supported_ssn[prt->assn]) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100406 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
407 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100408 type = SCCP_SSP;
409 } else {
410 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800411 }
412
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100413 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100414 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800415 if (!out)
416 return -1;
417
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100418 mtp_link_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100419 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800420 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100421
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100422 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100423 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424 return 0;
425}
426
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100427int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800428{
429 int rc = -1;
430 struct mtp_level_3_hdr *hdr;
431 int l3_len;
432
433 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
434 return -1;
435
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100436 if (!link->set->running) {
Holger Hans Peter Freyther38d936a2011-01-26 12:41:42 +0100437 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %s/%d\n",
438 link->set->name, link->link_no);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800439 return -1;
440 }
441
442 hdr = (struct mtp_level_3_hdr *) msg->l2h;
443 l3_len = msgb_l2len(msg) - sizeof(*hdr);
444
Holger Hans Peter Freyther326a1f72011-01-24 20:52:30 +0100445 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_IN]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100446 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
447
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800448 switch (hdr->ser_ind) {
449 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100450 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800451 break;
452 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100453 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800454 break;
455 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100456 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800457 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100458 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100459 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100460 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100461 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100462 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800463 default:
464 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
465 break;
466 }
467
468 return rc;
469}
470
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100471int 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 +0800472{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800473
474 if (!link->sccp_up) {
475 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
476 return -1;
477 }
478
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100479 if (sls == -1) {
480 sls = link->last_sls;
481 link->last_sls = (link->last_sls + 1) % 16;
482 }
483
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100484 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100485 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100486}
487
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100488int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100489 const uint8_t *data, unsigned int length)
490{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100491 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100492 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100493}
494
Holger Hans Peter Freyther0452f222011-02-03 13:35:42 +0100495int mtp_link_set_send(struct mtp_link_set *set, struct msgb *msg)
496{
497 int sls;
498 struct mtp_level_3_hdr *hdr;
499
500 if (msgb_l2len(msg) < sizeof(*hdr))
501 return -1;
502
503 hdr = (struct mtp_level_3_hdr *) msg->l2h;
504 sls = MTP_LINK_SLS(hdr->addr);
505 if (!set->slc[sls])
506 return -2;
507
508 mtp_link_submit(set->slc[sls], msg);
509 return 0;
510}
511
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100512static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100513 const uint8_t *data, unsigned int length)
514{
515 uint8_t *put_ptr;
516 struct mtp_level_3_hdr *hdr;
517 struct msgb *msg;
518
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100519 if (!link->slc[sls % 16])
520 return -1;
521
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800522 msg = mtp_msg_alloc(link);
523 if (!msg)
524 return -1;
525
526 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100527 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800528
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100529 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800530
531 /* copy the raw sccp data */
532 put_ptr = msgb_put(msg, length);
533 memcpy(put_ptr, data, length);
534
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100535 mtp_link_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800536 return 0;
537}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100538
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100539static struct mtp_link *find_next_link(struct mtp_link_set *set,
540 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100541{
542 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100543 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100544
545 if (llist_empty(&set->links))
546 return NULL;
547
548 if (data == NULL)
549 found = 1;
550
551 /* try to find the next one */
552 llist_for_each_entry(next, &set->links, entry) {
553 if (found && next->available)
554 return next;
555 if (next == data)
556 found = 1;
557 }
558
559 /* try to find any one */
560 llist_for_each_entry(next, &set->links, entry)
561 if (next->available)
562 return next;
563
564 return NULL;
565}
566
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100567void mtp_link_set_init_slc(struct mtp_link_set *set)
568{
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100569 struct mtp_link *link = NULL, *tmp;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100570 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100571
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100572 llist_for_each_entry(tmp, &set->links, entry)
573 tmp->first_sls = 100;
574
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100575
576 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
577 link = find_next_link(set, link);
578 set->slc[i] = link;
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100579
580 if (link && i < link->first_sls)
581 link->first_sls = i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100582 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100583}
584
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100585int mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100586{
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100587 lnk->set = set;
Holger Hans Peter Freyther1cc24562011-01-20 18:26:18 +0100588 lnk->link_no = set->nr_links++;
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100589 if (mtp_link_init(lnk) != 0)
590 return -1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100591
592 llist_add_tail(&lnk->entry, &set->links);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100593 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100594 return 0;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100595}
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100596
597struct mtp_link_set *mtp_link_set_alloc(struct bsc_data *bsc)
598{
599 struct mtp_link_set *link;
600
601 link = talloc_zero(bsc, struct mtp_link_set);
602 if (!link)
603 return NULL;
604
605 link->ctrg = rate_ctr_group_alloc(link,
606 mtp_link_set_rate_ctr_desc(),
607 bsc->num_linksets + 1);
608 if (!link->ctrg) {
609 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
610 return NULL;
611 }
612
613
614 link->ni = MTP_NI_NATION_NET;
615 INIT_LLIST_HEAD(&link->links);
616
Holger Hans Peter Freythera33b23f2011-02-16 23:37:40 +0100617 link->nr = bsc->num_linksets++;
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100618 llist_add(&link->entry, &bsc->linksets);
619
620 return link;
621}
622
623struct mtp_link_set *mtp_link_set_num(struct bsc_data *bsc, int num)
624{
625 struct mtp_link_set *set;
626
627 llist_for_each_entry(set, &bsc->linksets, entry)
Holger Hans Peter Freythera33b23f2011-02-16 23:37:40 +0100628 if (set->nr == num)
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100629 return set;
630
631 return NULL;
632}