blob: 544987daaa9ed409c878a14b21f6e524ef87acd2 [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 Freytherd062f832011-02-23 16:58:15 +010036static int mtp_int_submit(struct mtp_link_set *set, 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 Freytherd062f832011-02-23 16:58:15 +010046struct msgb *mtp_msg_alloc(struct mtp_link_set *set)
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;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010057 hdr->addr = MTP_ADDR(0x0, set->dpc, set->opc);
58 hdr->ni = set->ni;
59 hdr->spare = set->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080060 return msg;
61}
62
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010063static struct msgb *mtp_create_slta(struct mtp_link_set *set, int sls,
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010064 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;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010068 struct msgb *out = mtp_msg_alloc(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080069
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 Freytherd062f832011-02-23 16:58:15 +010075 hdr->addr = MTP_ADDR(sls, set->dpc, set->opc);
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010076
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 Freytherd062f832011-02-23 16:58:15 +0100135static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *set,
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
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100144 struct msgb *out = mtp_msg_alloc(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800145
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 Freytherd062f832011-02-23 16:58:15 +0100153 hdr->addr = MTP_ADDR(sls % 16, set->dpc, set->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 Freytherd062f832011-02-23 16:58:15 +0100186void mtp_link_set_stop(struct mtp_link_set *set)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800187{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100188 struct mtp_link *lnk;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100189 llist_for_each_entry(lnk, &set->links, entry)
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100190 mtp_link_stop_link_test(lnk);
191
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100192 bsc_del_timer(&set->T18);
193 bsc_del_timer(&set->T20);
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100194
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100195 set->sccp_up = 0;
196 set->running = 0;
197 set->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800198}
199
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100200void mtp_link_set_reset(struct mtp_link_set *set)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800201{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100202 struct mtp_link *lnk;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100203 mtp_link_set_stop(set);
204 set->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100205
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100206 llist_for_each_entry(lnk, &set->links, entry)
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100207 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800208}
209
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100210/* unused right now but we want to use it again */
211int send_tfp(struct mtp_link *link, int apoc)
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100212{
213 struct msgb *msg;
214 msg = mtp_tfp_alloc(link, apoc);
215 if (!msg)
216 return -1;
217
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100218 mtp_link_submit(link, msg);
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100219 return 0;
220}
221
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100222static int send_tra(struct mtp_link *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800223{
224 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100225 msg = mtp_tra_alloc(link, opc);
226 if (!msg)
227 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100228 mtp_link_submit(link, msg);
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100229 return 0;
230}
231
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100232static int send_tfa(struct mtp_link *link, int opc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100233{
234 struct msgb *msg;
235 msg = mtp_tfa_alloc(link, opc);
236 if (!msg)
237 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100238 mtp_link_submit(link, msg);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100239 return 0;
240}
241
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100242static int linkset_up(struct mtp_link *link)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100243{
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100244 struct mtp_link_set *set = link->set;
245
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100246 /* the link set is already up */
247 if (set->linkset_up)
248 return 0;
249
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100250 set->linkset_up = 1;
251 bsc_schedule_timer(&set->T18, set->timeout_t18, 0);
252 bsc_schedule_timer(&set->T20, set->timeout_t20, 0);
253
254 /* More the functionality of a SSP here... */
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100255 if (set->sccp_opc != set->opc &&
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100256 send_tfa(link, set->sccp_opc) != 0) {
257 LOGP(DINP, LOGL_ERROR,
258 "Failed to send TFA for OPC %d on linkset %d.\n", set->sccp_opc, set->nr);
259 }
260
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100261 if (set->isup_opc != set->opc &&
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100262 send_tfa(link, set->isup_opc) != 0) {
263 LOGP(DINP, LOGL_ERROR,
264 "Failed to send TFA for OPC %d on linkset %d.\n", set->sccp_opc, set->nr);
265 }
266
267 return 0;
268}
269
270static void linkset_t18_cb(void *_set)
271{
272 struct mtp_link_set *set = _set;
273 struct mtp_link *link = set->slc[0];
274
275 if (!link) {
276 LOGP(DINP, LOGL_ERROR,
277 "Linkset restart but no link available on linkset %d\n", set->nr);
278 bsc_del_timer(&set->T20);
279 set->linkset_up = 0;
280 return;
281 }
282
283 /* TODO: now send out routing states */
284 LOGP(DINP, LOGL_NOTICE, "The linkset %d has collected routing data.\n", set->nr);
285}
286
287static void linkset_t20_cb(void *_set)
288{
289 struct mtp_link_set *set = _set;
290 struct mtp_link *link = set->slc[0];
291
292 if (!link) {
293 LOGP(DINP, LOGL_ERROR,
294 "Linkset restart but no link available on linkset %d\n", set->nr);
295 bsc_del_timer(&set->T20);
296 set->linkset_up = 0;
297 return;
298 }
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100299
300 /* Send the TRA for all PCs */
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100301 if (send_tra(link, set->opc) != 0)
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100302 return;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100303
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100304 LOGP(DINP, LOGL_NOTICE,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100305 "The linkset %d/%s is considered running.\n", set->nr, set->name);
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100306 return;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100307}
308
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100309static int mtp_link_sign_msg(struct mtp_link_set *set, struct mtp_level_3_hdr *hdr, int l3_len)
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100310{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800311 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100312 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800313
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100314 if (hdr->ni != set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800315 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
316 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800317 return -1;
318 }
319
320 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
321 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
322 cmn->h0, cmn->h1);
323
324 switch (cmn->h0) {
325 case MTP_TRF_RESTR_MSG_GRP:
326 switch (cmn->h1) {
327 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100328 LOGP(DINP, LOGL_INFO,
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100329 "Received TRA on linkset %d/%s.\n", set->nr, set->name);
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100330 /*
331 * TODO: routing should be done on a higher level. This should not
332 * arrive after we expired the timer but we are friendly here and
333 * respond with a TFA and TRA...
334 */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100335 bsc_del_timer(&set->T18);
336 bsc_del_timer(&set->T20);
337 linkset_t18_cb(set);
338 linkset_t20_cb(set);
339 set->sccp_up = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800340 return 0;
341 break;
342 }
343 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100344 case MTP_PROHIBIT_MSG_GRP:
345 switch (cmn->h1) {
346 case MTP_PROHIBIT_MSG_SIG:
347 if (l3_len < 3) {
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100348 LOGP(DINP, LOGL_ERROR, "TFP is too short on %d/%s.\n", set->nr, set->name);
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100349 return -1;
350 }
351
352 apc = (uint16_t *) &hdr->data[1];
353 LOGP(DINP, LOGL_INFO,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100354 "TFP for the affected point code %d on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100355 *apc, set->nr, set->name);
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100356 return 0;
357 break;
358 }
359 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800360 }
361
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100362 LOGP(DINP, LOGL_ERROR, "Unknown message:%d/%d %s on %d/%s.\n",
363 cmn->h0, cmn->h1, hexdump(&hdr->data[0], l3_len),
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100364 set->nr, set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800365 return -1;
366}
367
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100368static 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 +0800369{
370 struct msgb *out;
371 struct mtp_level_3_mng *mng;
372
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100373 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800374 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
375 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800376 return -1;
377 }
378
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100379 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100380 LOGP(DINP, LOGL_ERROR, "MSG for OPC %d not handled on %d/%s\n",
381 MTP_ADDR_DPC(hdr->addr), link->set->nr, link->set->name);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100382 return -1;
383 }
384
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800385 mng = (struct mtp_level_3_mng *) &hdr->data[0];
386 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
387 mng->cmn.h0, mng->cmn.h1);
388
389 switch (mng->cmn.h0) {
390 case MTP_TST_MSG_GRP:
391 switch (mng->cmn.h1) {
392 case MTP_TST_MSG_SLTM:
393 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100394 out = mtp_create_slta(link->set,
395 MTP_LINK_SLS(hdr->addr),
396 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800397 if (!out)
398 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100399 mtp_link_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800400 return 0;
401 break;
402 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100403 /* If this link is proven set it up */
404 if (mtp_link_slta(link, l3_len, mng) == 0)
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100405 linkset_up(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800406 break;
407 }
408 break;
409 }
410
411 return -1;
412}
413
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100414static int mtp_link_sccp_data(struct mtp_link_set *set, struct mtp_level_3_hdr *hdr, struct msgb *msg, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800415{
416 struct msgb *out;
417 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100418 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100419 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800420
421 msg->l2h = &hdr->data[0];
422 if (msgb_l2len(msg) != l3_len) {
423 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
424 return -1;
425 }
426
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100427 if (!set->sccp_up) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100428 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100429 set->nr, set->name);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100430 return -1;
431 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800432
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100433 memset(&sccp, 0, sizeof(sccp));
434 if (sccp_parse_header(msg, &sccp) != 0) {
435 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
436 return -1;
437 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800438
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100439 /* check if it is a SST */
440 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
441 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800442 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100443 LOGP(DINP, LOGL_ERROR,
444 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800445 msgb_l3len(msg));
446 return -1;
447 }
448
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800449 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100450 if (prt->apoc != MTP_MAKE_APOC(set->sccp_opc)) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100451 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100452 ntohs(prt->apoc), prt->apoc, set->nr, set->name);
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100453 type = SCCP_SSP;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100454 } else if (!set->supported_ssn[prt->assn]) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100455 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100456 prt->assn, set->nr, set->name);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100457 type = SCCP_SSP;
458 } else {
459 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800460 }
461
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100462 out = mtp_sccp_alloc_scmg(set, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100463 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800464 if (!out)
465 return -1;
466
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100467 mtp_link_submit(set->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100468 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800469 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100470
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100471 rate_ctr_inc(&set->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
472 mtp_link_set_forward_sccp(set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800473 return 0;
474}
475
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100476int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800477{
478 int rc = -1;
479 struct mtp_level_3_hdr *hdr;
480 int l3_len;
481
482 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
483 return -1;
484
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100485 if (!link->set->running) {
Holger Hans Peter Freyther5a34c7f2011-02-17 03:23:42 +0100486 LOGP(DINP, LOGL_ERROR,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100487 "Link %d/%s of %d/%s is not running. Call mtp_link_reset first.\n",
Holger Hans Peter Freyther5a34c7f2011-02-17 03:23:42 +0100488 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800489 return -1;
490 }
491
492 hdr = (struct mtp_level_3_hdr *) msg->l2h;
493 l3_len = msgb_l2len(msg) - sizeof(*hdr);
494
Holger Hans Peter Freyther326a1f72011-01-24 20:52:30 +0100495 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_IN]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100496 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
497
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800498 switch (hdr->ser_ind) {
499 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100500 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800501 break;
502 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100503 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800504 break;
505 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100506 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800507 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100508 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100509 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100510 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100511 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100512 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800513 default:
514 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
515 break;
516 }
517
518 return rc;
519}
520
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100521int mtp_link_set_submit_sccp_data(struct mtp_link_set *set, int sls, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800522{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800523
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100524 if (!set->sccp_up) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100525 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100526 set->nr, set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800527 return -1;
528 }
529
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100530 if (sls == -1) {
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100531 sls = set->last_sls;
532 set->last_sls = (set->last_sls + 1) % 16;
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100533 }
534
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100535 rate_ctr_inc(&set->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
536 return mtp_int_submit(set, set->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100537}
538
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100539int mtp_link_set_submit_isup_data(struct mtp_link_set *set, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100540 const uint8_t *data, unsigned int length)
541{
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100542 rate_ctr_inc(&set->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
543 return mtp_int_submit(set, set->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100544}
545
Holger Hans Peter Freyther0452f222011-02-03 13:35:42 +0100546int mtp_link_set_send(struct mtp_link_set *set, struct msgb *msg)
547{
548 int sls;
549 struct mtp_level_3_hdr *hdr;
550
551 if (msgb_l2len(msg) < sizeof(*hdr))
552 return -1;
553
554 hdr = (struct mtp_level_3_hdr *) msg->l2h;
555 sls = MTP_LINK_SLS(hdr->addr);
556 if (!set->slc[sls])
557 return -2;
558
559 mtp_link_submit(set->slc[sls], msg);
560 return 0;
561}
562
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100563static int mtp_int_submit(struct mtp_link_set *set, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100564 const uint8_t *data, unsigned int length)
565{
566 uint8_t *put_ptr;
567 struct mtp_level_3_hdr *hdr;
568 struct msgb *msg;
569
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100570 if (!set->slc[sls % 16])
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100571 return -1;
572
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100573 msg = mtp_msg_alloc(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800574 if (!msg)
575 return -1;
576
577 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100578 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800579
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100580 hdr->addr = MTP_ADDR(sls % 16, set->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800581
582 /* copy the raw sccp data */
583 put_ptr = msgb_put(msg, length);
584 memcpy(put_ptr, data, length);
585
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100586 mtp_link_submit(set->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800587 return 0;
588}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100589
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100590static struct mtp_link *find_next_link(struct mtp_link_set *set,
591 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100592{
593 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100594 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100595
596 if (llist_empty(&set->links))
597 return NULL;
598
599 if (data == NULL)
600 found = 1;
601
602 /* try to find the next one */
603 llist_for_each_entry(next, &set->links, entry) {
604 if (found && next->available)
605 return next;
606 if (next == data)
607 found = 1;
608 }
609
610 /* try to find any one */
611 llist_for_each_entry(next, &set->links, entry)
612 if (next->available)
613 return next;
614
615 return NULL;
616}
617
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100618void mtp_link_set_init_slc(struct mtp_link_set *set)
619{
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100620 struct mtp_link *link = NULL, *tmp;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100621 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100622
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100623 llist_for_each_entry(tmp, &set->links, entry)
624 tmp->first_sls = 100;
625
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100626
627 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
628 link = find_next_link(set, link);
629 set->slc[i] = link;
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100630
631 if (link && i < link->first_sls)
632 link->first_sls = i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100633 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100634}
635
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100636struct mtp_link_set *mtp_link_set_alloc(struct bsc_data *bsc)
637{
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100638 struct mtp_link_set *set;
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100639
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100640 set = talloc_zero(bsc, struct mtp_link_set);
641 if (!set)
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100642 return NULL;
643
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100644 set->ctrg = rate_ctr_group_alloc(set,
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100645 mtp_link_set_rate_ctr_desc(),
646 bsc->num_linksets + 1);
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100647 if (!set->ctrg) {
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100648 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
649 return NULL;
650 }
651
652
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100653 set->ni = MTP_NI_NATION_NET;
654 INIT_LLIST_HEAD(&set->links);
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100655
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100656 set->nr = bsc->num_linksets++;
657 set->sccp_opc = set->isup_opc = -1;
658 set->pcap_fd = bsc->pcap_fd;
659 set->bsc = bsc;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100660
661 /* timeout code */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100662 set->timeout_t18 = 15;
663 set->timeout_t20 = 16;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100664
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100665 set->T18.cb = linkset_t18_cb;
666 set->T18.data = set;
667 set->T20.cb = linkset_t20_cb;
668 set->T20.data = set;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100669
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100670 llist_add_tail(&set->entry, &bsc->linksets);
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100671
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100672 return set;
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100673}
674
675struct mtp_link_set *mtp_link_set_num(struct bsc_data *bsc, int num)
676{
677 struct mtp_link_set *set;
678
679 llist_for_each_entry(set, &bsc->linksets, entry)
Holger Hans Peter Freythera33b23f2011-02-16 23:37:40 +0100680 if (set->nr == num)
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100681 return set;
682
683 return NULL;
684}