blob: dc24a73a49c067164d94a7a6f6c0fbae68bc45e5 [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 Freytherd062f832011-02-23 16:58:15 +010038struct msgb *mtp_msg_alloc(struct mtp_link_set *set)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080039{
40 struct mtp_level_3_hdr *hdr;
41 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
42 if (!msg) {
43 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
44 return NULL;
45 }
46
47 msg->l2h = msgb_put(msg, sizeof(*hdr));
48 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010049 hdr->addr = MTP_ADDR(0x0, set->dpc, set->opc);
50 hdr->ni = set->ni;
51 hdr->spare = set->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080052 return msg;
53}
54
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010055static struct msgb *mtp_create_slta(struct mtp_link_set *set, int sls,
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010056 struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080057{
58 struct mtp_level_3_hdr *hdr;
59 struct mtp_level_3_mng *mng;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010060 struct msgb *out = mtp_msg_alloc(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080061
62 if (!out)
63 return NULL;
64
65 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080066 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010067 hdr->addr = MTP_ADDR(sls, set->dpc, set->opc);
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010068
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080069 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
70 mng->cmn.h0 = MTP_TST_MSG_GRP;
71 mng->cmn.h1 = MTP_TST_MSG_SLTA;
72 mng->length = l3_len - 2;
73 msgb_put(out, mng->length);
74 memcpy(mng->data, in_mng->data, mng->length);
75
76 return out;
77}
78
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010079
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010080static struct msgb *mtp_base_alloc(struct mtp_link *link, int msg, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080081{
82 struct mtp_level_3_hdr *hdr;
83 struct mtp_level_3_prohib *prb;
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010084 struct msgb *out = mtp_msg_alloc(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080085
86 if (!out)
87 return NULL;
88
89 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080090 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010091 hdr->addr = MTP_ADDR(link->first_sls, link->set->dpc, link->set->opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080092 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
93 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +010094 prb->cmn.h1 = msg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080095 prb->apoc = MTP_MAKE_APOC(apoc);
96 return out;
97}
98
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +010099static struct msgb *mtp_tfp_alloc(struct mtp_link *link, int apoc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100100{
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100101 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100102}
103
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100104static struct msgb *mtp_tfa_alloc(struct mtp_link *link, int apoc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100105{
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100106 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100107}
108
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100109static struct msgb *mtp_tra_alloc(struct mtp_link *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800110{
111 struct mtp_level_3_hdr *hdr;
112 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100113 struct msgb *out = mtp_msg_alloc(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800114
115 if (!out)
116 return NULL;
117
118 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800119 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100120 hdr->addr = MTP_ADDR(0x0, link->set->dpc, opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800121 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
122 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
123 cmn->h1 = MTP_RESTR_MSG_ALLWED;
124 return out;
125}
126
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100127static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *set,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100128 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800129{
130 struct sccp_data_unitdata *udt;
131 struct sccp_con_ctrl_prt_mgt *prt;
132 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800133 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800134
135
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100136 struct msgb *out = mtp_msg_alloc(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800137
138 if (!out)
139 return NULL;
140
141 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800142 hdr->ser_ind = MTP_SI_MNT_SCCP;
143
144 /* this appears to be round robin or such.. */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100145 hdr->addr = MTP_ADDR(sls % 16, set->dpc, set->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800146
147 /* generate the UDT message... libsccp does not offer formating yet */
148 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
149 udt->type = SCCP_MSG_TYPE_UDT;
150 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
151 udt->variable_called = 3;
152 udt->variable_calling = 5;
153 udt->variable_data = 7;
154
155 /* put the called and calling address. It is LV */
156 data = msgb_put(out, 2 + 1);
157 data[0] = 2;
158 data[1] = 0x42;
159 data[2] = 0x1;
160
161 data = msgb_put(out, 2 + 1);
162 data[0] = 2;
163 data[1] = 0x42;
164 data[2] = 0x1;
165
166 data = msgb_put(out, 1);
167 data[0] = sizeof(*prt);
168
169 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100170 prt->sst = type;
171 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100172 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800173 prt->mul_ind = 0;
174
175 return out;
176}
177
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100178void mtp_link_set_stop(struct mtp_link_set *set)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800179{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100180 struct mtp_link *lnk;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100181 llist_for_each_entry(lnk, &set->links, entry)
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100182 mtp_link_stop_link_test(lnk);
183
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100184 bsc_del_timer(&set->T18);
185 bsc_del_timer(&set->T20);
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100186
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100187 set->sccp_up = 0;
188 set->running = 0;
189 set->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800190}
191
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100192void mtp_link_set_reset(struct mtp_link_set *set)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800193{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100194 struct mtp_link *lnk;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100195 mtp_link_set_stop(set);
196 set->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100197
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100198 llist_for_each_entry(lnk, &set->links, entry)
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100199 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800200}
201
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100202/* unused right now but we want to use it again */
203int send_tfp(struct mtp_link *link, int apoc)
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100204{
205 struct msgb *msg;
206 msg = mtp_tfp_alloc(link, apoc);
207 if (!msg)
208 return -1;
209
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100210 mtp_link_submit(link, msg);
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100211 return 0;
212}
213
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100214static int send_tra(struct mtp_link *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800215{
216 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100217 msg = mtp_tra_alloc(link, opc);
218 if (!msg)
219 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100220 mtp_link_submit(link, msg);
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100221 return 0;
222}
223
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100224static int send_tfa(struct mtp_link *link, int opc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100225{
226 struct msgb *msg;
227 msg = mtp_tfa_alloc(link, opc);
228 if (!msg)
229 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100230 mtp_link_submit(link, msg);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100231 return 0;
232}
233
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100234static int linkset_up(struct mtp_link *link)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100235{
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100236 struct mtp_link_set *set = link->set;
237
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100238 /* the link set is already up */
239 if (set->linkset_up)
240 return 0;
241
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100242 set->linkset_up = 1;
243 bsc_schedule_timer(&set->T18, set->timeout_t18, 0);
244 bsc_schedule_timer(&set->T20, set->timeout_t20, 0);
245
246 /* More the functionality of a SSP here... */
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100247 if (set->sccp_opc != set->opc &&
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100248 send_tfa(link, set->sccp_opc) != 0) {
249 LOGP(DINP, LOGL_ERROR,
250 "Failed to send TFA for OPC %d on linkset %d.\n", set->sccp_opc, set->nr);
251 }
252
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100253 if (set->isup_opc != set->opc &&
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100254 send_tfa(link, set->isup_opc) != 0) {
255 LOGP(DINP, LOGL_ERROR,
256 "Failed to send TFA for OPC %d on linkset %d.\n", set->sccp_opc, set->nr);
257 }
258
259 return 0;
260}
261
262static void linkset_t18_cb(void *_set)
263{
264 struct mtp_link_set *set = _set;
265 struct mtp_link *link = set->slc[0];
266
267 if (!link) {
268 LOGP(DINP, LOGL_ERROR,
269 "Linkset restart but no link available on linkset %d\n", set->nr);
270 bsc_del_timer(&set->T20);
271 set->linkset_up = 0;
272 return;
273 }
274
275 /* TODO: now send out routing states */
276 LOGP(DINP, LOGL_NOTICE, "The linkset %d has collected routing data.\n", set->nr);
Holger Hans Peter Freyther3574c122011-03-02 23:44:03 +0100277 set->sccp_up = 1;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100278}
279
280static void linkset_t20_cb(void *_set)
281{
282 struct mtp_link_set *set = _set;
283 struct mtp_link *link = set->slc[0];
284
285 if (!link) {
286 LOGP(DINP, LOGL_ERROR,
287 "Linkset restart but no link available on linkset %d\n", set->nr);
288 bsc_del_timer(&set->T20);
289 set->linkset_up = 0;
290 return;
291 }
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100292
293 /* Send the TRA for all PCs */
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100294 if (send_tra(link, set->opc) != 0)
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100295 return;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100296
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100297 LOGP(DINP, LOGL_NOTICE,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100298 "The linkset %d/%s is considered running.\n", set->nr, set->name);
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100299 return;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100300}
301
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100302static 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 +0100303{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800304 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100305 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800306
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100307 if (hdr->ni != set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800308 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
309 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800310 return -1;
311 }
312
313 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
314 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
315 cmn->h0, cmn->h1);
316
317 switch (cmn->h0) {
318 case MTP_TRF_RESTR_MSG_GRP:
319 switch (cmn->h1) {
320 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100321 LOGP(DINP, LOGL_INFO,
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100322 "Received TRA on linkset %d/%s.\n", set->nr, set->name);
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100323 /*
324 * TODO: routing should be done on a higher level. This should not
325 * arrive after we expired the timer but we are friendly here and
326 * respond with a TFA and TRA...
327 */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100328 bsc_del_timer(&set->T18);
329 bsc_del_timer(&set->T20);
330 linkset_t18_cb(set);
331 linkset_t20_cb(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800332 return 0;
333 break;
334 }
335 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100336 case MTP_PROHIBIT_MSG_GRP:
337 switch (cmn->h1) {
338 case MTP_PROHIBIT_MSG_SIG:
339 if (l3_len < 3) {
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100340 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 +0100341 return -1;
342 }
343
344 apc = (uint16_t *) &hdr->data[1];
345 LOGP(DINP, LOGL_INFO,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100346 "TFP for the affected point code %d on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100347 *apc, set->nr, set->name);
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100348 return 0;
349 break;
350 }
351 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800352 }
353
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100354 LOGP(DINP, LOGL_ERROR, "Unknown message:%d/%d %s on %d/%s.\n",
355 cmn->h0, cmn->h1, hexdump(&hdr->data[0], l3_len),
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100356 set->nr, set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800357 return -1;
358}
359
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100360static 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 +0800361{
362 struct msgb *out;
363 struct mtp_level_3_mng *mng;
364
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100365 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800366 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
367 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800368 return -1;
369 }
370
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100371 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100372 LOGP(DINP, LOGL_ERROR, "MSG for OPC %d not handled on %d/%s\n",
373 MTP_ADDR_DPC(hdr->addr), link->set->nr, link->set->name);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100374 return -1;
375 }
376
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800377 mng = (struct mtp_level_3_mng *) &hdr->data[0];
378 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
379 mng->cmn.h0, mng->cmn.h1);
380
381 switch (mng->cmn.h0) {
382 case MTP_TST_MSG_GRP:
383 switch (mng->cmn.h1) {
384 case MTP_TST_MSG_SLTM:
385 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100386 out = mtp_create_slta(link->set,
387 MTP_LINK_SLS(hdr->addr),
388 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800389 if (!out)
390 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100391 mtp_link_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800392 return 0;
393 break;
394 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100395 /* If this link is proven set it up */
396 if (mtp_link_slta(link, l3_len, mng) == 0)
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100397 linkset_up(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800398 break;
399 }
400 break;
401 }
402
403 return -1;
404}
405
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100406static 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 +0800407{
408 struct msgb *out;
409 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100410 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100411 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800412
413 msg->l2h = &hdr->data[0];
414 if (msgb_l2len(msg) != l3_len) {
415 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
416 return -1;
417 }
418
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100419 if (!set->sccp_up) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100420 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100421 set->nr, set->name);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100422 return -1;
423 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100425 memset(&sccp, 0, sizeof(sccp));
426 if (sccp_parse_header(msg, &sccp) != 0) {
427 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
428 return -1;
429 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800430
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100431 /* check if it is a SST */
432 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
433 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800434 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100435 LOGP(DINP, LOGL_ERROR,
436 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800437 msgb_l3len(msg));
438 return -1;
439 }
440
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800441 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100442 if (prt->apoc != MTP_MAKE_APOC(set->sccp_opc)) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100443 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100444 ntohs(prt->apoc), prt->apoc, set->nr, set->name);
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100445 type = SCCP_SSP;
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100446 } else if (!set->supported_ssn[prt->assn]) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100447 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u on %d/%s\n",
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100448 prt->assn, set->nr, set->name);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100449 type = SCCP_SSP;
450 } else {
451 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800452 }
453
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100454 out = mtp_sccp_alloc_scmg(set, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100455 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800456 if (!out)
457 return -1;
458
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100459 mtp_link_submit(set->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100460 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800461 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100462
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100463 rate_ctr_inc(&set->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
464 mtp_link_set_forward_sccp(set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800465 return 0;
466}
467
Holger Hans Peter Freyther56cba9a2011-03-03 01:16:53 +0100468int mtp_link_handle_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800469{
470 int rc = -1;
471 struct mtp_level_3_hdr *hdr;
472 int l3_len;
473
474 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
475 return -1;
476
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100477 if (!link->set->running) {
Holger Hans Peter Freyther5a34c7f2011-02-17 03:23:42 +0100478 LOGP(DINP, LOGL_ERROR,
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100479 "Link %d/%s of %d/%s is not running. Call mtp_link_reset first.\n",
Holger Hans Peter Freyther5a34c7f2011-02-17 03:23:42 +0100480 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800481 return -1;
482 }
483
484 hdr = (struct mtp_level_3_hdr *) msg->l2h;
485 l3_len = msgb_l2len(msg) - sizeof(*hdr);
486
Holger Hans Peter Freyther326a1f72011-01-24 20:52:30 +0100487 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_IN]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100488 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
489
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800490 switch (hdr->ser_ind) {
491 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100492 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800493 break;
494 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100495 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800496 break;
497 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100498 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800499 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100500 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100501 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100502 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100503 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100504 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800505 default:
506 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
507 break;
508 }
509
510 return rc;
511}
512
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100513int 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 +0800514{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800515
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100516 if (!set->sccp_up) {
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100517 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 +0100518 set->nr, set->name);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800519 return -1;
520 }
521
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100522 if (sls == -1) {
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100523 sls = set->last_sls;
524 set->last_sls = (set->last_sls + 1) % 16;
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100525 }
526
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100527 rate_ctr_inc(&set->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
528 return mtp_int_submit(set, set->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100529}
530
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100531int mtp_link_set_submit_isup_data(struct mtp_link_set *set, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100532 const uint8_t *data, unsigned int length)
533{
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100534 rate_ctr_inc(&set->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
535 return mtp_int_submit(set, set->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100536}
537
Holger Hans Peter Freyther0452f222011-02-03 13:35:42 +0100538int mtp_link_set_send(struct mtp_link_set *set, struct msgb *msg)
539{
540 int sls;
541 struct mtp_level_3_hdr *hdr;
542
543 if (msgb_l2len(msg) < sizeof(*hdr))
544 return -1;
545
546 hdr = (struct mtp_level_3_hdr *) msg->l2h;
547 sls = MTP_LINK_SLS(hdr->addr);
548 if (!set->slc[sls])
549 return -2;
550
551 mtp_link_submit(set->slc[sls], msg);
552 return 0;
553}
554
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100555static int mtp_int_submit(struct mtp_link_set *set, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100556 const uint8_t *data, unsigned int length)
557{
558 uint8_t *put_ptr;
559 struct mtp_level_3_hdr *hdr;
560 struct msgb *msg;
561
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100562 if (!set->slc[sls % 16])
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100563 return -1;
564
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100565 msg = mtp_msg_alloc(set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800566 if (!msg)
567 return -1;
568
569 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100570 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800571
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100572 hdr->addr = MTP_ADDR(sls % 16, set->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800573
574 /* copy the raw sccp data */
575 put_ptr = msgb_put(msg, length);
576 memcpy(put_ptr, data, length);
577
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100578 mtp_link_submit(set->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800579 return 0;
580}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100581
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100582static struct mtp_link *find_next_link(struct mtp_link_set *set,
583 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100584{
585 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100586 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100587
588 if (llist_empty(&set->links))
589 return NULL;
590
591 if (data == NULL)
592 found = 1;
593
594 /* try to find the next one */
595 llist_for_each_entry(next, &set->links, entry) {
596 if (found && next->available)
597 return next;
598 if (next == data)
599 found = 1;
600 }
601
602 /* try to find any one */
603 llist_for_each_entry(next, &set->links, entry)
604 if (next->available)
605 return next;
606
607 return NULL;
608}
609
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100610void mtp_link_set_init_slc(struct mtp_link_set *set)
611{
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100612 struct mtp_link *link = NULL, *tmp;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100613 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100614
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100615 llist_for_each_entry(tmp, &set->links, entry)
616 tmp->first_sls = 100;
617
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100618
619 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
620 link = find_next_link(set, link);
621 set->slc[i] = link;
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100622
623 if (link && i < link->first_sls)
624 link->first_sls = i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100625 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100626}
627
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100628struct mtp_link_set *mtp_link_set_alloc(struct bsc_data *bsc)
629{
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100630 struct mtp_link_set *set;
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100631
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100632 set = talloc_zero(bsc, struct mtp_link_set);
633 if (!set)
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100634 return NULL;
635
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100636 set->ctrg = rate_ctr_group_alloc(set,
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100637 mtp_link_set_rate_ctr_desc(),
638 bsc->num_linksets + 1);
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100639 if (!set->ctrg) {
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100640 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
641 return NULL;
642 }
643
644
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100645 set->ni = MTP_NI_NATION_NET;
646 INIT_LLIST_HEAD(&set->links);
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100647
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100648 set->nr = bsc->num_linksets++;
649 set->sccp_opc = set->isup_opc = -1;
650 set->pcap_fd = bsc->pcap_fd;
651 set->bsc = bsc;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100652
653 /* timeout code */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100654 set->timeout_t18 = 15;
655 set->timeout_t20 = 16;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100656
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100657 set->T18.cb = linkset_t18_cb;
658 set->T18.data = set;
659 set->T20.cb = linkset_t20_cb;
660 set->T20.data = set;
Holger Hans Peter Freyther47c9faa2011-02-23 11:25:45 +0100661
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100662 llist_add_tail(&set->entry, &bsc->linksets);
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100663
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100664 return set;
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100665}
666
667struct mtp_link_set *mtp_link_set_num(struct bsc_data *bsc, int num)
668{
669 struct mtp_link_set *set;
670
671 llist_for_each_entry(set, &bsc->linksets, entry)
Holger Hans Peter Freythera33b23f2011-02-16 23:37:40 +0100672 if (set->nr == num)
Holger Hans Peter Freyther694337f2011-02-15 11:24:05 +0100673 return set;
674
675 return NULL;
676}