blob: 24289cd91867404600295a898f5dd4b436bc41fd [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 Freyther5e5758c2011-02-17 18:18:22 +0100269 "The linkset %d/%s is considered running.\n", set->nr, 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 Freyther5e5758c2011-02-17 18:18:22 +0100292 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next on %d/%s.\n", link->nr, link->name);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100293 link->sccp_up = 1;
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100294 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed on %d/%s.\n", link->nr, 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) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100303 LOGP(DINP, LOGL_ERROR, "TFP is too short on %d/%s.\n", link->nr, link->name);
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100304 return -1;
305 }
306
307 apc = (uint16_t *) &hdr->data[1];
308 LOGP(DINP, LOGL_INFO,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100309 "TFP for the affected point code %d on %d/%s\n",
310 *apc, link->nr, link->name);
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100311 return 0;
312 break;
313 }
314 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800315 }
316
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100317 LOGP(DINP, LOGL_ERROR, "Unknown message:%d/%d %s on %d/%s.\n",
318 cmn->h0, cmn->h1, hexdump(&hdr->data[0], l3_len),
319 link->nr, link->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800320 return -1;
321}
322
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100323static 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 +0800324{
325 struct msgb *out;
326 struct mtp_level_3_mng *mng;
327
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100328 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800329 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
330 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800331 return -1;
332 }
333
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100334 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100335 LOGP(DINP, LOGL_ERROR, "MSG for OPC %d not handled on %d/%s\n",
336 MTP_ADDR_DPC(hdr->addr), link->set->nr, link->set->name);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100337 return -1;
338 }
339
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800340 mng = (struct mtp_level_3_mng *) &hdr->data[0];
341 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
342 mng->cmn.h0, mng->cmn.h1);
343
344 switch (mng->cmn.h0) {
345 case MTP_TST_MSG_GRP:
346 switch (mng->cmn.h1) {
347 case MTP_TST_MSG_SLTM:
348 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100349 out = mtp_create_slta(link->set,
350 MTP_LINK_SLS(hdr->addr),
351 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800352 if (!out)
353 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100354 mtp_link_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800355 return 0;
356 break;
357 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100358 /* If this link is proven set it up */
359 if (mtp_link_slta(link, l3_len, mng) == 0)
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100360 linkset_up(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800361 break;
362 }
363 break;
364 }
365
366 return -1;
367}
368
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100369static 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 +0800370{
371 struct msgb *out;
372 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100373 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100374 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800375
376 msg->l2h = &hdr->data[0];
377 if (msgb_l2len(msg) != l3_len) {
378 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
379 return -1;
380 }
381
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100382 if (!link->sccp_up) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100383 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed on %d/%s\n",
384 link->nr, link->name);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100385 return -1;
386 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800387
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100388 memset(&sccp, 0, sizeof(sccp));
389 if (sccp_parse_header(msg, &sccp) != 0) {
390 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
391 return -1;
392 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800393
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100394 /* check if it is a SST */
395 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
396 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800397 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100398 LOGP(DINP, LOGL_ERROR,
399 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800400 msgb_l3len(msg));
401 return -1;
402 }
403
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800404 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100405 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100406 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u on %d/%s\n",
407 ntohs(prt->apoc), prt->apoc, link->nr, link->name);
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100408 type = SCCP_SSP;
Holger Hans Peter Freyther1b5d8462011-02-17 01:48:42 +0100409 } else if (!link->supported_ssn[prt->assn]) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100410 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u on %d/%s\n",
411 prt->assn, link->nr, link->name);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100412 type = SCCP_SSP;
413 } else {
414 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800415 }
416
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100417 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100418 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800419 if (!out)
420 return -1;
421
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100422 mtp_link_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100423 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100425
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100426 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100427 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800428 return 0;
429}
430
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100431int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800432{
433 int rc = -1;
434 struct mtp_level_3_hdr *hdr;
435 int l3_len;
436
437 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
438 return -1;
439
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100440 if (!link->set->running) {
Holger Hans Peter Freyther5a34c7f2011-02-17 03:23:42 +0100441 LOGP(DINP, LOGL_ERROR,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100442 "Link %d/%s of %d/%s is not running. Call mtp_link_reset first.\n",
Holger Hans Peter Freyther5a34c7f2011-02-17 03:23:42 +0100443 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800444 return -1;
445 }
446
447 hdr = (struct mtp_level_3_hdr *) msg->l2h;
448 l3_len = msgb_l2len(msg) - sizeof(*hdr);
449
Holger Hans Peter Freyther326a1f72011-01-24 20:52:30 +0100450 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_IN]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100451 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
452
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800453 switch (hdr->ser_ind) {
454 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100455 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800456 break;
457 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100458 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800459 break;
460 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100461 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800462 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100463 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100464 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100465 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100466 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100467 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800468 default:
469 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
470 break;
471 }
472
473 return rc;
474}
475
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100476int 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 +0800477{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800478
479 if (!link->sccp_up) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100480 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it on %d/%s\n",
481 link->nr, link->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800482 return -1;
483 }
484
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100485 if (sls == -1) {
486 sls = link->last_sls;
487 link->last_sls = (link->last_sls + 1) % 16;
488 }
489
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100490 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100491 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100492}
493
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100494int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100495 const uint8_t *data, unsigned int length)
496{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100497 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100498 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100499}
500
Holger Hans Peter Freyther0452f222011-02-03 13:35:42 +0100501int mtp_link_set_send(struct mtp_link_set *set, struct msgb *msg)
502{
503 int sls;
504 struct mtp_level_3_hdr *hdr;
505
506 if (msgb_l2len(msg) < sizeof(*hdr))
507 return -1;
508
509 hdr = (struct mtp_level_3_hdr *) msg->l2h;
510 sls = MTP_LINK_SLS(hdr->addr);
511 if (!set->slc[sls])
512 return -2;
513
514 mtp_link_submit(set->slc[sls], msg);
515 return 0;
516}
517
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100518static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100519 const uint8_t *data, unsigned int length)
520{
521 uint8_t *put_ptr;
522 struct mtp_level_3_hdr *hdr;
523 struct msgb *msg;
524
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100525 if (!link->slc[sls % 16])
526 return -1;
527
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800528 msg = mtp_msg_alloc(link);
529 if (!msg)
530 return -1;
531
532 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100533 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800534
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100535 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800536
537 /* copy the raw sccp data */
538 put_ptr = msgb_put(msg, length);
539 memcpy(put_ptr, data, length);
540
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100541 mtp_link_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800542 return 0;
543}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100544
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100545static struct mtp_link *find_next_link(struct mtp_link_set *set,
546 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100547{
548 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100549 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100550
551 if (llist_empty(&set->links))
552 return NULL;
553
554 if (data == NULL)
555 found = 1;
556
557 /* try to find the next one */
558 llist_for_each_entry(next, &set->links, entry) {
559 if (found && next->available)
560 return next;
561 if (next == data)
562 found = 1;
563 }
564
565 /* try to find any one */
566 llist_for_each_entry(next, &set->links, entry)
567 if (next->available)
568 return next;
569
570 return NULL;
571}
572
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100573void mtp_link_set_init_slc(struct mtp_link_set *set)
574{
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100575 struct mtp_link *link = NULL, *tmp;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100576 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100577
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100578 llist_for_each_entry(tmp, &set->links, entry)
579 tmp->first_sls = 100;
580
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100581
582 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
583 link = find_next_link(set, link);
584 set->slc[i] = link;
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100585
586 if (link && i < link->first_sls)
587 link->first_sls = i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100588 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100589}
590
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100591struct mtp_link_set *mtp_link_set_alloc(struct bsc_data *bsc)
592{
593 struct mtp_link_set *link;
594
595 link = talloc_zero(bsc, struct mtp_link_set);
596 if (!link)
597 return NULL;
598
599 link->ctrg = rate_ctr_group_alloc(link,
600 mtp_link_set_rate_ctr_desc(),
601 bsc->num_linksets + 1);
602 if (!link->ctrg) {
603 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
604 return NULL;
605 }
606
607
608 link->ni = MTP_NI_NATION_NET;
609 INIT_LLIST_HEAD(&link->links);
610
Holger Hans Peter Freythera33b23f2011-02-16 23:37:40 +0100611 link->nr = bsc->num_linksets++;
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100612 llist_add(&link->entry, &bsc->linksets);
613
614 return link;
615}
616
617struct mtp_link_set *mtp_link_set_num(struct bsc_data *bsc, int num)
618{
619 struct mtp_link_set *set;
620
621 llist_for_each_entry(set, &bsc->linksets, entry)
Holger Hans Peter Freythera33b23f2011-02-16 23:37:40 +0100622 if (set->nr == num)
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100623 return set;
624
625 return NULL;
626}